├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── core_implementation.yml │ └── feature_request.yml ├── pull_request_template.md └── workflows │ ├── generic.yml │ └── typos.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── audits ├── 2025-02-v0.1.0-rc.pdf └── 2025-05-v0.2.0.pdf ├── clippy.toml ├── codecov.yml ├── docs ├── README.md ├── antora.yml ├── modules │ └── ROOT │ │ ├── nav.adoc │ │ ├── pages │ │ ├── get-started.adoc │ │ ├── index.adoc │ │ ├── tokens │ │ │ ├── fungible.adoc │ │ │ ├── nft-consecutive.adoc │ │ │ ├── nft-enumerable.adoc │ │ │ └── non-fungible.adoc │ │ └── utils │ │ │ ├── pausable.adoc │ │ │ └── upgradeable.adoc │ │ └── templates │ │ └── token_template.adoc ├── package-lock.json └── package.json ├── examples ├── fungible-allowlist │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── allowlist_approve_override_works.1.json │ │ ├── allowlist_transfer_from_override_works.1.json │ │ ├── cannot_transfer_after_disallow.1.json │ │ ├── cannot_transfer_before_allow.1.json │ │ ├── test_unauthorized_allow.1.json │ │ └── transfer_to_allowed_account_works.1.json ├── fungible-blocklist │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── block_unblock_works.1.json │ │ ├── blocked_spender_cannot_transfer_from.1.json │ │ ├── blocked_user_cannot_approve.1.json │ │ ├── blocklist_approve_override_works.1.json │ │ ├── blocklist_transfer_from_override_works.1.json │ │ ├── test_blocklist_functionality.1.json │ │ ├── test_unauthorized_block.1.json │ │ ├── transfer_from_blocked_user.1.json │ │ ├── transfer_from_to_blocked_user.1.json │ │ └── unauthorized_block_attempt_fails.1.json ├── fungible-capped │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── mint_exact_cap.1.json │ │ ├── mint_exceeds_cap.1.json │ │ ├── mint_multiple_exceeds_cap.1.json │ │ ├── mint_under_cap.1.json │ │ └── query_cap_works.1.json ├── fungible-merkle-airdrop │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── test_bad_claim.1.json │ │ ├── test_claimed_not_reset.1.json │ │ ├── test_double_claim.1.json │ │ └── test_valid_claim.1.json ├── fungible-pausable │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── burn_fails_when_paused.1.json │ │ ├── burn_works.1.json │ │ ├── initial_state.1.json │ │ ├── mint_fails_when_paused.1.json │ │ ├── mint_works.1.json │ │ ├── transfer_fails_when_paused.1.json │ │ ├── transfer_from_fails_when_paused.1.json │ │ ├── transfer_from_works.1.json │ │ └── transfer_works.1.json ├── fungible-token-interface │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── burn_fails_when_paused.1.json │ │ ├── burn_works.1.json │ │ ├── initial_state.1.json │ │ ├── mint_fails_when_paused.1.json │ │ ├── mint_works.1.json │ │ ├── transfer_fails_when_paused.1.json │ │ ├── transfer_from_fails_when_paused.1.json │ │ ├── transfer_from_works.1.json │ │ └── transfer_works.1.json ├── merkle-voting │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ └── test_merkle_voting.1.json ├── nft-access-control │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── admin_can_call_admin_restricted_function.1.json │ │ ├── admin_transfer_cancelled.1.json │ │ ├── admin_transfer_works.1.json │ │ ├── burner_admin_can_revoke_role.1.json │ │ ├── burners_can_burn.1.json │ │ ├── burners_can_burn_from.1.json │ │ ├── cannot_accept_after_admin_transfer_cancelled.1.json │ │ ├── cannot_cancel_with_invalid_pending_address.1.json │ │ ├── expired_admin_transfer_panics.1.json │ │ ├── minter_admin_can_grant_role.1.json │ │ ├── minters_can_mint.1.json │ │ ├── non_admin_cannot_call_admin_restricted_function.1.json │ │ ├── non_admin_cannot_cancel_transfer_admin_role.1.json │ │ ├── non_admin_cannot_grant_role.1.json │ │ ├── non_admin_cannot_initiate_transfer.1.json │ │ ├── non_admin_cannot_revoke_role.1.json │ │ ├── non_admin_cannot_set_role_admin.1.json │ │ ├── non_burners_cannot_burn.1.json │ │ ├── non_burners_cannot_burn_from.1.json │ │ ├── non_minters_cannot_mint.1.json │ │ └── non_recipient_cannot_accept_transfer.1.json ├── nft-consecutive │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── consecutive_batch_mint_works.1.json │ │ ├── consecutive_burn_works.1.json │ │ ├── consecutive_transfer_override_works.1.json │ │ ├── mint_exact_cap.1.json │ │ ├── mint_exceeds_cap.1.json │ │ ├── mint_multiple_exceeds_cap.1.json │ │ ├── mint_under_cap.1.json │ │ └── query_cap_works.1.json ├── nft-enumerable │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── enumerable_burn_works.1.json │ │ ├── enumerable_transfer_override_works.1.json │ │ ├── mint_exact_cap.1.json │ │ ├── mint_exceeds_cap.1.json │ │ ├── mint_multiple_exceeds_cap.1.json │ │ ├── mint_under_cap.1.json │ │ └── query_cap_works.1.json ├── nft-royalties │ ├── Cargo.toml │ └── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs ├── nft-sequential-minting │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── burn_works.1.json │ │ ├── mint_exact_cap.1.json │ │ ├── mint_exceeds_cap.1.json │ │ ├── mint_multiple_exceeds_cap.1.json │ │ ├── mint_under_cap.1.json │ │ ├── query_cap_works.1.json │ │ └── transfer_works.1.json ├── ownable │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── errors_pause_unauthorized.1.json │ │ ├── initial_state.1.json │ │ ├── non_owner_cannot_increment.1.json │ │ └── owner_can_increment.1.json ├── pausable │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── errors_decrement_when_not_paused.1.json │ │ ├── errors_emergency_reset_when_not_paused.1.json │ │ ├── errors_increment_when_paused.1.json │ │ ├── errors_pause_unauthorized.1.json │ │ ├── errors_unpause_unauthorized.1.json │ │ ├── initial_state.1.json │ │ ├── pause_works.1.json │ │ ├── test_1.1.json │ │ ├── test_increment_when_paused.1.json │ │ ├── test_initial_state.1.json │ │ ├── test_pause_errors_unauthorized.1.json │ │ ├── test_pause_works.1.json │ │ ├── test_unpause_errors_unauthorized.1.json │ │ ├── test_unpause_works.1.json │ │ └── unpause_works.1.json ├── sac-admin-generic │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ └── test_sac_generic.1.json ├── sac-admin-wrapper │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ ├── test_sac_transfer.1.json │ │ └── test_transfer_admin.1.json └── upgradeable │ ├── testdata │ ├── upgradeable_v1_example.wasm │ └── upgradeable_v2_example.wasm │ ├── upgrader │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ └── test_upgrade_with_upgrader.1.json │ ├── v1 │ ├── Cargo.toml │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── test.rs │ └── test_snapshots │ │ └── test │ │ └── test_upgrade.1.json │ └── v2 │ ├── Cargo.toml │ └── src │ ├── contract.rs │ └── lib.rs ├── netlify.toml ├── packages ├── access │ ├── access-control-macros │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── access-control │ │ ├── Cargo.toml │ │ ├── src │ │ │ ├── access_control.rs │ │ │ ├── lib.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ └── test_snapshots │ │ │ └── test │ │ │ ├── accept_transfer_with_no_pending_transfer_panics.1.json │ │ │ ├── add_to_role_enumeration_works.1.json │ │ │ ├── admin_functions_work.1.json │ │ │ ├── admin_transfer_cancel_works.1.json │ │ │ ├── admin_transfer_fails_when_no_admin_set.1.json │ │ │ ├── admin_transfer_works.1.json │ │ │ ├── admin_transfer_works_123.1.json │ │ │ ├── admin_transfer_works_with_admin_auth.1.json │ │ │ ├── cancel_transfer_admin_role_from_non_admin_panics.1.json │ │ │ ├── cancel_transfer_when_there_is_no_pending_transfer_panics.1.json │ │ │ ├── get_admin_with_no_admin_set_panics.1.json │ │ │ ├── get_role_admin_returns_none_when_not_set.1.json │ │ │ ├── get_role_admin_returns_some_when_set.1.json │ │ │ ├── get_role_member_count_for_nonexistent_role_returns_zero.1.json │ │ │ ├── get_role_member_with_out_of_bounds_index_panics.1.json │ │ │ ├── remove_from_role_enumeration_for_last_account_works.1.json │ │ │ ├── remove_from_role_enumeration_with_account_not_in_role_panics.1.json │ │ │ ├── remove_from_role_enumeration_with_nonexistent_role_panics.1.json │ │ │ ├── remove_from_role_enumeration_works.1.json │ │ │ ├── renounce_nonexistent_role_panics.1.json │ │ │ ├── renounce_role_works.1.json │ │ │ ├── role_admin_management_works.1.json │ │ │ ├── role_management_works.1.json │ │ │ ├── set_role_admin_auth_works.1.json │ │ │ ├── set_role_admin_from_non_admin_panics.1.json │ │ │ ├── transfer_admin_role_from_non_admin_panics.1.json │ │ │ ├── transfer_with_invalid_live_until_ledger_panics.1.json │ │ │ ├── unauthorized_role_grant_panics.1.json │ │ │ ├── unauthorized_role_revoke_panics.1.json │ │ │ └── wrong_pending_admin_accept_panics.1.json │ ├── ownable-macro │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── ownable │ │ ├── Cargo.toml │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── ownable.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ └── test_snapshots │ │ │ └── test │ │ │ ├── accept_ownership_completes_transfer.1.json │ │ │ ├── enforce_owner_auth_panics_if_renounced.1.json │ │ │ ├── enforce_owner_auth_works.1.json │ │ │ ├── ensure_is_owner_panics_if_not_owner.1.json │ │ │ ├── ensure_is_owner_panics_if_renounced.1.json │ │ │ ├── ensure_is_owner_works.1.json │ │ │ ├── renounce_fails_if_pending_transfer_exists.1.json │ │ │ ├── renounce_ownership_removes_owner.1.json │ │ │ └── transfer_ownership_sets_pending.1.json │ └── role-transfer │ │ ├── Cargo.toml │ │ ├── src │ │ ├── lib.rs │ │ ├── storage.rs │ │ └── test.rs │ │ └── test_snapshots │ │ └── test │ │ ├── accept_transfer_with_no_pending_transfer_panics.1.json │ │ ├── admin_transfer_cancel_works.1.json │ │ ├── admin_transfer_works.1.json │ │ ├── cancel_transfer_when_there_is_no_pending_transfer_panics.1.json │ │ ├── cannot_cancel_with_invalid_pending_address.1.json │ │ ├── error_when_no_admin_set.1.json │ │ ├── role_transfer_cancel_works.1.json │ │ ├── role_transfer_works.1.json │ │ ├── transfer_with_invalid_live_until_ledger_panics.1.json │ │ ├── wrong_pending_admin_accept_panics.1.json │ │ └── wrong_pending_role_accept_panics.1.json ├── constants │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── contract-utils │ ├── crypto │ │ ├── Cargo.toml │ │ ├── proptest-regressions │ │ │ └── merkle.txt │ │ └── src │ │ │ ├── hashable.rs │ │ │ ├── hasher.rs │ │ │ ├── keccak.rs │ │ │ ├── lib.rs │ │ │ ├── merkle.rs │ │ │ └── sha256.rs │ ├── default-impl-macro-test │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ ├── test_snapshots │ │ │ ├── default_impl_enumerable_burn.1.json │ │ │ ├── default_impl_enumerable_get_owner_token_id.1.json │ │ │ ├── default_impl_enumerable_get_token_id.1.json │ │ │ ├── default_impl_enumerable_total_supply.1.json │ │ │ ├── default_impl_enumerable_transfer.1.json │ │ │ ├── default_impl_fungible_allowance.1.json │ │ │ ├── default_impl_fungible_approve.1.json │ │ │ ├── default_impl_fungible_balance.1.json │ │ │ ├── default_impl_fungible_burnable_burn.1.json │ │ │ ├── default_impl_fungible_burnable_burn_from.1.json │ │ │ ├── default_impl_fungible_grant_role.1.json │ │ │ ├── default_impl_fungible_metadata.1.json │ │ │ ├── default_impl_fungible_mint.1.json │ │ │ ├── default_impl_fungible_total_supply.1.json │ │ │ ├── default_impl_fungible_transfer.1.json │ │ │ ├── default_impl_fungible_transfer_from.1.json │ │ │ ├── default_impl_non_fungible_approve.1.json │ │ │ ├── default_impl_non_fungible_approve_for_all.1.json │ │ │ ├── default_impl_non_fungible_balance.1.json │ │ │ ├── default_impl_non_fungible_burnable_burn.1.json │ │ │ ├── default_impl_non_fungible_burnable_burn_from.1.json │ │ │ ├── default_impl_non_fungible_metadata.1.json │ │ │ ├── default_impl_non_fungible_owner_of.1.json │ │ │ ├── default_impl_non_fungible_transfer.1.json │ │ │ ├── default_impl_non_fungible_transfer_from.1.json │ │ │ └── default_impl_ownable.1.json │ │ └── tests │ │ │ ├── access_control.rs │ │ │ ├── fungible.rs │ │ │ ├── fungible_burnable.rs │ │ │ ├── non_fungible.rs │ │ │ ├── non_fungible_burnable.rs │ │ │ ├── non_fungible_enumerable.rs │ │ │ └── ownable.rs │ ├── default-impl-macro │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── helper.rs │ │ │ └── lib.rs │ ├── macro-helpers │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── merkle-distributor │ │ ├── Cargo.toml │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── merkle_distributor.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ └── test_snapshots │ │ │ └── test │ │ │ ├── test_claim_already_claimed_index_fails.1.json │ │ │ ├── test_root_not_set_fails.1.json │ │ │ ├── test_set_root_twice_fails.1.json │ │ │ ├── test_successful_claim_emits_events.1.json │ │ │ ├── test_valid_merkle_proof_succeeds.1.json │ │ │ └── test_verify_with_invalid_proof_fails.1.json │ ├── pausable-macros │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── pausable │ │ ├── Cargo.toml │ │ ├── Makefile │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── pausable.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ └── test_snapshots │ │ │ └── test │ │ │ ├── errors_pause_when_paused.1.json │ │ │ ├── errors_unpause_when_not_paused.1.json │ │ │ ├── initial_state.1.json │ │ │ ├── pause_works.1.json │ │ │ ├── unpause_works.1.json │ │ │ ├── when_not_paused_works.1.json │ │ │ └── when_paused_works.1.json │ ├── upgradeable-macros │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── derive.rs │ │ │ └── lib.rs │ └── upgradeable │ │ ├── Cargo.toml │ │ ├── src │ │ ├── lib.rs │ │ ├── storage.rs │ │ ├── test.rs │ │ └── upgradeable.rs │ │ └── test_snapshots │ │ └── test │ │ ├── upgrade_ensure_can_complete_migration_panics_if_not_migrating.1.json │ │ ├── upgrade_ensure_can_migrate_panics_if_not_migrating.1.json │ │ └── upgrade_flow_works.1.json ├── test-utils │ └── event-assertion │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── tokens │ ├── fungible │ ├── Cargo.toml │ ├── src │ │ ├── extensions │ │ │ ├── allowlist │ │ │ │ ├── mod.rs │ │ │ │ ├── storage.rs │ │ │ │ └── test.rs │ │ │ ├── blocklist │ │ │ │ ├── mod.rs │ │ │ │ ├── storage.rs │ │ │ │ └── test.rs │ │ │ ├── burnable │ │ │ │ ├── mod.rs │ │ │ │ ├── storage.rs │ │ │ │ └── test.rs │ │ │ ├── capped │ │ │ │ ├── mod.rs │ │ │ │ ├── storage.rs │ │ │ │ └── test.rs │ │ │ └── mod.rs │ │ ├── fungible.rs │ │ ├── impl_token_interface_macro.rs │ │ ├── lib.rs │ │ ├── overrides.rs │ │ ├── storage.rs │ │ ├── test.rs │ │ └── utils │ │ │ ├── mod.rs │ │ │ ├── sac_admin_generic │ │ │ ├── README.md │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ │ └── sac_admin_wrapper │ │ │ ├── README.md │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ └── test_snapshots │ │ ├── extensions │ │ ├── allowlist │ │ │ └── test │ │ │ │ ├── allow_user_works.1.json │ │ │ │ ├── approve_with_owner_not_allowed_panics.1.json │ │ │ │ ├── disallow_user_works.1.json │ │ │ │ ├── transfer_with_allowed_users_works.1.json │ │ │ │ ├── transfer_with_receiver_not_allowed_panics.1.json │ │ │ │ └── transfer_with_sender_not_allowed_panics.1.json │ │ ├── blocklist │ │ │ └── test │ │ │ │ ├── approve_with_owner_blocked_panics.1.json │ │ │ │ ├── block_user_works.1.json │ │ │ │ ├── transfer_with_receiver_blocked_panics.1.json │ │ │ │ ├── transfer_with_sender_blocked_panics.1.json │ │ │ │ ├── transfer_with_unblocked_users_works.1.json │ │ │ │ └── unblock_user_works.1.json │ │ ├── burnable │ │ │ ├── test │ │ │ │ ├── burn_with_allowance_works.1.json │ │ │ │ ├── burn_with_insufficient_allowance_panics.1.json │ │ │ │ ├── burn_with_insufficient_balance_panics.1.json │ │ │ │ ├── burn_with_no_allowance_panics.1.json │ │ │ │ └── burn_works.1.json │ │ │ └── tests │ │ │ │ ├── burn_with_allowance_works.1.json │ │ │ │ ├── burn_with_insufficient_allowance_panics.1.json │ │ │ │ ├── burn_with_insufficient_balance_panics.1.json │ │ │ │ ├── burn_with_no_allowance_panics.1.json │ │ │ │ └── burn_works.1.json │ │ ├── capped │ │ │ └── test │ │ │ │ ├── test_cap_not_set.1.json │ │ │ │ ├── test_check_cap_overflows.1.json │ │ │ │ ├── test_invalid_cap.1.json │ │ │ │ ├── test_mint_exact_cap.1.json │ │ │ │ ├── test_mint_exceeds_cap.1.json │ │ │ │ ├── test_mint_multiple_exceeds_cap.1.json │ │ │ │ ├── test_mint_under_cap.1.json │ │ │ │ └── test_query_cap.1.json │ │ ├── metadata │ │ │ └── test │ │ │ │ ├── get_unset_metadata.1.json │ │ │ │ ├── metadata_update.1.json │ │ │ │ └── set_and_get_metadata.1.json │ │ └── mintable │ │ │ └── test │ │ │ ├── mint_base_implementation_has_no_auth.1.json │ │ │ ├── mint_requires_auth.1.json │ │ │ └── mint_works.1.json │ │ ├── test │ │ ├── approve_and_transfer_from.1.json │ │ ├── approve_handles_expiry.1.json │ │ ├── approve_requires_auth.1.json │ │ ├── approve_with_event.1.json │ │ ├── bump_instance_works.1.json │ │ ├── burn_from_requires_auth.1.json │ │ ├── burn_requires_auth.1.json │ │ ├── burn_works.1.json │ │ ├── extend_balance_ttl_thru_transfer.1.json │ │ ├── get_unset_metadata.1.json │ │ ├── initial_state.1.json │ │ ├── metadata_update.1.json │ │ ├── mint_base_implementation_has_no_auth.1.json │ │ ├── mint_works.1.json │ │ ├── set_allowance_with_expired_ledger_fails.1.json │ │ ├── set_allowance_with_greater_than_max_ledger_fails.1.json │ │ ├── set_allowance_with_neg_amount_fails.1.json │ │ ├── set_allowance_with_zero_amount.1.json │ │ ├── set_allowance_with_zero_value.1.json │ │ ├── set_and_get_metadata.1.json │ │ ├── spend_allowance_insufficient_allowance_fails.1.json │ │ ├── spend_allowance_invalid_amount_fails.1.json │ │ ├── spend_allowance_reduces_amount.1.json │ │ ├── spend_allowance_reduces_value.1.json │ │ ├── transfer_from_insufficient_allowance_fails.1.json │ │ ├── transfer_from_requires_auth.1.json │ │ ├── transfer_insufficient_balance_fails.1.json │ │ ├── transfer_requires_auth.1.json │ │ ├── transfer_works.1.json │ │ ├── transfer_zero_works.1.json │ │ ├── update_burns_tokens.1.json │ │ ├── update_mints_tokens.1.json │ │ ├── update_overflow_panics.1.json │ │ ├── update_transfers_between_accounts.1.json │ │ ├── update_with_insufficient_balance_panics.1.json │ │ ├── update_with_invalid_amount_panics.1.json │ │ └── update_with_invalid_value_panics.1.json │ │ └── utils │ │ ├── sac_admin_generic │ │ └── test │ │ │ ├── test_extract_context_address_mismatch.1.json │ │ │ ├── test_extract_context_clawback.1.json │ │ │ ├── test_extract_context_invalid_param_type.1.json │ │ │ ├── test_extract_context_mint.1.json │ │ │ ├── test_extract_context_missing_param.1.json │ │ │ ├── test_extract_context_set_admin.1.json │ │ │ ├── test_extract_context_set_authorized.1.json │ │ │ ├── test_extract_context_unknown_fn.1.json │ │ │ ├── test_sac_get_address_fails.1.json │ │ │ └── test_set_and_get_sac_address.1.json │ │ └── sac_admin_wrapper │ │ └── test │ │ ├── test_sac_clawback.1.json │ │ ├── test_sac_get_address_fails.1.json │ │ ├── test_sac_mint.1.json │ │ ├── test_sac_set_address.1.json │ │ ├── test_sac_set_admin.1.json │ │ └── test_sac_set_authorized.1.json │ └── non-fungible │ ├── Cargo.toml │ ├── src │ ├── extensions │ │ ├── burnable │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ ├── consecutive │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ ├── enumerable │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ │ ├── mod.rs │ │ └── royalties │ │ │ ├── mod.rs │ │ │ ├── storage.rs │ │ │ └── test.rs │ ├── lib.rs │ ├── non_fungible.rs │ ├── overrides.rs │ ├── storage.rs │ ├── test.rs │ └── utils │ │ ├── mod.rs │ │ └── sequential │ │ ├── mod.rs │ │ ├── storage.rs │ │ └── test.rs │ └── test_snapshots │ ├── extensions │ ├── burnable │ │ └── test │ │ │ ├── burn_from_with_approve_works.1.json │ │ │ ├── burn_from_with_insufficient_approval_panics.1.json │ │ │ ├── burn_from_with_operator_works.1.json │ │ │ ├── burn_from_with_owner_works.1.json │ │ │ ├── burn_with_non_existent_token_panics.1.json │ │ │ ├── burn_with_not_owner_panics.1.json │ │ │ └── burn_works.1.json │ ├── consecutive │ │ └── test │ │ │ ├── consecutive_batch_mint_amount_0_fails.1.json │ │ │ ├── consecutive_batch_mint_amount_max_fails.1.json │ │ │ ├── consecutive_batch_mint_works.1.json │ │ │ ├── consecutive_burn_from_works.1.json │ │ │ ├── consecutive_burn_works.1.json │ │ │ ├── consecutive_owner_of_on_nonexistent_token_fails.1.json │ │ │ ├── consecutive_owner_of_on_zero_token_fails.1.json │ │ │ ├── consecutive_owner_of_panics_on_burnt_token_fails.1.json │ │ │ ├── consecutive_owner_of_works.1.json │ │ │ ├── consecutive_set_owner_for_previous_token_works.1.json │ │ │ ├── consecutive_set_owner_for_works.1.json │ │ │ ├── consecutive_set_ownership_panics_for_max_sequential_fails.1.json │ │ │ ├── consecutive_set_ownership_works.1.json │ │ │ ├── consecutive_token_uri_panics_for_burned_id_fails.1.json │ │ │ ├── consecutive_token_uri_panics_for_more_than_max_id_fails.1.json │ │ │ ├── consecutive_token_uri_works.1.json │ │ │ ├── consecutive_transfer_edge_works.1.json │ │ │ ├── consecutive_transfer_from_works.1.json │ │ │ └── consecutive_transfer_works.1.json │ ├── enumerable │ │ └── test │ │ │ ├── test_add_to_global_enumeration.1.json │ │ │ ├── test_add_to_owner_enumeration.1.json │ │ │ ├── test_burn.1.json │ │ │ ├── test_burn_from.1.json │ │ │ ├── test_decrement_total_supply.1.json │ │ │ ├── test_enumerable_transfer.1.json │ │ │ ├── test_enumerable_transfer_from.1.json │ │ │ ├── test_get_owner_token_id.1.json │ │ │ ├── test_get_token_id.1.json │ │ │ ├── test_increment_total_supply.1.json │ │ │ ├── test_non_sequential_burn.1.json │ │ │ ├── test_non_sequential_burn_from.1.json │ │ │ ├── test_non_sequential_mint.1.json │ │ │ ├── test_remove_from_global_enumeration.1.json │ │ │ ├── test_remove_from_owner_enumeration.1.json │ │ │ ├── test_sequential_burn.1.json │ │ │ ├── test_sequential_burn_from.1.json │ │ │ ├── test_sequential_mint.1.json │ │ │ └── test_total_supply.1.json │ ├── mintable │ │ └── test │ │ │ ├── mint_base_implementation_has_no_auth.1.json │ │ │ ├── mint_works.1.json │ │ │ └── test_counter_works.1.json │ └── royalties │ │ └── test │ │ ├── test_invalid_royalty_amount.1.json │ │ ├── test_no_royalty_set.1.json │ │ ├── test_royalty_info_non_existent_token.1.json │ │ ├── test_set_default_royalty.1.json │ │ ├── test_set_default_royalty_too_high.1.json │ │ ├── test_set_token_royalty.1.json │ │ ├── test_set_token_royalty_already_set.1.json │ │ ├── test_set_token_royalty_too_high.1.json │ │ ├── test_token_royalty_overrides_default.1.json │ │ └── test_zero_royalty.1.json │ ├── test │ ├── approve_can_be_revoked_works.1.json │ ├── approve_for_all_works.1.json │ ├── approve_nft_works.1.json │ ├── approve_with_invalid_approver_fails.1.json │ ├── approve_with_invalid_live_until_ledger_fails.1.json │ ├── approve_with_operator_works.1.json │ ├── balance_of_non_existent_account_is_zero.1.json │ ├── get_metadata_should_panic_when_metadata_is_not_set.1.json │ ├── metadata_works.1.json │ ├── mint_base_implementation_has_no_auth.1.json │ ├── mint_works.1.json │ ├── owner_of_non_existent_token_fails.1.json │ ├── revoke_approval_for_all_works.1.json │ ├── revoke_approve_for_all_works.1.json │ ├── set_approval_for_all_with_invalid_operator_fails.1.json │ ├── set_approval_for_all_works.1.json │ ├── set_metadata_should_panic_when_base_uri_exceeds_max_length.1.json │ ├── test_counter_works.1.json │ ├── transfer_from_incorrect_owner_fails.1.json │ ├── transfer_from_invalid_receiver_fails.1.json │ ├── transfer_from_nft_approved_works.1.json │ ├── transfer_from_nft_insufficient_approval_fails.1.json │ ├── transfer_from_nft_operator_works.1.json │ ├── transfer_from_nft_owner_works.1.json │ ├── transfer_from_nft_unauthorized_fails.1.json │ ├── transfer_from_nft_works.1.json │ ├── transfer_from_unauthorized_spender_fails.1.json │ ├── transfer_nft_invalid_owner_fails.1.json │ ├── transfer_nft_unauthorized_fails.1.json │ ├── transfer_nft_works.1.json │ ├── transfer_to_invalid_receiver_fails.1.json │ └── update_with_math_overflow_fails.1.json │ └── utils │ └── sequential │ └── test │ ├── sequential_increment_token_id_fails_on_overflow.1.json │ └── sequential_token_id_counter_increments.1.json ├── rust-toolchain.toml └── rustfmt.toml /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug report 2 | description: Create a report to help us improve 3 | title: "🐞 [Bug]: " 4 | labels: ["bug", "needs triage"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out this bug report! Briefly describe the issue you're experiencing. Tell us what you were trying to do and what happened instead. Remember, this is not a place to ask for help debugging code. For that, we welcome you in the OpenZeppelin Community Forum: https://forum.openzeppelin.com/. 10 | - type: textarea 11 | id: what-happened 12 | attributes: 13 | label: What happened? 14 | description: if you want, you can include screenshots as well 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: expected 19 | attributes: 20 | label: Expected behavior 21 | description: What should have happened instead? 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/core_implementation.yml: -------------------------------------------------------------------------------- 1 | name: 🏗️ Core Implementation 2 | description: Create a report to help us improve 3 | title: "🏗️ [Core Feature]: " 4 | labels: ["core", "needs triage"] 5 | body: 6 | - type: textarea 7 | id: feature 8 | attributes: 9 | label: What is the key feature we're aiming to implement? 10 | validations: 11 | required: true 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🎁 Feature Request 2 | description: Suggest an idea for this project ⚡️ 3 | title: "🎁 [Feature Request]: " 4 | labels: ["enhancement", "needs triage"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill this feature request! 10 | - type: textarea 11 | id: feature 12 | attributes: 13 | label: What is the feature you would like to see? 14 | description: Is your feature request related to a specific problem? Is it just a crazy idea? Tell us about it! 15 | validations: 16 | required: true 17 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fixes #??? 7 | 8 | 9 | 10 | 11 | #### PR Checklist 12 | 13 | 14 | 15 | 16 | 17 | - [ ] Tests 18 | - [ ] Documentation 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/typos.yml: -------------------------------------------------------------------------------- 1 | name: Check for typos 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | check-for-typos: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout the repository 10 | uses: actions/checkout@v4 11 | 12 | - name: Check for typos 13 | uses: crate-ci/typos@v1.24.5 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | /.idea 3 | .DS_Store 4 | .thumbs.db 5 | .vscode 6 | 7 | # These are backup files generated by rustfmt 8 | **/*.rs.bk 9 | 10 | # Environments 11 | .env 12 | .venv 13 | env/ 14 | venv/ 15 | ENV/ 16 | env.bak/ 17 | venv.bak/ 18 | 19 | # Documentation 20 | docs/node_modules 21 | docs/build 22 | 23 | # Code Coverage 24 | htmlcov/ 25 | lcov.info 26 | coverage/ 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 OpenZeppelin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /audits/2025-02-v0.1.0-rc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/stellar-contracts/cf05a5d522f323274939a8bfbcea706fe21eeb52/audits/2025-02-v0.1.0-rc.pdf -------------------------------------------------------------------------------- /audits/2025-05-v0.2.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/stellar-contracts/cf05a5d522f323274939a8bfbcea706fe21eeb52/audits/2025-05-v0.2.0.pdf -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | allow-unwrap-in-tests = true 2 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "packages/contract-utils/access-control-macros" 3 | - "packages/contract-utils/ownable-macro" 4 | - "packages/contract-utils/macro-helpers" 5 | - "packages/tokens/fungible/src/impl_token_interface_macro.rs" 6 | - "packages/tokens/fungible/src/overrides.rs" 7 | - "packages/tokens/non-fungible/src/overrides.rs" 8 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs Editing Readme 2 | 3 | #### Build and run the documentation 4 | 5 | * Run `npm install` to install the dependencies 6 | * Run `npm run docs` to build the directory 7 | * Run `npm run docs:watch` to run the inner docs website 8 | * Open `https://127.0.0.1:8080/` to see the compiled docs 9 | 10 | #### Add a new page 11 | 12 | * Create a new file at desired destination 13 | * Add your info to the page 14 | * Add a link to the `docs/modules/ROOT/nav.adoc` 15 | -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: stellar-contracts 2 | title: Stellar Contracts 3 | version: 0.2.0 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | asciidoc: 7 | attributes: 8 | page-sidebar-collapse-default: false 9 | -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * Tokens 2 | ** xref:tokens/fungible.adoc[Fungible Tokens] 3 | ** xref:tokens/non-fungible.adoc[Non-Fungible Tokens] 4 | *** xref:tokens/non-fungible.adoc#base_and_extensions[Extensions] 5 | **** xref:tokens/nft-consecutive.adoc[Consecutive] 6 | **** xref:tokens/nft-enumerable.adoc[Enumerable] 7 | 8 | * Utilities 9 | ** xref:utils/pausable.adoc[Pausable] 10 | ** xref:utils/upgradeable.adoc[Upgradeable] 11 | 12 | * xref:get-started.adoc[Get Started] 13 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/get-started.adoc: -------------------------------------------------------------------------------- 1 | = Get Started 2 | 3 | Not sure where to start? Use the interactive generator below to bootstrap your contract and find about the components offered in OpenZeppelin Smart Contracts Suite for Stellar. You can also access the code generator from https://wizard.openzeppelin.com/stellar[here]. 4 | 5 | ++++ 6 | 7 | 8 | 9 | ++++ 10 | 11 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: highlight.js 2 | :highlightjs-languages: bash 3 | 4 | = Stellar Smart Contracts Suite 5 | 6 | A comprehensive collection of secure, scalable smart contracts and utilities for the Stellar network, 7 | supporting Fungible, Non-Fungible, and Multi-Token standards. 8 | 9 | == Tokens 10 | Explore our implementations for token standards on Stellar Soroban: 11 | 12 | - **xref:tokens/fungible.adoc[Fungible Tokens]**: Digital assets representing a fixed or dynamic supply of identical units. 13 | - **xref:tokens/non-fungible.adoc[Non-Fungible Tokens]**: Unique digital assets with verifiable ownership. 14 | - **Multi-Token**: Hybrid tokens enabling both fungible and non-fungible token functionalities (work in progress). 15 | 16 | == Utilities 17 | Discover our utility contracts for Stellar Soroban, applicable to all token standards mentioned above: 18 | 19 | - **xref:utils/pausable.adoc[Pausable]** 20 | - **xref:utils/upgradeable.adoc[Upgrades and Migrations]** 21 | 22 | == Error Codes 23 | In Stellar Soroban, each error variant is assigned an integer. To prevent duplication of error codes, 24 | we use the following convention: 25 | 26 | * Utilities: `1XX` 27 | ** Pausable: `10X` 28 | ** Upgradeable: `11X` 29 | ** any future utilities will continue from `12X`, `13X`, and so on. 30 | * Fungible: `2XX` 31 | * Non-Fungible: `3XX` 32 | * Multi-Token: `4XX` 33 | 34 | 35 | == Audits 36 | You can find our audit reports https://github.com/OpenZeppelin/stellar-contracts/tree/main/audits[here]. 37 | 38 | == Get Started 39 | Get started xref:get-started.adoc[here]. 40 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/tokens/nft-consecutive.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: highlight.js 2 | :highlightjs-languages: rust 3 | :github-icon: pass:[] 4 | = Non-Fungible Consecutive 5 | 6 | https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/consecutive[Source Code] 7 | 8 | Consecutive extension for xref:tokens/non-fungible.adoc[Non-Fungible Token] is useful 9 | for efficiently minting multiple tokens in a single transaction. This can significantly 10 | reduce costs and improve performance when creating a large number of tokens at once. 11 | 12 | == Usage 13 | 14 | We'll continue with the xref:tokens/non-fungible.adoc#usage[example] from *Non-Fungible Token* 15 | and modify the contract so that now batches of tokens can be minted with each call 16 | to `award_items`. Please note any account can call `award_items` and we might want to 17 | implement access control to restrict who can mint. 18 | 19 | 20 | [source,rust] 21 | ---- 22 | use soroban_sdk::{contract, contractimpl, Address, Env, String}; 23 | use stellar_default_impl_macro::default_impl; 24 | use stellar_non_fungible::{ 25 | consecutive::{Consecutive, NonFungibleConsecutive}, 26 | Base, ContractOverrides, NonFungibleToken, 27 | }; 28 | 29 | #[contract] 30 | pub struct GameItem; 31 | 32 | #[contractimpl] 33 | impl GameItem { 34 | pub fn __constructor(e: &Env) { 35 | Base::set_metadata( 36 | e, 37 | String::from_str(e, "www.mygame.com"), 38 | String::from_str(e, "My Game Items Collection"), 39 | String::from_str(e, "MGMC"), 40 | ); 41 | } 42 | 43 | pub fn award_items(e: &Env, to: Address, amount: u32) -> u32 { 44 | // access control might be needed 45 | Consecutive::batch_mint(e, &to, amount) 46 | } 47 | 48 | pub fn burn(e: &Env, from: Address, token_id: u32) { 49 | Consecutive::burn(e, &from, token_id); 50 | } 51 | } 52 | 53 | #[default_impl] 54 | #[contractimpl] 55 | impl NonFungibleToken for GameItem { 56 | type ContractType = Consecutive; 57 | } 58 | 59 | // no entry-point functions required, marker impl 60 | impl NonFungibleConsecutive for GameItem {} 61 | ---- 62 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/utils/pausable.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: highlight.js 2 | :highlightjs-languages: rust 3 | :github-icon: pass:[] 4 | = Pausable 5 | 6 | https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/pausable[Source Code] 7 | 8 | == Purpose 9 | 10 | Allows contracts to be paused and unpaused by authorized accounts. 11 | 12 | This utility contract can be used with any token standard (fungible, non-fungible, multi-token). 13 | 14 | == Design 15 | 16 | To make it easier to spot when inspecting the code, we turned this simple functionality into a macro that can annotate your smart contract functions. 17 | 18 | 19 | An example: 20 | ```rust 21 | #[when_paused] 22 | pub fn emergency_reset(e: &Env) { 23 | e.storage().instance().set(&DataKey::Counter, &0); 24 | } 25 | ``` 26 | 27 | Which will expand into the below code: 28 | 29 | ```rust 30 | pub fn emergency_reset(e: &Env) { 31 | when_paused(e); 32 | 33 | e.storage().instance().set(&DataKey::Counter, &0); 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/modules/ROOT/templates/token_template.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: highlight.js 2 | :highlightjs-languages: rust 3 | :github-icon: pass:[] 4 | = XXX Token Standard 5 | 6 | == Purpose 7 | 8 | == Extensions 9 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "docs": "oz-docs -c .", 6 | "docs:watch": "npm run docs watch", 7 | "prepare-docs": "" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@openzeppelin/docs-utils": "^0.1.2" 14 | } 15 | } -------------------------------------------------------------------------------- /examples/fungible-allowlist/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-allowlist-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-access-control = { workspace = true } 16 | stellar-access-control-macros = { workspace = true } 17 | stellar-fungible = { workspace = true } 18 | stellar-default-impl-macro = { workspace = true } 19 | 20 | [dev-dependencies] 21 | soroban-sdk = { workspace = true, features = ["testutils"] } 22 | -------------------------------------------------------------------------------- /examples/fungible-allowlist/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Fungible AllowList Example Contract. 2 | 3 | //! This contract showcases how to integrate the AllowList extension with a 4 | //! SEP-41-compliant fungible token. It includes essential features such as 5 | //! controlled token transfers by an admin who can allow or disallow specific 6 | //! accounts. 7 | 8 | use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env, String}; 9 | use stellar_access_control::{self as access_control, AccessControl}; 10 | use stellar_access_control_macros::has_role; 11 | use stellar_default_impl_macro::default_impl; 12 | use stellar_fungible::{ 13 | allowlist::{AllowList, FungibleAllowList}, 14 | Base, FungibleToken, 15 | }; 16 | 17 | #[contract] 18 | pub struct ExampleContract; 19 | 20 | #[contractimpl] 21 | impl ExampleContract { 22 | pub fn __constructor(e: &Env, admin: Address, manager: Address, initial_supply: i128) { 23 | Base::set_metadata( 24 | e, 25 | 18, 26 | String::from_str(e, "AllowList Token"), 27 | String::from_str(e, "ALT"), 28 | ); 29 | 30 | access_control::set_admin(e, &admin); 31 | 32 | // create a role "manager" and grant it to `manager` 33 | 34 | access_control::grant_role_no_auth(e, &admin, &manager, &symbol_short!("manager")); 35 | 36 | // Allow the admin to transfer tokens 37 | AllowList::allow_user(e, &admin); 38 | 39 | // Mint initial supply to the admin 40 | Base::mint(e, &admin, initial_supply); 41 | } 42 | } 43 | 44 | #[default_impl] 45 | #[contractimpl] 46 | impl FungibleToken for ExampleContract { 47 | type ContractType = AllowList; 48 | } 49 | #[contractimpl] 50 | impl FungibleAllowList for ExampleContract { 51 | fn allowed(e: &Env, account: Address) -> bool { 52 | AllowList::allowed(e, &account) 53 | } 54 | 55 | #[has_role(operator, "manager")] 56 | fn allow_user(e: &Env, user: Address, operator: Address) { 57 | AllowList::allow_user(e, &user) 58 | } 59 | 60 | #[has_role(operator, "manager")] 61 | fn disallow_user(e: &Env, user: Address, operator: Address) { 62 | AllowList::disallow_user(e, &user) 63 | } 64 | } 65 | 66 | #[default_impl] 67 | #[contractimpl] 68 | impl AccessControl for ExampleContract {} 69 | -------------------------------------------------------------------------------- /examples/fungible-allowlist/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/fungible-blocklist/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-blocklist-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-access-control = { workspace = true } 16 | stellar-access-control-macros = { workspace = true } 17 | stellar-fungible = { workspace = true } 18 | stellar-default-impl-macro = { workspace = true } 19 | 20 | [dev-dependencies] 21 | soroban-sdk = { workspace = true, features = ["testutils"] } 22 | -------------------------------------------------------------------------------- /examples/fungible-blocklist/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/fungible-capped/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-capped-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-fungible = { workspace = true } 16 | 17 | [dev-dependencies] 18 | soroban-sdk = { workspace = true, features = ["testutils"] } 19 | -------------------------------------------------------------------------------- /examples/fungible-capped/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Capped Example Contract. 2 | //! 3 | //! Demonstrates an example usage of `capped` module by 4 | //! implementing a capped mint mechanism, and setting the maximum supply 5 | //! at the constructor. 6 | //! 7 | //! **IMPORTANT**: this example is for demonstration purposes, and authorization 8 | //! is not taken into consideration 9 | 10 | use soroban_sdk::{contract, contractimpl, Address, Env, String}; 11 | use stellar_fungible::{ 12 | capped::{check_cap, set_cap}, 13 | Base, FungibleToken, 14 | }; 15 | 16 | #[contract] 17 | pub struct ExampleContract; 18 | 19 | #[contractimpl] 20 | impl ExampleContract { 21 | pub fn __constructor(e: &Env, cap: i128) { 22 | set_cap(e, cap); 23 | } 24 | 25 | pub fn mint(e: &Env, account: Address, amount: i128) { 26 | check_cap(e, amount); 27 | Base::mint(e, &account, amount); 28 | } 29 | } 30 | 31 | #[contractimpl] 32 | impl FungibleToken for ExampleContract { 33 | type ContractType = Base; 34 | 35 | fn total_supply(e: &Env) -> i128 { 36 | Self::ContractType::total_supply(e) 37 | } 38 | 39 | fn balance(e: &Env, account: Address) -> i128 { 40 | Self::ContractType::balance(e, &account) 41 | } 42 | 43 | fn allowance(e: &Env, owner: Address, spender: Address) -> i128 { 44 | Self::ContractType::allowance(e, &owner, &spender) 45 | } 46 | 47 | fn transfer(e: &Env, from: Address, to: Address, amount: i128) { 48 | Self::ContractType::transfer(e, &from, &to, amount); 49 | } 50 | 51 | fn transfer_from(e: &Env, spender: Address, from: Address, to: Address, amount: i128) { 52 | Self::ContractType::transfer_from(e, &spender, &from, &to, amount); 53 | } 54 | 55 | fn approve(e: &Env, owner: Address, spender: Address, amount: i128, live_until_ledger: u32) { 56 | Self::ContractType::approve(e, &owner, &spender, amount, live_until_ledger); 57 | } 58 | 59 | fn decimals(e: &Env) -> u32 { 60 | Self::ContractType::decimals(e) 61 | } 62 | 63 | fn name(e: &Env) -> String { 64 | Self::ContractType::name(e) 65 | } 66 | 67 | fn symbol(e: &Env) -> String { 68 | Self::ContractType::symbol(e) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/fungible-capped/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/fungible-capped/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{testutils::Address as _, Address, Env}; 6 | 7 | use crate::contract::{ExampleContract, ExampleContractClient}; 8 | 9 | fn create_client<'a>(e: &Env, cap: &i128) -> ExampleContractClient<'a> { 10 | let address = e.register(ExampleContract, (cap,)); 11 | ExampleContractClient::new(e, &address) 12 | } 13 | 14 | #[test] 15 | fn mint_under_cap() { 16 | let e = Env::default(); 17 | let cap = 1000; 18 | let client = create_client(&e, &cap); 19 | let user = Address::generate(&e); 20 | 21 | client.mint(&user, &500); 22 | 23 | assert_eq!(client.balance(&user), 500); 24 | assert_eq!(client.total_supply(), 500); 25 | } 26 | 27 | #[test] 28 | fn mint_exact_cap() { 29 | let e = Env::default(); 30 | let cap = 1000; 31 | let client = create_client(&e, &cap); 32 | let user = Address::generate(&e); 33 | 34 | client.mint(&user, &1000); 35 | 36 | assert_eq!(client.balance(&user), 1000); 37 | assert_eq!(client.total_supply(), 1000); 38 | } 39 | 40 | #[test] 41 | #[should_panic(expected = "Error(Contract, #106)")] 42 | fn mint_exceeds_cap() { 43 | let e = Env::default(); 44 | let cap = 1000; 45 | let client = create_client(&e, &cap); 46 | let user = Address::generate(&e); 47 | 48 | // Attempt to mint 1001 tokens (would exceed cap) 49 | client.mint(&user, &1001); // This should panic 50 | } 51 | 52 | #[test] 53 | #[should_panic(expected = "Error(Contract, #106)")] 54 | fn mint_multiple_exceeds_cap() { 55 | let e = Env::default(); 56 | let cap = 1000; 57 | let client = create_client(&e, &cap); 58 | let user = Address::generate(&e); 59 | 60 | // Mint 600 tokens first 61 | client.mint(&user, &600); 62 | 63 | assert_eq!(client.balance(&user), 600); 64 | assert_eq!(client.total_supply(), 600); 65 | 66 | // Attempt to mint 500 more tokens (would exceed cap) 67 | client.mint(&user, &500); // This should panic 68 | } 69 | -------------------------------------------------------------------------------- /examples/fungible-capped/test_snapshots/test/query_cap_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /examples/fungible-merkle-airdrop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-merkle-airdrop-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-fungible = { workspace = true } 16 | stellar-ownable = { workspace = true } 17 | stellar-crypto = { workspace = true } 18 | stellar-merkle-distributor = { workspace = true } 19 | 20 | [dev-dependencies] 21 | soroban-sdk = { workspace = true, features = ["testutils"] } 22 | hex-literal = { workspace = true } 23 | stellar-default-impl-macro = { workspace = true } 24 | -------------------------------------------------------------------------------- /examples/fungible-merkle-airdrop/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod contract; 4 | 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/fungible-pausable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-pausable-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-pausable = { workspace = true } 16 | stellar-pausable-macros = { workspace = true } 17 | stellar-fungible = { workspace = true } 18 | 19 | [dev-dependencies] 20 | soroban-sdk = { workspace = true, features = ["testutils"] } 21 | -------------------------------------------------------------------------------- /examples/fungible-pausable/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/fungible-token-interface/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fungible-token-interface-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-pausable = { workspace = true } 16 | stellar-pausable-macros = { workspace = true } 17 | stellar-fungible = { workspace = true } 18 | 19 | [dev-dependencies] 20 | soroban-sdk = { workspace = true, features = ["testutils"] } 21 | -------------------------------------------------------------------------------- /examples/fungible-token-interface/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/merkle-voting/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "merkle-voting-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-crypto = { workspace = true } 16 | stellar-merkle-distributor = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/merkle-voting/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | pub mod contract; 3 | mod test; 4 | -------------------------------------------------------------------------------- /examples/merkle-voting/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use soroban_sdk::{testutils::Address as _, xdr::ToXdr, Address, BytesN, Env, Vec}; 4 | use stellar_crypto::{hashable::commutative_hash_pair, hasher::Hasher, sha256::Sha256}; 5 | 6 | use crate::contract::{MerkleVoting, MerkleVotingClient, VoteData}; 7 | 8 | fn hash_vote(e: &Env, data: &VoteData) -> BytesN<32> { 9 | let mut hasher = Sha256::new(e); 10 | hasher.update(data.clone().to_xdr(e)); 11 | hasher.finalize() 12 | } 13 | 14 | #[test] 15 | fn test_merkle_voting() { 16 | let e = Env::default(); 17 | 18 | let voter1 = Address::generate(&e); 19 | let voter2 = Address::generate(&e); 20 | 21 | let vote1 = VoteData { index: 0, account: voter1.clone(), voting_power: 100 }; 22 | let vote2 = VoteData { index: 1, account: voter2.clone(), voting_power: 50 }; 23 | 24 | let leaf1 = hash_vote(&e, &vote1); 25 | let leaf2 = hash_vote(&e, &vote2); 26 | 27 | let root = commutative_hash_pair(&leaf1, &leaf2, Sha256::new(&e)); 28 | 29 | let contract_id = e.register(MerkleVoting, (root,)); 30 | let client = MerkleVotingClient::new(&e, &contract_id); 31 | 32 | let proof1 = Vec::from_array(&e, [leaf2.clone()]); 33 | client.vote(&vote1, &proof1, &true); 34 | 35 | let proof2 = Vec::from_array(&e, [leaf1.clone()]); 36 | client.vote(&vote2, &proof2, &false); 37 | 38 | // Verify votes were recorded 39 | assert!(client.has_voted(&0)); 40 | assert!(client.has_voted(&1)); 41 | 42 | // Check vote results 43 | let (votes_pro, votes_against) = client.get_vote_results(); 44 | assert_eq!(votes_pro, 100); 45 | assert_eq!(votes_against, 50); 46 | } 47 | -------------------------------------------------------------------------------- /examples/nft-access-control/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nft-access-control-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-access-control = { workspace = true } 16 | stellar-access-control-macros = { workspace = true } 17 | stellar-default-impl-macro = { workspace = true } 18 | stellar-non-fungible = { workspace = true } 19 | 20 | [dev-dependencies] 21 | soroban-sdk = { workspace = true, features = ["testutils"] } 22 | -------------------------------------------------------------------------------- /examples/nft-access-control/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Non-Fungible with Access Control Example Contract. 2 | //! 3 | //! Demonstrates how can Access Control be utilized. 4 | 5 | use soroban_sdk::{contract, contractimpl, vec, Address, Env, String, Vec}; 6 | use stellar_access_control::{set_admin, AccessControl}; 7 | use stellar_access_control_macros::{has_role, only_admin}; 8 | use stellar_default_impl_macro::default_impl; 9 | use stellar_non_fungible::{burnable::NonFungibleBurnable, Base, NonFungibleToken}; 10 | 11 | #[contract] 12 | pub struct ExampleContract; 13 | 14 | #[contractimpl] 15 | impl ExampleContract { 16 | pub fn __constructor(e: &Env, admin: Address) { 17 | set_admin(e, &admin); 18 | Base::set_metadata( 19 | e, 20 | String::from_str(e, "www.mytoken.com"), 21 | String::from_str(e, "My Token"), 22 | String::from_str(e, "TKN"), 23 | ); 24 | } 25 | 26 | #[only_admin] 27 | pub fn admin_restricted_function(e: &Env) -> Vec { 28 | vec![&e, String::from_str(e, "seems sus")] 29 | } 30 | 31 | #[has_role(caller, "minter")] 32 | pub fn mint(e: &Env, caller: Address, to: Address, token_id: u32) { 33 | Base::mint(e, &to, token_id) 34 | } 35 | } 36 | 37 | #[default_impl] 38 | #[contractimpl] 39 | impl NonFungibleToken for ExampleContract { 40 | type ContractType = Base; 41 | } 42 | 43 | // for this contract, the `burn*` functions are only meant to be called by 44 | // specific people with the `burner` role 45 | #[contractimpl] 46 | impl NonFungibleBurnable for ExampleContract { 47 | #[has_role(from, "burner")] 48 | fn burn(e: &Env, from: Address, token_id: u32) { 49 | Base::burn(e, &from, token_id); 50 | } 51 | 52 | #[has_role(spender, "burner")] 53 | fn burn_from(e: &Env, spender: Address, from: Address, token_id: u32) { 54 | Base::burn_from(e, &spender, &from, token_id); 55 | } 56 | } 57 | 58 | #[default_impl] 59 | #[contractimpl] 60 | impl AccessControl for ExampleContract {} 61 | -------------------------------------------------------------------------------- /examples/nft-access-control/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/nft-consecutive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nft-consecutive-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-non-fungible = { workspace = true } 16 | 17 | [dev-dependencies] 18 | soroban-sdk = { workspace = true, features = ["testutils"] } 19 | -------------------------------------------------------------------------------- /examples/nft-consecutive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/nft-consecutive/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{testutils::Address as _, Address, Env}; 6 | 7 | use crate::contract::{ExampleContract, ExampleContractClient}; 8 | 9 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 10 | let address = e.register(ExampleContract, (owner,)); 11 | ExampleContractClient::new(e, &address) 12 | } 13 | 14 | #[test] 15 | fn consecutive_transfer_override_works() { 16 | let e = Env::default(); 17 | 18 | let owner = Address::generate(&e); 19 | 20 | let recipient = Address::generate(&e); 21 | 22 | let client = create_client(&e, &owner); 23 | 24 | e.mock_all_auths(); 25 | client.batch_mint(&owner, &100); 26 | client.transfer(&owner, &recipient, &10); 27 | assert_eq!(client.balance(&owner), 99); 28 | assert_eq!(client.balance(&recipient), 1); 29 | assert_eq!(client.owner_of(&10), recipient); 30 | } 31 | 32 | #[test] 33 | fn consecutive_batch_mint_works() { 34 | let e = Env::default(); 35 | let owner = Address::generate(&e); 36 | let client = create_client(&e, &owner); 37 | e.mock_all_auths(); 38 | client.batch_mint(&owner, &100); 39 | client.burn(&owner, &0); 40 | assert_eq!(client.balance(&owner), 99); 41 | client.batch_mint(&owner, &100); 42 | assert_eq!(client.owner_of(&101), owner); 43 | } 44 | 45 | #[test] 46 | fn consecutive_burn_works() { 47 | let e = Env::default(); 48 | let owner = Address::generate(&e); 49 | let client = create_client(&e, &owner); 50 | e.mock_all_auths(); 51 | client.batch_mint(&owner, &100); 52 | client.burn(&owner, &0); 53 | assert_eq!(client.balance(&owner), 99); 54 | } 55 | -------------------------------------------------------------------------------- /examples/nft-consecutive/test_snapshots/test/query_cap_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /examples/nft-enumerable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nft-enumerable-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-non-fungible = { workspace = true } 16 | stellar-default-impl-macro = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/nft-enumerable/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Non-Fungible Enumerable Example Contract. 2 | //! 3 | //! Demonstrates an example usage of the Enumerable extension, allowing for 4 | //! enumeration of all the token IDs in the contract as well as all the token 5 | //! IDs owned by each account. 6 | 7 | use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String}; 8 | use stellar_default_impl_macro::default_impl; 9 | use stellar_non_fungible::{ 10 | burnable::NonFungibleBurnable, 11 | enumerable::{Enumerable, NonFungibleEnumerable}, 12 | Base, NonFungibleToken, 13 | }; 14 | 15 | #[contracttype] 16 | pub enum DataKey { 17 | Owner, 18 | } 19 | 20 | #[contract] 21 | pub struct ExampleContract; 22 | 23 | #[contractimpl] 24 | impl ExampleContract { 25 | pub fn __constructor(e: &Env, owner: Address) { 26 | e.storage().instance().set(&DataKey::Owner, &owner); 27 | Base::set_metadata( 28 | e, 29 | String::from_str(e, "www.mytoken.com"), 30 | String::from_str(e, "My Token"), 31 | String::from_str(e, "TKN"), 32 | ); 33 | } 34 | 35 | pub fn mint(e: &Env, to: Address) -> u32 { 36 | let owner: Address = 37 | e.storage().instance().get(&DataKey::Owner).expect("owner should be set"); 38 | owner.require_auth(); 39 | Enumerable::sequential_mint(e, &to) 40 | } 41 | } 42 | 43 | #[default_impl] 44 | #[contractimpl] 45 | impl NonFungibleToken for ExampleContract { 46 | type ContractType = Enumerable; 47 | } 48 | 49 | #[default_impl] 50 | #[contractimpl] 51 | impl NonFungibleEnumerable for ExampleContract {} 52 | 53 | #[default_impl] 54 | #[contractimpl] 55 | impl NonFungibleBurnable for ExampleContract {} 56 | -------------------------------------------------------------------------------- /examples/nft-enumerable/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/nft-enumerable/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{testutils::Address as _, Address, Env}; 6 | 7 | use crate::contract::{ExampleContract, ExampleContractClient}; 8 | 9 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 10 | let address = e.register(ExampleContract, (owner,)); 11 | ExampleContractClient::new(e, &address) 12 | } 13 | 14 | #[test] 15 | fn enumerable_transfer_override_works() { 16 | let e = Env::default(); 17 | 18 | let owner = Address::generate(&e); 19 | 20 | let recipient = Address::generate(&e); 21 | 22 | let client = create_client(&e, &owner); 23 | 24 | e.mock_all_auths(); 25 | client.mint(&owner); 26 | client.transfer(&owner, &recipient, &0); 27 | assert_eq!(client.balance(&owner), 0); 28 | assert_eq!(client.balance(&recipient), 1); 29 | assert_eq!(client.get_owner_token_id(&recipient, &0), 0); 30 | } 31 | 32 | #[test] 33 | fn enumerable_burn_works() { 34 | let e = Env::default(); 35 | let owner = Address::generate(&e); 36 | let client = create_client(&e, &owner); 37 | e.mock_all_auths(); 38 | client.mint(&owner); 39 | client.burn(&owner, &0); 40 | assert_eq!(client.balance(&owner), 0); 41 | client.mint(&owner); 42 | assert_eq!(client.balance(&owner), 1); 43 | assert_eq!(client.get_owner_token_id(&owner, &0), 1); 44 | } 45 | -------------------------------------------------------------------------------- /examples/nft-enumerable/test_snapshots/test/query_cap_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /examples/nft-royalties/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nft-royalties-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-non-fungible = { workspace = true } 16 | stellar-default-impl-macro = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/nft-royalties/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod contract; 2 | #[cfg(test)] 3 | mod test; 4 | -------------------------------------------------------------------------------- /examples/nft-sequential-minting/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nft-sequential-minting-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | stellar-default-impl-macro = { workspace = true } 15 | soroban-sdk = { workspace = true } 16 | stellar-non-fungible = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/nft-sequential-minting/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Non-Fungible Vanilla Example Contract. 2 | //! 3 | //! Demonstrates an example usage of the NFT default base implementation. 4 | 5 | use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String}; 6 | use stellar_default_impl_macro::default_impl; 7 | use stellar_non_fungible::{burnable::NonFungibleBurnable, Base, NonFungibleToken}; 8 | 9 | #[contracttype] 10 | pub enum DataKey { 11 | Owner, 12 | } 13 | 14 | #[contract] 15 | pub struct ExampleContract; 16 | 17 | #[contractimpl] 18 | impl ExampleContract { 19 | pub fn __constructor(e: &Env, owner: Address) { 20 | e.storage().instance().set(&DataKey::Owner, &owner); 21 | Base::set_metadata( 22 | e, 23 | String::from_str(e, "www.mytoken.com"), 24 | String::from_str(e, "My Token"), 25 | String::from_str(e, "TKN"), 26 | ); 27 | } 28 | 29 | pub fn mint(e: &Env, to: Address) -> u32 { 30 | let owner: Address = 31 | e.storage().instance().get(&DataKey::Owner).expect("owner should be set"); 32 | owner.require_auth(); 33 | Base::sequential_mint(e, &to) 34 | } 35 | } 36 | 37 | #[default_impl] 38 | #[contractimpl] 39 | impl NonFungibleToken for ExampleContract { 40 | type ContractType = Base; 41 | } 42 | 43 | #[default_impl] 44 | #[contractimpl] 45 | impl NonFungibleBurnable for ExampleContract {} 46 | -------------------------------------------------------------------------------- /examples/nft-sequential-minting/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/nft-sequential-minting/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{testutils::Address as _, Address, Env}; 6 | 7 | use crate::contract::{ExampleContract, ExampleContractClient}; 8 | 9 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 10 | let address = e.register(ExampleContract, (owner,)); 11 | ExampleContractClient::new(e, &address) 12 | } 13 | 14 | #[test] 15 | fn transfer_works() { 16 | let e = Env::default(); 17 | let owner = Address::generate(&e); 18 | let recipient = Address::generate(&e); 19 | let client = create_client(&e, &owner); 20 | 21 | e.mock_all_auths(); 22 | client.mint(&owner); 23 | client.transfer(&owner, &recipient, &0); 24 | assert_eq!(client.balance(&owner), 0); 25 | assert_eq!(client.balance(&recipient), 1); 26 | } 27 | 28 | #[test] 29 | fn burn_works() { 30 | let e = Env::default(); 31 | let owner = Address::generate(&e); 32 | let client = create_client(&e, &owner); 33 | 34 | e.mock_all_auths(); 35 | client.mint(&owner); 36 | client.burn(&owner, &0); 37 | assert_eq!(client.balance(&owner), 0); 38 | } 39 | -------------------------------------------------------------------------------- /examples/nft-sequential-minting/test_snapshots/test/query_cap_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /examples/ownable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ownable-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-ownable = { workspace = true } 16 | stellar-ownable-macro = { workspace = true } 17 | stellar-default-impl-macro = { workspace = true } 18 | 19 | [dev-dependencies] 20 | soroban-sdk = { workspace = true, features = ["testutils"] } 21 | -------------------------------------------------------------------------------- /examples/ownable/src/contract.rs: -------------------------------------------------------------------------------- 1 | //! Ownable Example Contract. 2 | //! 3 | //! Demonstrates an example usage of `ownable` module by 4 | //! implementing `#[only_owner]` macro on a sensitive function. 5 | 6 | use soroban_sdk::{contract, contractimpl, contracttype, Address, Env}; 7 | use stellar_default_impl_macro::default_impl; 8 | use stellar_ownable::{set_owner, Ownable}; 9 | use stellar_ownable_macro::only_owner; 10 | 11 | #[contracttype] 12 | pub enum DataKey { 13 | Owner, 14 | Counter, 15 | } 16 | 17 | #[contract] 18 | pub struct ExampleContract; 19 | 20 | #[contractimpl] 21 | impl ExampleContract { 22 | pub fn __constructor(e: &Env, owner: Address) { 23 | set_owner(e, &owner); 24 | e.storage().instance().set(&DataKey::Counter, &0); 25 | } 26 | 27 | #[only_owner] 28 | pub fn increment(e: &Env) -> i32 { 29 | let mut counter: i32 = 30 | e.storage().instance().get(&DataKey::Counter).expect("counter should be set"); 31 | 32 | counter += 1; 33 | 34 | e.storage().instance().set(&DataKey::Counter, &counter); 35 | 36 | counter 37 | } 38 | } 39 | 40 | #[default_impl] 41 | #[contractimpl] 42 | impl Ownable for ExampleContract {} 43 | -------------------------------------------------------------------------------- /examples/ownable/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/ownable/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{ 6 | testutils::{Address as _, MockAuth, MockAuthInvoke}, 7 | Address, Env, IntoVal, 8 | }; 9 | 10 | use crate::contract::{ExampleContract, ExampleContractClient}; 11 | 12 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 13 | let address = e.register(ExampleContract, (owner,)); 14 | ExampleContractClient::new(e, &address) 15 | } 16 | 17 | #[test] 18 | fn owner_can_increment() { 19 | let e = Env::default(); 20 | let owner = Address::generate(&e); 21 | let client = create_client(&e, &owner); 22 | 23 | e.mock_auths(&[MockAuth { 24 | address: &owner, 25 | invoke: &MockAuthInvoke { 26 | contract: &client.address, 27 | fn_name: "increment", 28 | args: ().into_val(&e), 29 | sub_invokes: &[], 30 | }, 31 | }]); 32 | 33 | assert_eq!(client.increment(), 1); 34 | } 35 | 36 | #[test] 37 | #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")] 38 | fn non_owner_cannot_increment() { 39 | let e = Env::default(); 40 | let owner = Address::generate(&e); 41 | let non_owner = Address::generate(&e); 42 | let client = create_client(&e, &owner); 43 | 44 | e.mock_auths(&[MockAuth { 45 | address: &non_owner, 46 | invoke: &MockAuthInvoke { 47 | contract: &client.address, 48 | fn_name: "increment", 49 | args: ().into_val(&e), 50 | sub_invokes: &[], 51 | }, 52 | }]); 53 | 54 | client.increment(); 55 | } 56 | -------------------------------------------------------------------------------- /examples/pausable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pausable-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-pausable = { workspace = true } 16 | stellar-pausable-macros = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/pausable/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/sac-admin-generic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sac-admin-generic-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-fungible = { workspace = true } 16 | 17 | [dev-dependencies] 18 | soroban-sdk = { workspace = true, features = ["testutils"] } 19 | ed25519-dalek = { version = "1.0.1" } 20 | rand = { version = "0.7.3" } 21 | -------------------------------------------------------------------------------- /examples/sac-admin-generic/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | pub mod contract; 3 | mod test; 4 | -------------------------------------------------------------------------------- /examples/sac-admin-wrapper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sac-admin-wrapper-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-fungible = { workspace = true } 16 | stellar-access-control = { workspace = true } 17 | stellar-access-control-macros = { workspace = true } 18 | stellar-default-impl-macro = { workspace = true } 19 | 20 | [dev-dependencies] 21 | soroban-sdk = { workspace = true, features = ["testutils"] } 22 | -------------------------------------------------------------------------------- /examples/sac-admin-wrapper/src/contract.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env}; 2 | use stellar_access_control::{self as access_control, AccessControl}; 3 | use stellar_access_control_macros::{has_role, only_admin}; 4 | use stellar_default_impl_macro::default_impl; 5 | use stellar_fungible::{self as fungible, sac_admin_wrapper::SACAdminWrapper}; 6 | 7 | #[contract] 8 | pub struct ExampleContract; 9 | 10 | #[contractimpl] 11 | impl ExampleContract { 12 | pub fn __constructor( 13 | e: &Env, 14 | default_admin: Address, 15 | manager1: Address, 16 | manager2: Address, 17 | sac: Address, 18 | ) { 19 | access_control::set_admin(e, &default_admin); 20 | 21 | // create a role "manager" and grant it to `manager1` 22 | access_control::grant_role_no_auth(e, &default_admin, &manager1, &symbol_short!("manager")); 23 | 24 | // grant it to `manager2` 25 | access_control::grant_role_no_auth(e, &default_admin, &manager2, &symbol_short!("manager")); 26 | 27 | fungible::sac_admin_wrapper::set_sac_address(e, &sac); 28 | } 29 | } 30 | 31 | #[contractimpl] 32 | impl SACAdminWrapper for ExampleContract { 33 | #[only_admin] 34 | fn set_admin(e: Env, new_admin: Address, _operator: Address) { 35 | fungible::sac_admin_wrapper::set_admin(&e, &new_admin); 36 | } 37 | 38 | #[has_role(operator, "manager")] 39 | fn set_authorized(e: Env, id: Address, authorize: bool, operator: Address) { 40 | fungible::sac_admin_wrapper::set_authorized(&e, &id, authorize); 41 | } 42 | 43 | #[has_role(operator, "manager")] 44 | fn mint(e: Env, to: Address, amount: i128, operator: Address) { 45 | fungible::sac_admin_wrapper::mint(&e, &to, amount); 46 | } 47 | 48 | #[has_role(operator, "manager")] 49 | fn clawback(e: Env, from: Address, amount: i128, operator: Address) { 50 | fungible::sac_admin_wrapper::clawback(&e, &from, amount); 51 | } 52 | } 53 | 54 | #[default_impl] 55 | #[contractimpl] 56 | impl AccessControl for ExampleContract {} 57 | -------------------------------------------------------------------------------- /examples/sac-admin-wrapper/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/upgradeable/testdata/upgradeable_v1_example.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/stellar-contracts/cf05a5d522f323274939a8bfbcea706fe21eeb52/examples/upgradeable/testdata/upgradeable_v1_example.wasm -------------------------------------------------------------------------------- /examples/upgradeable/testdata/upgradeable_v2_example.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenZeppelin/stellar-contracts/cf05a5d522f323274939a8bfbcea706fe21eeb52/examples/upgradeable/testdata/upgradeable_v2_example.wasm -------------------------------------------------------------------------------- /examples/upgradeable/upgrader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "upgrader-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-upgradeable = { workspace = true } 16 | stellar-ownable = { workspace = true } 17 | stellar-ownable-macro = { workspace = true } 18 | 19 | [dev-dependencies] 20 | soroban-sdk = { workspace = true, features = ["testutils"] } 21 | -------------------------------------------------------------------------------- /examples/upgradeable/upgrader/src/contract.rs: -------------------------------------------------------------------------------- 1 | /// Helper contract to perform upgrade+migrate in a single transaction. 2 | use soroban_sdk::{contract, contractimpl, symbol_short, Address, BytesN, Env, Symbol, Val}; 3 | use stellar_ownable::{self as ownable}; 4 | use stellar_ownable_macro::only_owner; 5 | use stellar_upgradeable::UpgradeableClient; 6 | 7 | pub const MIGRATE: Symbol = symbol_short!("migrate"); 8 | 9 | #[contract] 10 | pub struct Upgrader; 11 | 12 | #[contractimpl] 13 | impl Upgrader { 14 | pub fn __constructor(e: &Env, owner: Address) { 15 | ownable::set_owner(e, &owner); 16 | } 17 | 18 | #[only_owner] 19 | pub fn upgrade(e: &Env, contract_address: Address, operator: Address, wasm_hash: BytesN<32>) { 20 | let contract_client = UpgradeableClient::new(e, &contract_address); 21 | 22 | contract_client.upgrade(&wasm_hash, &operator); 23 | } 24 | 25 | #[only_owner] 26 | pub fn upgrade_and_migrate( 27 | e: &Env, 28 | contract_address: Address, 29 | operator: Address, 30 | wasm_hash: BytesN<32>, 31 | migration_data: soroban_sdk::Vec, 32 | ) { 33 | let contract_client = UpgradeableClient::new(e, &contract_address); 34 | 35 | contract_client.upgrade(&wasm_hash, &operator); 36 | // The types of the arguments to the migrate function are unknown to this 37 | // contract, so we need to call it with invoke_contract. 38 | e.invoke_contract::<()>(&contract_address, &MIGRATE, migration_data); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/upgradeable/upgrader/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | mod contract; 3 | 4 | mod test; 5 | -------------------------------------------------------------------------------- /examples/upgradeable/upgrader/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use contract_v2::Data; 6 | use soroban_sdk::{testutils::Address as _, Address, BytesN, Env, TryIntoVal}; 7 | 8 | use crate::contract::{Upgrader, UpgraderClient}; 9 | 10 | mod contract_v1 { 11 | soroban_sdk::contractimport!(file = "../testdata/upgradeable_v1_example.wasm"); 12 | } 13 | 14 | mod contract_v2 { 15 | use crate::test::MigrationData; 16 | 17 | soroban_sdk::contractimport!(file = "../testdata/upgradeable_v2_example.wasm"); 18 | } 19 | 20 | fn install_new_wasm(e: &Env) -> BytesN<32> { 21 | e.deployer().upload_contract_wasm(contract_v2::WASM) 22 | } 23 | 24 | type MigrationData = Data; 25 | 26 | #[test] 27 | fn test_upgrade_with_upgrader() { 28 | let e = Env::default(); 29 | e.mock_all_auths_allowing_non_root_auth(); 30 | 31 | let admin = Address::generate(&e); 32 | let contract_id = e.register(contract_v1::WASM, (&admin,)); 33 | 34 | let upgrader = e.register(Upgrader, (&admin,)); 35 | let upgrader_client = UpgraderClient::new(&e, &upgrader); 36 | 37 | let new_wasm_hash = install_new_wasm(&e); 38 | let data = Data { num1: 12, num2: 34 }; 39 | 40 | upgrader_client.upgrade_and_migrate( 41 | &contract_id, 42 | &admin, 43 | &new_wasm_hash, 44 | &soroban_sdk::vec![&e, data.try_into_val(&e).unwrap(), admin.try_into_val(&e).unwrap()], 45 | ); 46 | 47 | let client_v2 = contract_v2::Client::new(&e, &contract_id); 48 | 49 | assert!(client_v2.try_migrate(&Data { num1: 12, num2: 34 }, &admin).is_err()); 50 | } 51 | -------------------------------------------------------------------------------- /examples/upgradeable/v1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "upgradeable-v1-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version = "1.0.0" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-upgradeable = { workspace = true } 16 | stellar-upgradeable-macros = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/upgradeable/v1/src/contract.rs: -------------------------------------------------------------------------------- 1 | /// A basic contract that demonstrates the usage of the `Upgradeable` derive 2 | /// macro. It only implements `UpgradeableInternal` and the derive macro do the 3 | /// rest of the job. The goal is to upgrade this "v1" contract with the contract 4 | /// in "v2". 5 | use soroban_sdk::{ 6 | contract, contracterror, contractimpl, panic_with_error, symbol_short, Address, Env, Symbol, 7 | }; 8 | use stellar_upgradeable::UpgradeableInternal; 9 | use stellar_upgradeable_macros::Upgradeable; 10 | 11 | pub const OWNER: Symbol = symbol_short!("OWNER"); 12 | 13 | #[contracterror] 14 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 15 | #[repr(u32)] 16 | pub enum ExampleContractError { 17 | Unauthorized = 1, 18 | } 19 | 20 | #[derive(Upgradeable)] 21 | #[contract] 22 | pub struct ExampleContract; 23 | 24 | #[contractimpl] 25 | impl ExampleContract { 26 | pub fn __constructor(e: &Env, admin: Address) { 27 | e.storage().instance().set(&OWNER, &admin); 28 | } 29 | } 30 | 31 | impl UpgradeableInternal for ExampleContract { 32 | fn _require_auth(e: &Env, operator: &Address) { 33 | operator.require_auth(); 34 | let owner = e.storage().instance().get::<_, Address>(&OWNER).unwrap(); 35 | if *operator != owner { 36 | panic_with_error!(e, ExampleContractError::Unauthorized) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/upgradeable/v1/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | pub mod contract; 5 | mod test; 6 | -------------------------------------------------------------------------------- /examples/upgradeable/v1/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use contract_v2::Data; 6 | use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; 7 | 8 | use crate::contract::{ExampleContract, ExampleContractClient}; 9 | 10 | mod contract_v2 { 11 | use crate::test::MigrationData; 12 | 13 | soroban_sdk::contractimport!(file = "../testdata/upgradeable_v2_example.wasm"); 14 | } 15 | 16 | fn install_new_wasm(e: &Env) -> BytesN<32> { 17 | e.deployer().upload_contract_wasm(contract_v2::WASM) 18 | } 19 | 20 | type MigrationData = Data; 21 | 22 | #[test] 23 | fn test_upgrade() { 24 | let env = Env::default(); 25 | env.mock_all_auths(); 26 | 27 | let admin = Address::generate(&env); 28 | // deploy v1 29 | let address = env.register(ExampleContract, (&admin,)); 30 | 31 | let client_v1 = ExampleContractClient::new(&env, &address); 32 | 33 | // install the new wasm and upgrade 34 | let new_wasm_hash = install_new_wasm(&env); 35 | client_v1.upgrade(&new_wasm_hash, &admin); 36 | 37 | // init the upgraded client and migrate 38 | let client_v2 = contract_v2::Client::new(&env, &address); 39 | client_v2.migrate(&Data { num1: 12, num2: 34 }, &admin); 40 | 41 | // ensure migrate can't be invoked again 42 | assert!(client_v2.try_migrate(&Data { num1: 12, num2: 34 }, &admin).is_err()); 43 | } 44 | -------------------------------------------------------------------------------- /examples/upgradeable/v2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "upgradeable-v2-example" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version = "2.0.0" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-upgradeable = { workspace = true } 16 | stellar-upgradeable-macros = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | -------------------------------------------------------------------------------- /examples/upgradeable/v2/src/contract.rs: -------------------------------------------------------------------------------- 1 | /// The contract in "v1" needs to be upgraded with this one. We are 2 | /// demonstrating the usage of the `UpgradeableMigratable` macro, because this 3 | /// time we want to do a migration after the upgrade. That's why we derive 4 | /// `UpgradeableMigratable`. For it to work, we implement 5 | /// `UpgradeableMigratableInternal` with the custom migration logic. 6 | use soroban_sdk::{ 7 | contract, contracterror, contracttype, panic_with_error, symbol_short, Address, Env, Symbol, 8 | }; 9 | use stellar_upgradeable::UpgradeableMigratableInternal; 10 | use stellar_upgradeable_macros::UpgradeableMigratable; 11 | 12 | pub const DATA_KEY: Symbol = symbol_short!("DATA_KEY"); 13 | pub const OWNER: Symbol = symbol_short!("OWNER"); 14 | 15 | #[contracterror] 16 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 17 | #[repr(u32)] 18 | pub enum ExampleContractError { 19 | Unauthorized = 1, 20 | } 21 | 22 | #[contracttype] 23 | pub struct Data { 24 | pub num1: u32, 25 | pub num2: u32, 26 | } 27 | 28 | #[derive(UpgradeableMigratable)] 29 | #[contract] 30 | pub struct ExampleContract; 31 | 32 | impl UpgradeableMigratableInternal for ExampleContract { 33 | type MigrationData = Data; 34 | 35 | fn _require_auth(e: &Env, operator: &Address) { 36 | operator.require_auth(); 37 | let owner = e.storage().instance().get::<_, Address>(&OWNER).unwrap(); 38 | if *operator != owner { 39 | panic_with_error!(e, ExampleContractError::Unauthorized) 40 | } 41 | } 42 | 43 | fn _migrate(e: &Env, data: &Self::MigrationData) { 44 | e.storage().instance().set(&DATA_KEY, data); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/upgradeable/v2/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | mod contract; 5 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "docs/" 3 | command = "npm run docs" 4 | publish = "build/site" 5 | -------------------------------------------------------------------------------- /packages/access/access-control-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-access-control-macros" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | stellar-macro-helpers = { workspace = true } 18 | -------------------------------------------------------------------------------- /packages/access/access-control/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-access-control" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-constants = { workspace = true } 16 | stellar-role-transfer = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | stellar-event-assertion = { workspace = true } 21 | -------------------------------------------------------------------------------- /packages/access/access-control/test_snapshots/test/admin_transfer_fails_when_no_admin_set.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/access-control/test_snapshots/test/get_admin_with_no_admin_set_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/access-control/test_snapshots/test/remove_from_role_enumeration_with_nonexistent_role_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/ownable-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-ownable-macro" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | stellar-macro-helpers = { workspace = true } 18 | -------------------------------------------------------------------------------- /packages/access/ownable-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::quote; 3 | use stellar_macro_helpers::generate_auth_check; 4 | use syn::{parse_macro_input, ItemFn}; 5 | 6 | /// A procedural macro that ensures the caller is the owner before executing the 7 | /// function. 8 | /// 9 | /// This macro retrieves the owner from storage and requires authorization from 10 | /// the owner before executing the function body. 11 | /// 12 | /// # Usage 13 | /// 14 | /// ```rust 15 | /// #[only_owner] 16 | /// pub fn restricted_function(e: &Env, other_param: u32) { 17 | /// // Function body 18 | /// } 19 | /// ``` 20 | /// 21 | /// This will expand to: 22 | /// 23 | /// ```rust 24 | /// pub fn restricted_function(e: &Env, other_param: u32) { 25 | /// let owner: soroban_sdk::Address = 26 | /// e.storage().instance().get(&stellar_ownable::OwnableStorageKey::Owner).unwrap(); 27 | /// owner.require_auth(); 28 | /// // Function body 29 | /// } 30 | /// ``` 31 | #[proc_macro_attribute] 32 | pub fn only_owner(_attrs: TokenStream, input: TokenStream) -> TokenStream { 33 | let input_fn = parse_macro_input!(input as ItemFn); 34 | 35 | // Generate the function with the owner authorization check 36 | let auth_check_path = quote! { stellar_ownable::enforce_owner_auth }; 37 | let expanded = generate_auth_check(&input_fn, auth_check_path); 38 | 39 | TokenStream::from(expanded) 40 | } 41 | -------------------------------------------------------------------------------- /packages/access/ownable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-ownable" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-constants = { workspace = true } 16 | stellar-role-transfer = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | stellar-event-assertion = { workspace = true } 21 | -------------------------------------------------------------------------------- /packages/access/ownable/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Ownable Contract Module. 2 | //! 3 | //! This module introduces a simple access control mechanism where a contract 4 | //! has an account (owner) that can be granted exclusive access to specific 5 | //! functions. 6 | //! 7 | //! The `Ownable` trait exposes methods for: 8 | //! - Getting the current owner 9 | //! - Transferring ownership 10 | //! - Renouncing ownership 11 | //! 12 | //! The helper `enforce_owner_auth()` is available to restrict access to only 13 | //! the owner. You can also use the `#[only_owner]` macro (provided elsewhere) 14 | //! to simplify this. 15 | //! 16 | //! ```ignore 17 | //! #[only_owner] 18 | //! fn set_config(e: &Env, new_config: u32) { ... } 19 | //! ``` 20 | //! 21 | //! See `examples/ownable/src/contract.rs` for a working example. 22 | 23 | #![no_std] 24 | 25 | mod ownable; 26 | mod storage; 27 | 28 | pub use crate::{ 29 | ownable::{ 30 | emit_ownership_renounced, emit_ownership_transfer, emit_ownership_transfer_completed, 31 | Ownable, OwnableError, 32 | }, 33 | storage::{ 34 | accept_ownership, enforce_owner_auth, get_owner, renounce_ownership, set_owner, 35 | transfer_ownership, OwnableStorageKey, 36 | }, 37 | }; 38 | 39 | mod test; 40 | -------------------------------------------------------------------------------- /packages/access/ownable/test_snapshots/test/ensure_is_owner_panics_if_not_owner.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/ownable/test_snapshots/test/ensure_is_owner_panics_if_renounced.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/role-transfer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-role-transfer" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | 16 | [dev-dependencies] 17 | soroban-sdk = { workspace = true, features = ["testutils"] } 18 | -------------------------------------------------------------------------------- /packages/access/role-transfer/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This module only acts as a utility crate for `Access Control` and `Ownable`. 2 | //! It is not intended to be used directly. 3 | 4 | #![no_std] 5 | 6 | use soroban_sdk::contracterror; 7 | 8 | mod storage; 9 | 10 | pub use storage::{accept_transfer, transfer_role}; 11 | 12 | #[contracterror] 13 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 14 | #[repr(u32)] 15 | enum RoleTransferError { 16 | NoPendingTransfer = 1200, 17 | InvalidLiveUntilLedger = 1201, 18 | InvalidPendingAccount = 1202, 19 | } 20 | 21 | mod test; 22 | -------------------------------------------------------------------------------- /packages/access/role-transfer/test_snapshots/test/accept_transfer_with_no_pending_transfer_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/role-transfer/test_snapshots/test/cancel_transfer_when_there_is_no_pending_transfer_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/access/role-transfer/test_snapshots/test/transfer_with_invalid_live_until_ledger_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 1000, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/constants/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-constants" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | -------------------------------------------------------------------------------- /packages/constants/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk as _; // Import soroban-sdk for its panic handler 4 | 5 | // Same values as in Stellar Asset Contract (SAC) implementation: 6 | // https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/builtin_contracts/stellar_asset_contract/storage_types.rs 7 | pub const DAY_IN_LEDGERS: u32 = 17280; 8 | 9 | pub const INSTANCE_EXTEND_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; 10 | pub const INSTANCE_TTL_THRESHOLD: u32 = INSTANCE_EXTEND_AMOUNT - DAY_IN_LEDGERS; 11 | 12 | pub const ALLOW_BLOCK_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 13 | pub const ALLOW_BLOCK_TTL_THRESHOLD: u32 = ALLOW_BLOCK_EXTEND_AMOUNT - DAY_IN_LEDGERS; 14 | 15 | pub const BALANCE_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 16 | pub const BALANCE_TTL_THRESHOLD: u32 = BALANCE_EXTEND_AMOUNT - DAY_IN_LEDGERS; 17 | 18 | pub const OWNER_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 19 | pub const OWNER_TTL_THRESHOLD: u32 = OWNER_EXTEND_AMOUNT - DAY_IN_LEDGERS; 20 | 21 | pub const OWNERSHIP_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 22 | pub const OWNERSHIP_TTL_THRESHOLD: u32 = OWNERSHIP_EXTEND_AMOUNT - DAY_IN_LEDGERS; 23 | 24 | pub const TOKEN_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 25 | pub const TOKEN_TTL_THRESHOLD: u32 = TOKEN_EXTEND_AMOUNT - DAY_IN_LEDGERS; 26 | 27 | pub const ROLE_EXTEND_AMOUNT: u32 = 90 * DAY_IN_LEDGERS; 28 | pub const ROLE_TTL_THRESHOLD: u32 = ROLE_EXTEND_AMOUNT - DAY_IN_LEDGERS; 29 | 30 | pub const ADMIN_TRANSFER_TTL: u32 = 2 * DAY_IN_LEDGERS; 31 | pub const ADMIN_TRANSFER_THRESHOLD: u32 = DAY_IN_LEDGERS; 32 | 33 | // Merkle Distributor TTL constants 34 | pub const MERKLE_CLAIMED_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; 35 | pub const MERKLE_CLAIMED_TTL_THRESHOLD: u32 = MERKLE_CLAIMED_EXTEND_AMOUNT - DAY_IN_LEDGERS; 36 | -------------------------------------------------------------------------------- /packages/contract-utils/crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-crypto" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | 16 | [dev-dependencies] 17 | soroban-sdk = { workspace = true, features = ["testutils"] } 18 | proptest = { workspace = true } 19 | hex-literal = { workspace = true } 20 | -------------------------------------------------------------------------------- /packages/contract-utils/crypto/proptest-regressions/merkle.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 5abce70720b91d83efed4599d5c38af4837571b4a929beea2dc0d1585d2e0748 # shrinks to (proof, root, leaf) = ([BytesN<32>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)], BytesN<32>(173, 50, 40, 182, 118, 247, 211, 205, 66, 132, 165, 68, 63, 23, 241, 150, 43, 54, 228, 145, 179, 10, 64, 178, 64, 88, 73, 229, 151, 186, 95, 181), BytesN<32>(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), tamper_idx = 0 8 | -------------------------------------------------------------------------------- /packages/contract-utils/crypto/src/hasher.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{Bytes, Env}; 2 | 3 | /// A trait for hashing an arbitrary stream of bytes. 4 | /// 5 | /// Instances of `Hasher` usually represent state that is changed while hashing 6 | /// data. 7 | /// 8 | /// `Hasher` provides a fairly basic interface for retrieving the generated hash 9 | /// (with [`Hasher::finalize`]), and absorbing an arbitrary number of bytes 10 | /// (with [`Hasher::update`]). Most of the time, [`Hasher`] instances are used 11 | /// in conjunction with the [`Hashable`] trait. 12 | pub trait Hasher { 13 | type Output; 14 | 15 | /// Creates a new [`Hasher`] instance. 16 | fn new(e: &Env) -> Self; 17 | 18 | /// Absorbs additional input. Can be called multiple times. 19 | fn update(&mut self, input: Bytes); 20 | 21 | /// Outputs the hashing algorithm state. 22 | fn finalize(self) -> Self::Output; 23 | } 24 | -------------------------------------------------------------------------------- /packages/contract-utils/crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod hashable; 4 | pub mod hasher; 5 | pub mod keccak; 6 | pub mod merkle; 7 | pub mod sha256; 8 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-default-impl-macro-test" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | 14 | [dev-dependencies] 15 | soroban-sdk = { workspace = true, features = ["testutils"] } 16 | stellar-access-control = { workspace = true } 17 | stellar-access-control-macros = { workspace = true } 18 | stellar-event-assertion = { workspace = true } 19 | stellar-default-impl-macro = { workspace = true } 20 | stellar-fungible = { workspace = true } 21 | stellar-non-fungible = { workspace = true } 22 | stellar-ownable = { workspace = true } 23 | stellar-ownable-macro = { workspace = true } 24 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate is a test crate for the default-impl-macro. 2 | //! Proc-macros cannot be tested within their own crate due to Rust's 3 | //! limitations, hence a separate crate for testing is used for testing the 4 | //! proc-macro. 5 | //! 6 | //! This crate is not intended for use in any other context. And this `lib.rs` 7 | //! file is empty on purpose. 8 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/tests/access_control.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{ 2 | contract, contractimpl, contracttype, testutils::Address as _, Address, Env, String, Symbol, 3 | }; 4 | use stellar_access_control::{set_admin, AccessControl}; 5 | use stellar_access_control_macros::has_role; 6 | use stellar_default_impl_macro::default_impl; 7 | use stellar_fungible::{Base, FungibleToken}; 8 | 9 | #[contracttype] 10 | pub enum DataKey { 11 | Admin, 12 | } 13 | 14 | #[contract] 15 | pub struct ExampleContract; 16 | 17 | #[contractimpl] 18 | impl ExampleContract { 19 | pub fn __constructor(e: &Env, owner: Address) { 20 | set_admin(e, &owner); 21 | Base::set_metadata(e, 7, String::from_str(e, "My Token"), String::from_str(e, "TKN")); 22 | } 23 | 24 | #[has_role(caller, "minter")] 25 | pub fn mint(e: &Env, caller: Address, to: Address, amount: i128) { 26 | Base::mint(e, &to, amount); 27 | } 28 | } 29 | 30 | #[default_impl] 31 | #[contractimpl] 32 | impl FungibleToken for ExampleContract { 33 | type ContractType = Base; 34 | } 35 | 36 | #[default_impl] 37 | #[contractimpl] 38 | impl AccessControl for ExampleContract {} 39 | 40 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 41 | let address = e.register(ExampleContract, (owner,)); 42 | ExampleContractClient::new(e, &address) 43 | } 44 | 45 | #[test] 46 | fn default_impl_fungible_grant_role() { 47 | let e = Env::default(); 48 | let owner = Address::generate(&e); 49 | let client = create_client(&e, &owner); 50 | 51 | e.mock_all_auths(); 52 | 53 | client.grant_role(&owner, &owner, &Symbol::new(&e, "minter")); 54 | } 55 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/tests/fungible_burnable.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Env, String}; 2 | use stellar_default_impl_macro::default_impl; 3 | use stellar_fungible::{burnable::FungibleBurnable, Base, FungibleToken}; 4 | 5 | #[contract] 6 | pub struct ExampleContract; 7 | 8 | #[contractimpl] 9 | impl ExampleContract { 10 | pub fn __constructor(e: &Env) { 11 | Base::set_metadata(e, 7, String::from_str(e, "My Token"), String::from_str(e, "TKN")); 12 | } 13 | 14 | pub fn mint(e: &Env, to: Address, amount: i128) { 15 | Base::mint(e, &to, amount); 16 | } 17 | } 18 | 19 | #[default_impl] 20 | #[contractimpl] 21 | impl FungibleToken for ExampleContract { 22 | type ContractType = Base; 23 | } 24 | 25 | #[default_impl] 26 | #[contractimpl] 27 | impl FungibleBurnable for ExampleContract {} 28 | 29 | fn create_client<'a>(e: &Env) -> ExampleContractClient<'a> { 30 | let address = e.register(ExampleContract, ()); 31 | ExampleContractClient::new(e, &address) 32 | } 33 | 34 | #[test] 35 | fn default_impl_fungible_burnable_burn() { 36 | let e = Env::default(); 37 | let owner = Address::generate(&e); 38 | let client = create_client(&e); 39 | 40 | e.mock_all_auths(); 41 | client.mint(&owner, &100); 42 | client.burn(&owner, &50); 43 | assert_eq!(client.balance(&owner), 50); 44 | assert_eq!(client.total_supply(), 50); 45 | } 46 | 47 | #[test] 48 | fn default_impl_fungible_burnable_burn_from() { 49 | let e = Env::default(); 50 | let owner = Address::generate(&e); 51 | let spender = Address::generate(&e); 52 | let client = create_client(&e); 53 | 54 | e.mock_all_auths(); 55 | client.mint(&owner, &100); 56 | client.approve(&owner, &spender, &50, &1000); 57 | client.burn_from(&spender, &owner, &30); 58 | assert_eq!(client.balance(&owner), 70); 59 | assert_eq!(client.total_supply(), 70); 60 | assert_eq!(client.allowance(&owner, &spender), 20); 61 | } 62 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/tests/non_fungible_enumerable.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Env, String}; 2 | use stellar_default_impl_macro::default_impl; 3 | use stellar_non_fungible::{ 4 | enumerable::{Enumerable, NonFungibleEnumerable}, 5 | Base, NonFungibleToken, 6 | }; 7 | 8 | #[contract] 9 | pub struct ExampleContract; 10 | 11 | #[contractimpl] 12 | impl ExampleContract { 13 | pub fn __constructor(e: &Env) { 14 | Base::set_metadata( 15 | e, 16 | String::from_str(e, "www.mytoken.com"), 17 | String::from_str(e, "My Token"), 18 | String::from_str(e, "TKN"), 19 | ); 20 | } 21 | 22 | pub fn mint(e: &Env, to: Address, token_id: u32) { 23 | Enumerable::non_sequential_mint(e, &to, token_id); 24 | } 25 | } 26 | 27 | #[default_impl] 28 | #[contractimpl] 29 | impl NonFungibleToken for ExampleContract { 30 | type ContractType = Enumerable; 31 | } 32 | 33 | #[default_impl] 34 | #[contractimpl] 35 | impl NonFungibleEnumerable for ExampleContract {} 36 | 37 | fn create_client<'a>(e: &Env) -> ExampleContractClient<'a> { 38 | let address = e.register(ExampleContract, ()); 39 | ExampleContractClient::new(e, &address) 40 | } 41 | 42 | #[test] 43 | fn default_impl_enumerable_total_supply() { 44 | let e = Env::default(); 45 | 46 | let owner = Address::generate(&e); 47 | 48 | let recipient = Address::generate(&e); 49 | 50 | let client = create_client(&e); 51 | 52 | e.mock_all_auths(); 53 | client.mint(&owner, &10); 54 | client.transfer(&owner, &recipient, &10); 55 | assert_eq!(client.total_supply(), 1); 56 | } 57 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro-test/tests/ownable.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{ 2 | contract, contractimpl, contracttype, testutils::Address as _, Address, Env, String, 3 | }; 4 | use stellar_default_impl_macro::default_impl; 5 | use stellar_fungible::{Base, FungibleToken}; 6 | use stellar_ownable::{set_owner, Ownable}; 7 | use stellar_ownable_macro::only_owner; 8 | 9 | #[contracttype] 10 | pub enum DataKey { 11 | Owner, 12 | } 13 | 14 | #[contract] 15 | pub struct ExampleContract; 16 | 17 | #[contractimpl] 18 | impl ExampleContract { 19 | pub fn __constructor(e: &Env, owner: Address) { 20 | set_owner(e, &owner); 21 | Base::set_metadata(e, 7, String::from_str(e, "My Token"), String::from_str(e, "TKN")); 22 | } 23 | 24 | #[only_owner] 25 | pub fn mint(e: &Env, to: Address, amount: i128) { 26 | Base::mint(e, &to, amount); 27 | } 28 | } 29 | 30 | #[default_impl] 31 | #[contractimpl] 32 | impl FungibleToken for ExampleContract { 33 | type ContractType = Base; 34 | } 35 | 36 | #[default_impl] 37 | #[contractimpl] 38 | impl Ownable for ExampleContract {} 39 | 40 | fn create_client<'a>(e: &Env, owner: &Address) -> ExampleContractClient<'a> { 41 | let address = e.register(ExampleContract, (owner,)); 42 | ExampleContractClient::new(e, &address) 43 | } 44 | 45 | #[test] 46 | fn default_impl_ownable() { 47 | let e = Env::default(); 48 | let owner = Address::generate(&e); 49 | let client = create_client(&e, &owner); 50 | 51 | e.mock_all_auths(); 52 | 53 | client.mint(&owner, &100); 54 | } 55 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-default-impl-macro" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | -------------------------------------------------------------------------------- /packages/contract-utils/default-impl-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | 3 | use crate::helper::generate_default_impl; 4 | 5 | mod helper; 6 | 7 | /// Generates the missing default implementations for the traits provided by 8 | /// OpenZeppelin Stellar library. 9 | /// 10 | /// `#[contractimpl]` macro requires all the default implementations to be 11 | /// provided under the code block: 12 | /// 13 | /// ```ignore 14 | /// #[contractimpl] 15 | /// impl Trait for MyContract { 16 | /// /* 17 | /// The client generated by the `#[contractimpl]` macro will have access only 18 | /// to the methods specified in here. Which means, if you do not provide the 19 | /// default implementations of the methods, the client generated by the 20 | /// `#[contractimpl]` macro won't have access to those methods. 21 | /// 22 | /// This is due to how macro's work in Rust. They cannot access the default 23 | /// implementations of the methods of this trait, since they are not in the 24 | /// scope of the macro. 25 | /// 26 | /// To overcome this, we provide a macro for our traits, that generates the 27 | /// missing default implementations for the methods of the trait, so 28 | /// you can only focus on the overrides, and leave the default implementations 29 | /// out as per usual. 30 | /// */ 31 | /// } 32 | /// ``` 33 | /// 34 | /// # Example: 35 | /// 36 | /// ```ignore 37 | /// #[default_impl] // IMPORTANT: place this above `#[contractimpl]` 38 | /// #[contractimpl] 39 | /// impl NonFungibleToken for MyContract { 40 | /// /* your overrides here */ 41 | /// } 42 | /// ``` 43 | /// 44 | /// This macro works for the following traits: 45 | /// - `FungibleToken` 46 | /// - `FungibleBurnable` 47 | /// - `NonFungibleToken` 48 | /// - `NonFungibleBurnable` 49 | /// - `NonFungibleEnumerable` 50 | /// - `AccessControl` 51 | /// - `Ownable` 52 | #[proc_macro_attribute] 53 | pub fn default_impl(_attr: TokenStream, item: TokenStream) -> TokenStream { 54 | generate_default_impl(item) 55 | } 56 | -------------------------------------------------------------------------------- /packages/contract-utils/macro-helpers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-macro-helpers" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | -------------------------------------------------------------------------------- /packages/contract-utils/merkle-distributor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-merkle-distributor" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-crypto = { workspace = true } 16 | stellar-constants = { workspace = true } 17 | 18 | [dev-dependencies] 19 | soroban-sdk = { workspace = true, features = ["testutils"] } 20 | hex-literal = { workspace = true } 21 | stellar-event-assertion = { workspace = true } 22 | -------------------------------------------------------------------------------- /packages/contract-utils/merkle-distributor/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | //! # Merkle Distributor 3 | //! 4 | //! This module implements a Merkle-based claim distribution system using Merkle 5 | //! proofs for verification. 6 | //! 7 | //! ## Implementation Notes 8 | //! 9 | //! Claims are **indexed by a `u32` index**, corresponding to the position of 10 | //! each leaf in the original Merkle tree. 11 | //! 12 | //! ### Requirements for Leaf Structure 13 | //! 14 | //! - Each node (leaf) **MUST** include an indexable field of type `u32` and 15 | //! implement the `IndexableNode`. 16 | //! - Aside from the `index`, the node can contain any additional fields, with 17 | //! any names and types, depending on the specific use case (e.g., `address`, 18 | //! `amount`, `token_id`, etc.). 19 | //! - When constructing the Merkle tree, ensure that the `index` values are 20 | //! unique and consecutive (or at least unique). 21 | //! 22 | //! ### Example 23 | //! 24 | //! ```ignore,rust 25 | //! use soroban_sdk::contracttype; 26 | //! use stellar_merkle_distributor::IndexableNode; 27 | //! 28 | //! #[contracttype] 29 | //! struct LeafData { 30 | //! pub index: u32, 31 | //! pub address: Address, 32 | //! pub amount: i128, 33 | //! } 34 | //! 35 | //! impl IndexableNode for LeafData { 36 | //! fn index(&self) -> u32 { 37 | //! self.index 38 | //! } 39 | //! } 40 | //! ``` 41 | //! 42 | //! This structure supports a wide variety of distribution mechanisms such as: 43 | //! 44 | //! - Token airdrops 45 | //! - NFT distributions 46 | //! - Off-chain allowlists 47 | //! - Snapshot-based voting 48 | //! - Custom claim logic involving metadata 49 | 50 | mod merkle_distributor; 51 | mod storage; 52 | mod test; 53 | 54 | pub use crate::{ 55 | merkle_distributor::{ 56 | emit_set_claimed, emit_set_root, IndexableNode, MerkleDistributor, MerkleDistributorError, 57 | }, 58 | storage::MerkleDistributorStorageKey, 59 | }; 60 | -------------------------------------------------------------------------------- /packages/contract-utils/merkle-distributor/src/merkle_distributor.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use soroban_sdk::{contracterror, symbol_short, Bytes, Env, Symbol, Val}; 4 | use stellar_crypto::hasher::Hasher; 5 | 6 | pub trait IndexableNode { 7 | fn index(&self) -> u32; 8 | } 9 | 10 | pub struct MerkleDistributor(PhantomData); 11 | 12 | // ################## ERRORS ################## 13 | 14 | #[contracterror] 15 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 16 | #[repr(u32)] 17 | pub enum MerkleDistributorError { 18 | /// The merkle root is not set. 19 | RootNotSet = 1300, 20 | /// The merkle root is already set. 21 | RootAlreadySet = 1301, 22 | /// The provided index was already claimed. 23 | IndexAlreadyClaimed = 1302, 24 | /// The proof is invalid. 25 | InvalidProof = 1303, 26 | } 27 | 28 | // ################## EVENTS ################## 29 | 30 | /// Emits an event when a merkle root is set. 31 | /// 32 | /// # Arguments 33 | /// 34 | /// * `e` - Access to Soroban environment. 35 | /// * `root` - The root to be set. 36 | /// 37 | /// # Events 38 | /// 39 | /// * topics - `["set_root"]` 40 | /// * data - `[root: Bytes]` 41 | pub fn emit_set_root(e: &Env, root: Bytes) { 42 | let topics = (symbol_short!("set_root"),); 43 | e.events().publish(topics, root) 44 | } 45 | 46 | /// Emits an event when an index is claimed. 47 | /// 48 | /// # Arguments 49 | /// 50 | /// * `e` - Access to Soroban environment. 51 | /// * `index` - The index that was claimed. 52 | /// 53 | /// # Events 54 | /// 55 | /// * topics - `["set_claimed"]` 56 | /// * data - `[index: u32]` 57 | pub fn emit_set_claimed(e: &Env, index: Val) { 58 | let topics = (Symbol::new(e, "set_claimed"),); 59 | e.events().publish(topics, index) 60 | } 61 | -------------------------------------------------------------------------------- /packages/contract-utils/merkle-distributor/test_snapshots/test/test_root_not_set_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/contract-utils/pausable-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-pausable-macros" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | stellar-macro-helpers = { workspace = true } 18 | -------------------------------------------------------------------------------- /packages/contract-utils/pausable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-pausable" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | 16 | [dev-dependencies] 17 | soroban-sdk = { workspace = true, features = ["testutils"] } 18 | -------------------------------------------------------------------------------- /packages/contract-utils/pausable/Makefile: -------------------------------------------------------------------------------- 1 | default: build 2 | 3 | all: test 4 | 5 | test: build 6 | cargo test 7 | 8 | build: 9 | stellar contract build 10 | @ls -l target/wasm32-unknown-unknown/release/*.wasm 11 | 12 | fmt: 13 | cargo fmt --all 14 | 15 | clean: 16 | cargo clean 17 | -------------------------------------------------------------------------------- /packages/contract-utils/pausable/test_snapshots/test/initial_state.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [] 9 | ], 10 | "ledger": { 11 | "protocol_version": 22, 12 | "sequence_number": 0, 13 | "timestamp": 0, 14 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 15 | "base_reserve": 0, 16 | "min_persistent_entry_ttl": 4096, 17 | "min_temp_entry_ttl": 16, 18 | "max_entry_ttl": 6312000, 19 | "ledger_entries": [ 20 | [ 21 | { 22 | "contract_data": { 23 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 24 | "key": "ledger_key_contract_instance", 25 | "durability": "persistent" 26 | } 27 | }, 28 | [ 29 | { 30 | "last_modified_ledger_seq": 0, 31 | "data": { 32 | "contract_data": { 33 | "ext": "v0", 34 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 35 | "key": "ledger_key_contract_instance", 36 | "durability": "persistent", 37 | "val": { 38 | "contract_instance": { 39 | "executable": { 40 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 41 | }, 42 | "storage": null 43 | } 44 | } 45 | } 46 | }, 47 | "ext": "v0" 48 | }, 49 | 4095 50 | ] 51 | ], 52 | [ 53 | { 54 | "contract_code": { 55 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 56 | } 57 | }, 58 | [ 59 | { 60 | "last_modified_ledger_seq": 0, 61 | "data": { 62 | "contract_code": { 63 | "ext": "v0", 64 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 65 | "code": "" 66 | } 67 | }, 68 | "ext": "v0" 69 | }, 70 | 4095 71 | ] 72 | ] 73 | ] 74 | }, 75 | "events": [] 76 | } -------------------------------------------------------------------------------- /packages/contract-utils/pausable/test_snapshots/test/when_not_paused_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [] 9 | ], 10 | "ledger": { 11 | "protocol_version": 22, 12 | "sequence_number": 0, 13 | "timestamp": 0, 14 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 15 | "base_reserve": 0, 16 | "min_persistent_entry_ttl": 4096, 17 | "min_temp_entry_ttl": 16, 18 | "max_entry_ttl": 6312000, 19 | "ledger_entries": [ 20 | [ 21 | { 22 | "contract_data": { 23 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 24 | "key": "ledger_key_contract_instance", 25 | "durability": "persistent" 26 | } 27 | }, 28 | [ 29 | { 30 | "last_modified_ledger_seq": 0, 31 | "data": { 32 | "contract_data": { 33 | "ext": "v0", 34 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 35 | "key": "ledger_key_contract_instance", 36 | "durability": "persistent", 37 | "val": { 38 | "contract_instance": { 39 | "executable": { 40 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 41 | }, 42 | "storage": null 43 | } 44 | } 45 | } 46 | }, 47 | "ext": "v0" 48 | }, 49 | 4095 50 | ] 51 | ], 52 | [ 53 | { 54 | "contract_code": { 55 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 56 | } 57 | }, 58 | [ 59 | { 60 | "last_modified_ledger_seq": 0, 61 | "data": { 62 | "contract_code": { 63 | "ext": "v0", 64 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 65 | "code": "" 66 | } 67 | }, 68 | "ext": "v0" 69 | }, 70 | 4095 71 | ] 72 | ] 73 | ] 74 | }, 75 | "events": [] 76 | } -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-upgradeable-macros" 3 | authors.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | version.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | doctest = false 12 | 13 | [dependencies] 14 | proc-macro2 = { workspace = true } 15 | quote = { workspace = true } 16 | syn = { workspace = true } 17 | -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-upgradeable" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | 16 | [dev-dependencies] 17 | soroban-sdk = { workspace = true, features = ["testutils"] } 18 | -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable/src/storage.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{panic_with_error, symbol_short, Env, Symbol}; 2 | 3 | use crate::upgradeable::UpgradeableError; 4 | 5 | pub const MIGRATING: Symbol = symbol_short!("MIGRATING"); 6 | 7 | /// Sets the `MIGRATING` state to `true`, enabling migration process. 8 | /// 9 | /// # Arguments 10 | /// 11 | /// * `e` - The Soroban environment. 12 | pub fn enable_migration(e: &Env) { 13 | e.storage().instance().set(&MIGRATING, &true); 14 | } 15 | 16 | /// Returns `true` if completing migration is allowed. 17 | /// 18 | /// # Arguments 19 | /// 20 | /// * `e` - The Soroban environment. 21 | pub fn can_complete_migration(e: &Env) -> bool { 22 | e.storage().instance().get::<_, bool>(&MIGRATING).unwrap_or(false) 23 | } 24 | 25 | /// Sets the `MIGRATING` state to `false`, completing the migration process. 26 | /// 27 | /// # Arguments 28 | /// 29 | /// * `e` - The Soroban environment. 30 | pub fn complete_migration(e: &Env) { 31 | e.storage().instance().set(&MIGRATING, &false); 32 | } 33 | 34 | /// Ensures that completing migration is allowed, otherwise panics. 35 | /// 36 | /// # Arguments 37 | /// 38 | /// * `e` - The Soroban environment. 39 | /// 40 | /// # Errors 41 | /// 42 | /// * [`UpgradeableError::MigrationNotAllowed`] - If `MIGRATING` is `false`. 43 | pub fn ensure_can_complete_migration(e: &Env) { 44 | if !can_complete_migration(e) { 45 | panic_with_error!(e, UpgradeableError::MigrationNotAllowed) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable/src/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use soroban_sdk::{contract, Env}; 4 | 5 | use crate::storage::{ 6 | can_complete_migration, complete_migration, enable_migration, ensure_can_complete_migration, 7 | }; 8 | 9 | #[contract] 10 | struct MockContract; 11 | 12 | #[test] 13 | fn upgrade_flow_works() { 14 | let e = Env::default(); 15 | let address = e.register(MockContract, ()); 16 | 17 | e.as_contract(&address, || { 18 | assert!(!can_complete_migration(&e)); 19 | 20 | enable_migration(&e); 21 | assert!(can_complete_migration(&e)); 22 | 23 | complete_migration(&e); 24 | assert!(!can_complete_migration(&e)); 25 | }); 26 | } 27 | 28 | #[test] 29 | #[should_panic(expected = "Error(Contract, #1100)")] 30 | fn upgrade_ensure_can_complete_migration_panics_if_not_migrating() { 31 | let e = Env::default(); 32 | let address = e.register(MockContract, ()); 33 | 34 | e.as_contract(&address, || { 35 | complete_migration(&e); 36 | ensure_can_complete_migration(&e); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable/test_snapshots/test/upgrade_ensure_can_complete_migration_panics_if_not_migrating.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/contract-utils/upgradeable/test_snapshots/test/upgrade_ensure_can_migrate_panics_if_not_migrating.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/test-utils/event-assertion/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-event-assertion" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | # This crate is only used for testing, and not compatible with `wasm32` targets. 10 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies.soroban-sdk] 11 | workspace = true 12 | features = ["testutils"] 13 | 14 | [dependencies] 15 | stellar-non-fungible = { workspace = true } 16 | -------------------------------------------------------------------------------- /packages/tokens/fungible/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-fungible" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | stellar-constants = { workspace = true } 15 | soroban-sdk = { workspace = true } 16 | 17 | [dev-dependencies] 18 | soroban-sdk = { workspace = true, features = ["testutils"] } 19 | soroban-test-helpers = { workspace = true } 20 | stellar-event-assertion = { workspace = true } 21 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/extensions/burnable/storage.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{Address, Env}; 2 | 3 | use crate::{extensions::burnable::emit_burn, Base}; 4 | 5 | impl Base { 6 | /// Destroys `amount` of tokens from `from`. Updates the total 7 | /// supply accordingly. 8 | /// 9 | /// # Arguments 10 | /// 11 | /// * `e` - Access to the Soroban environment. 12 | /// * `from` - The account whose tokens are destroyed. 13 | /// * `amount` - The amount of tokens to burn. 14 | /// 15 | /// # Errors 16 | /// 17 | /// * refer to [`Base::update`] errors. 18 | /// 19 | /// # Events 20 | /// 21 | /// * topics - `["burn", from: Address]` 22 | /// * data - `[amount: i128]` 23 | /// 24 | /// # Notes 25 | /// 26 | /// Authorization for `from` is required. 27 | pub fn burn(e: &Env, from: &Address, amount: i128) { 28 | from.require_auth(); 29 | Base::update(e, Some(from), None, amount); 30 | emit_burn(e, from, amount); 31 | } 32 | 33 | /// Destroys `amount` of tokens from `from` using the allowance mechanism. 34 | /// `amount` is then deducted from `spender` allowance. 35 | /// Updates the total supply accordingly. 36 | /// 37 | /// # Arguments 38 | /// 39 | /// * `e` - Access to the Soroban environment. 40 | /// * `spender` - The address authorizing the transfer, and having its 41 | /// allowance. 42 | /// * `from` - The account whose tokens are destroyed. 43 | /// * `amount` - The amount of tokens to burn. 44 | /// 45 | /// # Errors 46 | /// 47 | /// * refer to [`Base::spend_allowance`] errors. 48 | /// * refer to [`Base::update`] errors. 49 | /// 50 | /// # Events 51 | /// 52 | /// * topics - `["burn", from: Address]` 53 | /// * data - `[amount: i128]` 54 | /// 55 | /// # Notes 56 | /// 57 | /// Authorization for `spender` is required. 58 | pub fn burn_from(e: &Env, spender: &Address, from: &Address, amount: i128) { 59 | spender.require_auth(); 60 | Base::spend_allowance(e, from, spender, amount); 61 | Base::update(e, Some(from), None, amount); 62 | emit_burn(e, from, amount); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/extensions/capped/mod.rs: -------------------------------------------------------------------------------- 1 | /// Unlike other extensions, the `capped` extension does not provide a separate 2 | /// trait. This is because its methods are not intended to be used 3 | /// independently, like [`crate::extensions::burnable::burn()`]. 4 | /// Instead, the `capped` extension modifies the business logic of the `mint` 5 | /// function to enforce a supply cap. 6 | /// 7 | /// This module provides the following helper functions: 8 | /// - `set_cap`: Sets the maximum token supply. 9 | /// - `query_cap`: Returns the maximum token supply. 10 | /// - `check_cap`: Panics if minting a specified `amount` would exceed the cap. 11 | /// Should be used before calling `mint()`. 12 | mod storage; 13 | pub use self::storage::{check_cap, query_cap, set_cap, CAP_KEY}; 14 | mod test; 15 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/extensions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod allowlist; 2 | pub mod blocklist; 3 | pub mod burnable; 4 | pub mod capped; 5 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sac_admin_generic; 2 | pub mod sac_admin_wrapper; 3 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/utils/sac_admin_generic/README.md: -------------------------------------------------------------------------------- 1 | An example flow when a `SACAdminGeneric` contract is set as a new administrator for a Stellar Classic Asset (SAC). 2 | 3 | ```mermaid 4 | sequenceDiagram 5 | actor Issuer 6 | actor Minter 7 | participant AdminGeneric as AdminGeneric
Contract 8 | participant AdminSigner 9 | participant SAC as Stellar
Asset
Contract 10 | actor User as Asset Holder 11 | 12 | Note over Issuer,AdminGeneric: 1. Asset Deployment 13 | Issuer->>SAC: Deploy Stellar Asset Contract 14 | Note over SAC: Issuer is the initial admin 15 | 16 | Note over Issuer,AdminGeneric: 2. AdminGeneric Deployment and Setup 17 | Issuer->>AdminGeneric: Deploy AdminGeneric with __constructor(SAC, AdminSigner, Minter) 18 | Note over AdminGeneric: Constructor stores
SAC address,
AdminSigner address,
and Minter address 19 | 20 | Note over Issuer,AdminGeneric: 3. Admin Change 21 | Issuer->>SAC: set_admin(AdminGeneric) 22 | SAC-->>Issuer: Success (AdminGeneric is now admin) 23 | 24 | Note over Minter,AdminGeneric: 4. Admin Functions
via AdminGeneric 25 | Minter->>SAC: mint(User, 1000) 26 | activate SAC 27 | critical Policies checked and signers verified 28 | SAC->>+AdminGeneric: require_auth() 29 | AdminGeneric->>AdminSigner: require_auth() 30 | AdminSigner-->>AdminGeneric: Authorized 31 | AdminGeneric-->>-SAC: Authorized
(automatically because it was the invoker) 32 | end 33 | SAC-->>User: Receive 1000 tokens 34 | SAC-->>-Minter: Success 35 | 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /packages/tokens/fungible/src/utils/sac_admin_wrapper/README.md: -------------------------------------------------------------------------------- 1 | An example flow when a `SACAdminWrapper` contract is set as a new administrator for a Stellar Classic Asset (SAC). 2 | 3 | ```mermaid 4 | sequenceDiagram 5 | actor Issuer 6 | actor Minter 7 | participant AdminWrapper as AdminWrapper
Contract 8 | participant AdminSigner 9 | participant SAC as Stellar
Asset
Contract 10 | actor User as Asset Holder 11 | 12 | Note over Issuer,AdminWrapper: 1. Asset Deployment 13 | Issuer->>SAC: Deploy Stellar Asset Contract 14 | Note over SAC: Issuer is the initial admin 15 | 16 | Note over Issuer,AdminWrapper: 2. AdminWrapper Deployment and Setup 17 | Issuer->>AdminWrapper: Deploy AdminWrapper with __constructor(SAC, AdminSigner, Minter) 18 | Note over AdminWrapper: Constructor stores
SAC address,
AdminSigner address,
and Minter address 19 | 20 | Note over Issuer,AdminWrapper: 3. Admin Change 21 | Issuer->>SAC: set_admin(AdminWrapper) 22 | SAC-->>Issuer: Success (AdminWrapper is now admin) 23 | 24 | Note over Minter,AdminWrapper: 4. Admin Functions
via AdminWrapper 25 | Minter->>AdminWrapper: mint(User, 1000) 26 | activate AdminWrapper 27 | activate AdminWrapper 28 | critical Policies checked and signers verified 29 | AdminWrapper->>AdminSigner: require_auth() 30 | AdminSigner-->>AdminWrapper: Authorized 31 | end 32 | deactivate AdminWrapper 33 | AdminWrapper->>SAC: mint(User, 1000) 34 | activate SAC 35 | SAC->>AdminWrapper: require_auth() 36 | AdminWrapper-->>SAC: Authorized
(automatically because it was the invoker) 37 | SAC-->>User: Receive 1000 tokens 38 | SAC-->>AdminWrapper: Success 39 | deactivate SAC 40 | AdminWrapper-->>Minter: Success 41 | deactivate AdminWrapper 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/extensions/allowlist/test/approve_with_owner_not_allowed_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/extensions/capped/test/test_cap_not_set.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/extensions/capped/test/test_invalid_cap.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/extensions/capped/test/test_mint_exceeds_cap.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/extensions/metadata/test/get_unset_metadata.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/bump_instance_works.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [] 9 | ], 10 | "ledger": { 11 | "protocol_version": 22, 12 | "sequence_number": 499, 13 | "timestamp": 0, 14 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 15 | "base_reserve": 0, 16 | "min_persistent_entry_ttl": 500, 17 | "min_temp_entry_ttl": 16, 18 | "max_entry_ttl": 6312000, 19 | "ledger_entries": [ 20 | [ 21 | { 22 | "contract_data": { 23 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 24 | "key": "ledger_key_contract_instance", 25 | "durability": "persistent" 26 | } 27 | }, 28 | [ 29 | { 30 | "last_modified_ledger_seq": 0, 31 | "data": { 32 | "contract_data": { 33 | "ext": "v0", 34 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 35 | "key": "ledger_key_contract_instance", 36 | "durability": "persistent", 37 | "val": { 38 | "contract_instance": { 39 | "executable": { 40 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 41 | }, 42 | "storage": null 43 | } 44 | } 45 | } 46 | }, 47 | "ext": "v0" 48 | }, 49 | 121459 50 | ] 51 | ], 52 | [ 53 | { 54 | "contract_code": { 55 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 56 | } 57 | }, 58 | [ 59 | { 60 | "last_modified_ledger_seq": 0, 61 | "data": { 62 | "contract_code": { 63 | "ext": "v0", 64 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 65 | "code": "" 66 | } 67 | }, 68 | "ext": "v0" 69 | }, 70 | 121459 71 | ] 72 | ] 73 | ] 74 | }, 75 | "events": [] 76 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/get_unset_metadata.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/initial_state.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [] 9 | ], 10 | "ledger": { 11 | "protocol_version": 22, 12 | "sequence_number": 0, 13 | "timestamp": 0, 14 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 15 | "base_reserve": 0, 16 | "min_persistent_entry_ttl": 4096, 17 | "min_temp_entry_ttl": 16, 18 | "max_entry_ttl": 6312000, 19 | "ledger_entries": [ 20 | [ 21 | { 22 | "contract_data": { 23 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 24 | "key": "ledger_key_contract_instance", 25 | "durability": "persistent" 26 | } 27 | }, 28 | [ 29 | { 30 | "last_modified_ledger_seq": 0, 31 | "data": { 32 | "contract_data": { 33 | "ext": "v0", 34 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 35 | "key": "ledger_key_contract_instance", 36 | "durability": "persistent", 37 | "val": { 38 | "contract_instance": { 39 | "executable": { 40 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 41 | }, 42 | "storage": null 43 | } 44 | } 45 | } 46 | }, 47 | "ext": "v0" 48 | }, 49 | 4095 50 | ] 51 | ], 52 | [ 53 | { 54 | "contract_code": { 55 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 56 | } 57 | }, 58 | [ 59 | { 60 | "last_modified_ledger_seq": 0, 61 | "data": { 62 | "contract_code": { 63 | "ext": "v0", 64 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 65 | "code": "" 66 | } 67 | }, 68 | "ext": "v0" 69 | }, 70 | 4095 71 | ] 72 | ] 73 | ] 74 | }, 75 | "events": [] 76 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/set_allowance_with_expired_ledger_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 10, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/set_allowance_with_greater_than_max_ledger_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/set_allowance_with_neg_amount_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/spend_allowance_invalid_amount_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/update_with_invalid_amount_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/test/update_with_invalid_value_panics.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/utils/sac_admin_generic/test/test_extract_context_address_mismatch.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/utils/sac_admin_generic/test/test_extract_context_invalid_param_type.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 3, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/utils/sac_admin_generic/test/test_extract_context_missing_param.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/utils/sac_admin_generic/test/test_sac_get_address_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/fungible/test_snapshots/utils/sac_admin_wrapper/test/test_sac_get_address_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stellar-non-fungible" 3 | edition.workspace = true 4 | license.workspace = true 5 | repository.workspace = true 6 | publish = false 7 | version.workspace = true 8 | 9 | [lib] 10 | crate-type = ["lib", "cdylib"] 11 | doctest = false 12 | 13 | [dependencies] 14 | soroban-sdk = { workspace = true } 15 | stellar-constants = { workspace = true } 16 | 17 | [dev-dependencies] 18 | soroban-sdk = { workspace = true, features = ["testutils"] } 19 | stellar-event-assertion = { workspace = true } 20 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/extensions/burnable/storage.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{Address, Env}; 2 | 3 | use crate::{extensions::burnable::emit_burn, Base}; 4 | 5 | impl Base { 6 | /// Destroys the token with `token_id` from `from`, ensuring ownership 7 | /// checks, and emits a `burn` event. 8 | /// 9 | /// # Arguments 10 | /// 11 | /// * `e` - Access to the Soroban environment. 12 | /// * `from` - The account whose token is destroyed. 13 | /// * `token_id` - The identifier of the token to burn. 14 | /// 15 | /// # Errors 16 | /// 17 | /// * refer to [`update`] errors. 18 | /// 19 | /// # Events 20 | /// 21 | /// * topics - `["burn", from: Address]` 22 | /// * data - `[token_id: u32]` 23 | /// 24 | /// # Notes 25 | /// 26 | /// Authorization for `from` is required. 27 | pub fn burn(e: &Env, from: &Address, token_id: u32) { 28 | from.require_auth(); 29 | Base::update(e, Some(from), None, token_id); 30 | emit_burn(e, from, token_id); 31 | } 32 | 33 | /// Destroys the token with `token_id` from `from`, ensuring ownership 34 | /// and approval checks, and emits a `burn` event. 35 | /// 36 | /// # Arguments 37 | /// 38 | /// * `e` - Access to the Soroban environment. 39 | /// * `spender` - The account that is allowed to burn the token on behalf of 40 | /// the owner. 41 | /// * `from` - The account whose token is destroyed. 42 | /// * `token_id` - The identifier of the token to burn. 43 | /// 44 | /// # Errors 45 | /// 46 | /// * refer to [`check_spender_approval`] errors. 47 | /// * refer to [`update`] errors. 48 | /// 49 | /// # Events 50 | /// 51 | /// * topics - `["burn", from: Address]` 52 | /// * data - `[token_id: u32]` 53 | /// 54 | /// # Notes 55 | /// 56 | /// Authorization for `spender` is required. 57 | pub fn burn_from(e: &Env, spender: &Address, from: &Address, token_id: u32) { 58 | spender.require_auth(); 59 | Base::check_spender_approval(e, spender, from, token_id); 60 | Base::update(e, Some(from), None, token_id); 61 | emit_burn(e, from, token_id); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/extensions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod burnable; 2 | pub mod consecutive; 3 | pub mod enumerable; 4 | pub mod royalties; 5 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sequential; 2 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/utils/sequential/mod.rs: -------------------------------------------------------------------------------- 1 | mod storage; 2 | mod test; 3 | 4 | pub use self::storage::{increment_token_id, next_token_id}; 5 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/utils/sequential/storage.rs: -------------------------------------------------------------------------------- 1 | use soroban_sdk::{contracttype, panic_with_error, Env}; 2 | 3 | use crate::NonFungibleTokenError; 4 | 5 | #[contracttype] 6 | pub enum NFTSequentialStorageKey { 7 | TokenIdCounter, 8 | } 9 | 10 | /// Get the current token counter value to determine the next token_id. 11 | /// The returned value is the next available token_id. 12 | /// 13 | /// # Arguments 14 | /// 15 | /// * `e` - Access to the Soroban environment. 16 | pub fn next_token_id(e: &Env) -> u32 { 17 | e.storage().instance().get(&NFTSequentialStorageKey::TokenIdCounter).unwrap_or(0) 18 | } 19 | 20 | /// Return the next free token ID, then increment the counter. 21 | /// 22 | /// # Arguments 23 | /// 24 | /// * `e` - Access to the Soroban environment. 25 | /// * `amount` - The number by which the counter is incremented. 26 | /// 27 | /// # Errors 28 | /// 29 | /// * [`crate::NonFungibleTokenError::TokenIDsAreDepleted`] - When all the 30 | /// available `token_id`s are consumed for this smart contract. 31 | pub fn increment_token_id(e: &Env, amount: u32) -> u32 { 32 | let current_id = next_token_id(e); 33 | let Some(next_id) = current_id.checked_add(amount) else { 34 | panic_with_error!(e, NonFungibleTokenError::TokenIDsAreDepleted); 35 | }; 36 | e.storage().instance().set(&NFTSequentialStorageKey::TokenIdCounter, &next_id); 37 | current_id 38 | } 39 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/src/utils/sequential/test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | extern crate std; 4 | 5 | use soroban_sdk::{contract, Env}; 6 | 7 | use crate::sequential::storage::{increment_token_id, next_token_id, NFTSequentialStorageKey}; 8 | 9 | #[contract] 10 | pub struct MockContract; 11 | 12 | #[test] 13 | fn sequential_token_id_counter_increments() { 14 | let e = Env::default(); 15 | let address = e.register(MockContract, ()); 16 | 17 | e.as_contract(&address, || { 18 | assert_eq!(next_token_id(&e), 0); 19 | 20 | let id1 = increment_token_id(&e, 10); 21 | assert_eq!(id1, 0); 22 | assert_eq!(next_token_id(&e), 10); 23 | 24 | let id2 = increment_token_id(&e, 5); 25 | assert_eq!(id2, 10); 26 | assert_eq!(next_token_id(&e), 15); 27 | }); 28 | } 29 | 30 | #[test] 31 | #[should_panic(expected = "Error(Contract, #206)")] 32 | fn sequential_increment_token_id_fails_on_overflow() { 33 | let e = Env::default(); 34 | let address = e.register(MockContract, ()); 35 | 36 | e.as_contract(&address, || { 37 | e.storage().instance().set(&NFTSequentialStorageKey::TokenIdCounter, &u32::MAX); 38 | let _ = increment_token_id(&e, 1); 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/consecutive/test/consecutive_batch_mint_amount_0_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/consecutive/test/consecutive_batch_mint_amount_max_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/consecutive/test/consecutive_owner_of_on_zero_token_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/enumerable/test/test_remove_from_global_enumeration.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/royalties/test/test_royalty_info_non_existent_token.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/extensions/royalties/test/test_set_default_royalty_too_high.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/test/balance_of_non_existent_account_is_zero.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 2, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [], 8 | [] 9 | ], 10 | "ledger": { 11 | "protocol_version": 22, 12 | "sequence_number": 0, 13 | "timestamp": 0, 14 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 15 | "base_reserve": 0, 16 | "min_persistent_entry_ttl": 4096, 17 | "min_temp_entry_ttl": 16, 18 | "max_entry_ttl": 6312000, 19 | "ledger_entries": [ 20 | [ 21 | { 22 | "contract_data": { 23 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 24 | "key": "ledger_key_contract_instance", 25 | "durability": "persistent" 26 | } 27 | }, 28 | [ 29 | { 30 | "last_modified_ledger_seq": 0, 31 | "data": { 32 | "contract_data": { 33 | "ext": "v0", 34 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 35 | "key": "ledger_key_contract_instance", 36 | "durability": "persistent", 37 | "val": { 38 | "contract_instance": { 39 | "executable": { 40 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 41 | }, 42 | "storage": null 43 | } 44 | } 45 | } 46 | }, 47 | "ext": "v0" 48 | }, 49 | 4095 50 | ] 51 | ], 52 | [ 53 | { 54 | "contract_code": { 55 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 56 | } 57 | }, 58 | [ 59 | { 60 | "last_modified_ledger_seq": 0, 61 | "data": { 62 | "contract_code": { 63 | "ext": "v0", 64 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 65 | "code": "" 66 | } 67 | }, 68 | "ext": "v0" 69 | }, 70 | 4095 71 | ] 72 | ] 73 | ] 74 | }, 75 | "events": [] 76 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/test/get_metadata_should_panic_when_metadata_is_not_set.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/test/owner_of_non_existent_token_fails.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/test/set_metadata_should_panic_when_base_uri_exceeds_max_length.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /packages/tokens/non-fungible/test_snapshots/utils/sequential/test/sequential_increment_token_id_fails_on_overflow.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "address": 1, 4 | "nonce": 0 5 | }, 6 | "auth": [ 7 | [] 8 | ], 9 | "ledger": { 10 | "protocol_version": 22, 11 | "sequence_number": 0, 12 | "timestamp": 0, 13 | "network_id": "0000000000000000000000000000000000000000000000000000000000000000", 14 | "base_reserve": 0, 15 | "min_persistent_entry_ttl": 4096, 16 | "min_temp_entry_ttl": 16, 17 | "max_entry_ttl": 6312000, 18 | "ledger_entries": [ 19 | [ 20 | { 21 | "contract_data": { 22 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 23 | "key": "ledger_key_contract_instance", 24 | "durability": "persistent" 25 | } 26 | }, 27 | [ 28 | { 29 | "last_modified_ledger_seq": 0, 30 | "data": { 31 | "contract_data": { 32 | "ext": "v0", 33 | "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", 34 | "key": "ledger_key_contract_instance", 35 | "durability": "persistent", 36 | "val": { 37 | "contract_instance": { 38 | "executable": { 39 | "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 40 | }, 41 | "storage": null 42 | } 43 | } 44 | } 45 | }, 46 | "ext": "v0" 47 | }, 48 | 4095 49 | ] 50 | ], 51 | [ 52 | { 53 | "contract_code": { 54 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 55 | } 56 | }, 57 | [ 58 | { 59 | "last_modified_ledger_seq": 0, 60 | "data": { 61 | "contract_code": { 62 | "ext": "v0", 63 | "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 64 | "code": "" 65 | } 66 | }, 67 | "ext": "v0" 68 | }, 69 | 4095 70 | ] 71 | ] 72 | ] 73 | }, 74 | "events": [] 75 | } -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | targets = ["wasm32-unknown-unknown"] 4 | components = ["rustfmt", "clippy", "rust-src"] 5 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | 2 | format_macro_bodies = true 3 | format_macro_matchers = true 4 | format_strings = true 5 | imports_granularity = "Crate" 6 | match_arm_blocks = false 7 | reorder_impl_items = true 8 | group_imports = "StdExternalCrate" 9 | use_field_init_shorthand = true 10 | use_small_heuristics = "Max" 11 | wrap_comments = true 12 | format_code_in_doc_comments = true 13 | 14 | # most of these are unstable, so we enable them 15 | unstable_features = true 16 | 17 | 18 | # wanted to enable below, but they are removing the documentation comments if there is an empty line in between 19 | # wrap_comments = true 20 | # format_code_in_doc_comments = true 21 | --------------------------------------------------------------------------------