├── .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 |
--------------------------------------------------------------------------------