From cf3ef5f8ffdcdc41ab54ab6d9ef7e0a385a153f1 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Fri, 6 Mar 2026 12:42:14 +0200 Subject: [PATCH 1/9] published files --- packages/pas/Published.toml | 12 ++++++++++++ packages/ptb/Published.toml | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 packages/pas/Published.toml create mode 100644 packages/ptb/Published.toml diff --git a/packages/pas/Published.toml b/packages/pas/Published.toml new file mode 100644 index 0000000..184c2e2 --- /dev/null +++ b/packages/pas/Published.toml @@ -0,0 +1,12 @@ +# Generated by Move +# This file contains metadata about published versions of this package in different environments +# This file SHOULD be committed to source control + +[published.testnet] +chain-id = "4c78adac" +published-at = "0x99aaabf713d90278bfde44c0c854fe7588d551de1d000e3a065e519dafc268a9" +original-id = "0x99aaabf713d90278bfde44c0c854fe7588d551de1d000e3a065e519dafc268a9" +version = 1 +toolchain-version = "1.66.1" +build-config = { flavor = "sui", edition = "2024" } +upgrade-capability = "0x0fc39d004bfe813ffdf0cd983d2fb15fb6e2ef83b857d67ca257b725676763eb" diff --git a/packages/ptb/Published.toml b/packages/ptb/Published.toml new file mode 100644 index 0000000..567ef6b --- /dev/null +++ b/packages/ptb/Published.toml @@ -0,0 +1,12 @@ +# Generated by Move +# This file contains metadata about published versions of this package in different environments +# This file SHOULD be committed to source control + +[published.testnet] +chain-id = "4c78adac" +published-at = "0xc53cecae541e43e672bd359d3f3667b2b0dcb09785b3d4eba18bb88b3dd8ee55" +original-id = "0xc53cecae541e43e672bd359d3f3667b2b0dcb09785b3d4eba18bb88b3dd8ee55" +version = 1 +toolchain-version = "1.66.1" +build-config = { flavor = "sui", edition = "2024" } +upgrade-capability = "0x8201bf60419edec4241995f5644b16f63c12d3e925f5eff9dcdc7877e175d0fb" From b0aea83f0cceb534cf9a0e77c50a5c0ce8ca20f9 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Mon, 9 Mar 2026 19:02:19 +0200 Subject: [PATCH 2/9] feat: acme securities example --- packages/testing/acme_compliance/Move.lock | 35 +++ packages/testing/acme_compliance/Move.toml | 7 + .../sources/acme_compliance.move | 202 ++++++++++++++++++ .../acme_compliance/sources/acme_token.move | 22 ++ .../sources/acme_treasury.move | 96 +++++++++ 5 files changed, 362 insertions(+) create mode 100644 packages/testing/acme_compliance/Move.lock create mode 100644 packages/testing/acme_compliance/Move.toml create mode 100644 packages/testing/acme_compliance/sources/acme_compliance.move create mode 100644 packages/testing/acme_compliance/sources/acme_token.move create mode 100644 packages/testing/acme_compliance/sources/acme_treasury.move diff --git a/packages/testing/acme_compliance/Move.lock b/packages/testing/acme_compliance/Move.lock new file mode 100644 index 0000000..ce7cda3 --- /dev/null +++ b/packages/testing/acme_compliance/Move.lock @@ -0,0 +1,35 @@ +# Generated by move; do not edit +# This file should be checked in. + +[move] +version = 4 + +[pinned.testnet.MoveStdlib] +source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } +use_environment = "testnet" +manifest_digest = "C4FE4C91DE74CBF223B2E380AE40F592177D21870DC2D7EB6227D2D694E05363" +deps = {} + +[pinned.testnet.Sui] +source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } +use_environment = "testnet" +manifest_digest = "7AFB66695545775FBFBB2D3078ADFD084244D5002392E837FDE21D9EA1C6D01C" +deps = { MoveStdlib = "MoveStdlib" } + +[pinned.testnet.acme_compliance] +source = { root = true } +use_environment = "testnet" +manifest_digest = "F42F13A0483640C91598349E0E0C125899BD5635A850639255F6EC2E598ADAF8" +deps = { pas = "pas", ptb = "ptb", std = "MoveStdlib", sui = "Sui" } + +[pinned.testnet.pas] +source = { local = "../../pas" } +use_environment = "testnet" +manifest_digest = "38AA62656ABE7551C444DA427ADBAA7751CB67250663D39FCDE36E938138EA7D" +deps = { ptb = "ptb", std = "MoveStdlib", sui = "Sui" } + +[pinned.testnet.ptb] +source = { local = "../../ptb" } +use_environment = "testnet" +manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87" +deps = { std = "MoveStdlib", sui = "Sui" } diff --git a/packages/testing/acme_compliance/Move.toml b/packages/testing/acme_compliance/Move.toml new file mode 100644 index 0000000..7e6e63b --- /dev/null +++ b/packages/testing/acme_compliance/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "acme_compliance" +edition = "2024.beta" + +[dependencies] +pas = { local = "../../pas" } +ptb = { local = "../../ptb" } diff --git a/packages/testing/acme_compliance/sources/acme_compliance.move b/packages/testing/acme_compliance/sources/acme_compliance.move new file mode 100644 index 0000000..142a637 --- /dev/null +++ b/packages/testing/acme_compliance/sources/acme_compliance.move @@ -0,0 +1,202 @@ +/// Example: Securities compliance with PAS. +/// +/// Demonstrates two common compliance rules for tokenized securities: +/// 1. Accredited investor checks (both sender and recipient must be accredited) +/// 2. Holding limits (min/max balance per investor) +/// +/// Balance tracking is maintained internally because PAS stores balances inside +/// Chests using Sui's address balances, which the compliance contract cannot +/// read directly during approval. +module acme_compliance::acme_compliance; + +use pas::clawback_funds::ClawbackFunds; +use pas::request::Request; +use pas::send_funds::SendFunds; +use sui::balance::Balance; +use sui::table::Table; +use acme_compliance::acme_token::ACME_TOKEN; + +// ==== Error Codes ==== + +#[error] +const ENotWhitelisted: vector = b"Address is not in the investor registry"; +#[error] +const ENotAccredited: vector = b"Investor is not accredited"; +#[error] +const EBelowMinBalance: vector = b"Balance would fall below minimum holding requirement"; +#[error] +const EAboveMaxBalance: vector = b"Balance would exceed maximum holding limit"; + +// ==== Witness ==== + +/// Witness stamp for approved transfers. +public struct TransferApproval() has drop; + +/// Witness stamp for approved clawbacks (burn). +public struct ClawbackApproval() has drop; + +// ==== Structs ==== + +/// On-chain registry of investor status and balances. +public struct InvestorRegistry has key { + id: UID, + investors: Table, + /// Minimum balance per investor (0 = no minimum) + min_balance: u64, + /// Maximum balance per investor (0 = no maximum) + max_balance: u64, +} + +public struct InvestorProfile has drop, store { + accredited: bool, + balance: u64, +} + +/// Admin capability for managing the registry +public struct RegistryCap has key, store { id: UID } + +// ==== Init ==== + +fun init(ctx: &mut TxContext) { + transfer::share_object(InvestorRegistry { + id: object::new(ctx), + investors: sui::table::new(ctx), + min_balance: 0, + max_balance: 0, + }); + transfer::transfer(RegistryCap { id: object::new(ctx) }, ctx.sender()); +} + +// ==== Approval Functions ==== + +/// Validates accreditation and holding limits for both parties, +/// updates internal balance tracking, then stamps the request. +public fun approve_transfer( + registry: &mut InvestorRegistry, + request: &mut Request>>, +) { + let sender = request.data().sender(); + let recipient = request.data().recipient(); + let amount = request.data().funds().value(); + + assert_eligible(registry, sender); + assert_eligible(registry, recipient); + + // Check sender's remaining balance meets minimum (if non-zero after transfer) + let sender_balance_after = registry.investors.borrow(sender).balance - amount; + if (sender_balance_after > 0 && registry.min_balance > 0) { + assert!(sender_balance_after >= registry.min_balance, EBelowMinBalance); + }; + + // Check recipient's new balance within limits + let recipient_balance_after = registry.investors.borrow(recipient).balance + amount; + assert_within_limits(registry, recipient_balance_after); + + // Update internal balance tracking + registry.investors.borrow_mut(sender).balance = sender_balance_after; + registry.investors.borrow_mut(recipient).balance = recipient_balance_after; + + request.approve(TransferApproval()); +} + +/// Validates accreditation and holding limits for a clawback, +/// updates internal balance tracking, then stamps the request. +public(package) fun approve_clawback( + registry: &mut InvestorRegistry, + request: &mut Request>>, +) { + let investor = request.data().owner(); + let amount = request.data().funds().value(); + + assert_eligible(registry, investor); + + // Allow burning to zero, otherwise check minimum + let new_balance = registry.investors.borrow(investor).balance - amount; + if (new_balance > 0 && registry.min_balance > 0) { + assert!(new_balance >= registry.min_balance, EBelowMinBalance); + }; + + registry.investors.borrow_mut(investor).balance = new_balance; + request.approve(ClawbackApproval()); +} + +/// Validates accreditation and holding limits for minting, +/// updates internal balance tracking. +public(package) fun validate_mint( + registry: &mut InvestorRegistry, + _cap: &RegistryCap, + investor: address, + amount: u64, +) { + assert_eligible(registry, investor); + + let new_balance = registry.investors.borrow(investor).balance + amount; + assert_within_limits(registry, new_balance); + + registry.investors.borrow_mut(investor).balance = new_balance; +} + +// ==== Permits ==== + +/// Permit for TransferApproval (only this module can create it). +public(package) fun transfer_approval_permit(): internal::Permit { + internal::permit() +} + +/// Permit for ClawbackApproval (only this module can create it). +public(package) fun clawback_approval_permit(): internal::Permit { + internal::permit() +} + +// ==== Admin ==== + +/// Register or update an investor's accreditation status. +public fun set_investor( + registry: &mut InvestorRegistry, + _cap: &RegistryCap, + investor: address, + accredited: bool, +) { + if (registry.investors.contains(investor)) { + registry.investors.borrow_mut(investor).accredited = accredited; + } else { + registry + .investors + .add( + investor, + InvestorProfile { + accredited, + balance: 0, + }, + ); + } +} + +/// Configure holding limits. +public fun set_holding_limits( + registry: &mut InvestorRegistry, + _cap: &RegistryCap, + min_balance: u64, + max_balance: u64, +) { + registry.min_balance = min_balance; + registry.max_balance = max_balance; +} + +// ==== Internal ==== + +/// Assert investor is registered and accredited. +fun assert_eligible(registry: &InvestorRegistry, investor: address) { + assert!(registry.investors.contains(investor), ENotWhitelisted); + assert!(registry.investors.borrow(investor).accredited, ENotAccredited); +} + +/// Assert balance is within configured min/max limits. +fun assert_within_limits(registry: &InvestorRegistry, balance: u64) { + if (registry.min_balance > 0) { + assert!(balance >= registry.min_balance, EBelowMinBalance); + }; + if (registry.max_balance > 0) { + assert!(balance <= registry.max_balance, EAboveMaxBalance); + }; +} diff --git a/packages/testing/acme_compliance/sources/acme_token.move b/packages/testing/acme_compliance/sources/acme_token.move new file mode 100644 index 0000000..33853b7 --- /dev/null +++ b/packages/testing/acme_compliance/sources/acme_token.move @@ -0,0 +1,22 @@ +/// ACME_TOKEN currency type definition and creation. +module acme_compliance::acme_token; + +use sui::coin_registry; + +public struct ACME_TOKEN has drop {} + +fun init(otw: ACME_TOKEN, ctx: &mut TxContext) { + let (initializer, cap) = coin_registry::new_currency_with_otw( + otw, + 6, + b"ACME".to_string(), + b"Acme Token".to_string(), + b"Acme security token".to_string(), + b"https://acme.example".to_string(), + ctx, + ); + let metadata = initializer.finalize(ctx); + + transfer::public_transfer(cap, ctx.sender()); + transfer::public_transfer(metadata, ctx.sender()); +} diff --git a/packages/testing/acme_compliance/sources/acme_treasury.move b/packages/testing/acme_compliance/sources/acme_treasury.move new file mode 100644 index 0000000..2425bdf --- /dev/null +++ b/packages/testing/acme_compliance/sources/acme_treasury.move @@ -0,0 +1,96 @@ +/// Treasury operations for ACME_TOKEN. +/// +/// Handles minting (deposit into Chest) and burning (clawback from Chest), +/// enforcing the same compliance rules as transfers: accreditation and +/// holding limits. +module acme_compliance::acme_treasury; + +use acme_compliance::acme_compliance::{ + Self, + InvestorRegistry, + RegistryCap, + TransferApproval, + ClawbackApproval +}; +use acme_compliance::acme_token::ACME_TOKEN; +use pas::chest::Chest; +use pas::clawback_funds::{Self, ClawbackFunds}; +use pas::namespace::Namespace; +use pas::policy::{Self, Policy}; +use pas::request::Request; +use pas::templates::Templates; +use ptb::ptb; +use std::type_name; +use sui::balance::Balance; +use sui::coin::TreasuryCap; + +// ==== Setup ==== + +/// One-time setup: PAS policy + compliance template + holding limits. +/// Call after publishing (TreasuryCap is created in `acme_token::init`). +#[allow(lint(self_transfer), unused_mut_parameter)] +entry fun setup( + namespace: &mut Namespace, + templates: &mut Templates, + registry: &mut InvestorRegistry, + treasury_cap: &mut TreasuryCap, + registry_cap: &RegistryCap, + ctx: &mut TxContext, +) { + // 1. Create policy with clawback enabled + let (mut policy, policy_cap) = policy::new_for_currency( + namespace, + treasury_cap, + true, // clawback allowed (for burn) + ); + + // 2. Set required approvals per action + policy.set_required_approval<_, TransferApproval>(&policy_cap, "send_funds"); + policy.set_required_approval<_, ClawbackApproval>(&policy_cap, "clawback_funds"); + + // 3. Register template so the SDK can auto-construct approve_transfer calls + let type_name = type_name::with_defining_ids(); + + let cmd = ptb::move_call( + type_name.address_string().to_string(), + "acme_compliance", + "approve_transfer", + vector[ptb::ext_input("pas:request"), ptb::object_by_type()], + vector[(*type_name.as_string()).to_string()], + ); + + templates.set_template_command(acme_compliance::transfer_approval_permit(), cmd); + + policy.share(); + transfer::public_transfer(policy_cap, ctx.sender()); + + // 4. Configure holding limits: min 100 tokens, max 1M tokens (6 decimals) + registry.set_holding_limits(registry_cap, 100_000_000, 1_000_000_000_000); +} + +// ==== Mint & Burn ==== + +/// Mint tokens and deposit into an investor's Chest. +entry fun mint( + registry: &mut InvestorRegistry, + to_chest: &Chest, + cap: &mut TreasuryCap, + registry_cap: &RegistryCap, + amount: u64, +) { + registry.validate_mint(registry_cap, to_chest.owner(), amount); + to_chest.deposit_balance(cap.mint_balance(amount)); +} + +/// Burn tokens from an investor's Chest via clawback. +entry fun burn( + registry: &mut InvestorRegistry, + policy: &Policy>, + cap: &mut TreasuryCap, + mut request: Request>>, + ctx: &mut TxContext, +) { + registry.approve_clawback(&mut request); + let balance = clawback_funds::resolve(request, policy); + cap.burn(balance.into_coin(ctx)); +} From 859f62cf2dfd737a0fa0913fd657d63232f515a8 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Mon, 9 Mar 2026 19:06:47 +0200 Subject: [PATCH 3/9] wip: remove unnecessary files --- packages/pas/Published.toml | 12 ------------ packages/ptb/Published.toml | 12 ------------ 2 files changed, 24 deletions(-) delete mode 100644 packages/pas/Published.toml delete mode 100644 packages/ptb/Published.toml diff --git a/packages/pas/Published.toml b/packages/pas/Published.toml deleted file mode 100644 index 184c2e2..0000000 --- a/packages/pas/Published.toml +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Move -# This file contains metadata about published versions of this package in different environments -# This file SHOULD be committed to source control - -[published.testnet] -chain-id = "4c78adac" -published-at = "0x99aaabf713d90278bfde44c0c854fe7588d551de1d000e3a065e519dafc268a9" -original-id = "0x99aaabf713d90278bfde44c0c854fe7588d551de1d000e3a065e519dafc268a9" -version = 1 -toolchain-version = "1.66.1" -build-config = { flavor = "sui", edition = "2024" } -upgrade-capability = "0x0fc39d004bfe813ffdf0cd983d2fb15fb6e2ef83b857d67ca257b725676763eb" diff --git a/packages/ptb/Published.toml b/packages/ptb/Published.toml deleted file mode 100644 index 567ef6b..0000000 --- a/packages/ptb/Published.toml +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Move -# This file contains metadata about published versions of this package in different environments -# This file SHOULD be committed to source control - -[published.testnet] -chain-id = "4c78adac" -published-at = "0xc53cecae541e43e672bd359d3f3667b2b0dcb09785b3d4eba18bb88b3dd8ee55" -original-id = "0xc53cecae541e43e672bd359d3f3667b2b0dcb09785b3d4eba18bb88b3dd8ee55" -version = 1 -toolchain-version = "1.66.1" -build-config = { flavor = "sui", edition = "2024" } -upgrade-capability = "0x8201bf60419edec4241995f5644b16f63c12d3e925f5eff9dcdc7877e175d0fb" From eb1c0ff1e60fb88d2a4e9f36e6e5e3ad89235a7a Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Mon, 9 Mar 2026 23:36:44 +0200 Subject: [PATCH 4/9] feat: simplify example --- packages/testing/kyc_compliance/Move.lock | 35 ++++++++ packages/testing/kyc_compliance/Move.toml | 7 ++ .../kyc_compliance/sources/kyc_registry.move | 80 +++++++++++++++++ .../kyc_compliance/sources/my_coin.move | 22 +++++ .../kyc_compliance/sources/treasury.move | 89 +++++++++++++++++++ 5 files changed, 233 insertions(+) create mode 100644 packages/testing/kyc_compliance/Move.lock create mode 100644 packages/testing/kyc_compliance/Move.toml create mode 100644 packages/testing/kyc_compliance/sources/kyc_registry.move create mode 100644 packages/testing/kyc_compliance/sources/my_coin.move create mode 100644 packages/testing/kyc_compliance/sources/treasury.move diff --git a/packages/testing/kyc_compliance/Move.lock b/packages/testing/kyc_compliance/Move.lock new file mode 100644 index 0000000..8d351c4 --- /dev/null +++ b/packages/testing/kyc_compliance/Move.lock @@ -0,0 +1,35 @@ +# Generated by move; do not edit +# This file should be checked in. + +[move] +version = 4 + +[pinned.testnet.MoveStdlib] +source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } +use_environment = "testnet" +manifest_digest = "C4FE4C91DE74CBF223B2E380AE40F592177D21870DC2D7EB6227D2D694E05363" +deps = {} + +[pinned.testnet.Sui] +source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } +use_environment = "testnet" +manifest_digest = "7AFB66695545775FBFBB2D3078ADFD084244D5002392E837FDE21D9EA1C6D01C" +deps = { MoveStdlib = "MoveStdlib" } + +[pinned.testnet.kyc_example] +source = { root = true } +use_environment = "testnet" +manifest_digest = "F42F13A0483640C91598349E0E0C125899BD5635A850639255F6EC2E598ADAF8" +deps = { pas = "pas", ptb = "ptb", std = "MoveStdlib", sui = "Sui" } + +[pinned.testnet.pas] +source = { local = "../../pas" } +use_environment = "testnet" +manifest_digest = "38AA62656ABE7551C444DA427ADBAA7751CB67250663D39FCDE36E938138EA7D" +deps = { ptb = "ptb", std = "MoveStdlib", sui = "Sui" } + +[pinned.testnet.ptb] +source = { local = "../../ptb" } +use_environment = "testnet" +manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87" +deps = { std = "MoveStdlib", sui = "Sui" } diff --git a/packages/testing/kyc_compliance/Move.toml b/packages/testing/kyc_compliance/Move.toml new file mode 100644 index 0000000..767cc9c --- /dev/null +++ b/packages/testing/kyc_compliance/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "kyc_example" +edition = "2024.beta" + +[dependencies] +pas = { local = "../../pas" } +ptb = { local = "../../ptb" } diff --git a/packages/testing/kyc_compliance/sources/kyc_registry.move b/packages/testing/kyc_compliance/sources/kyc_registry.move new file mode 100644 index 0000000..98283dd --- /dev/null +++ b/packages/testing/kyc_compliance/sources/kyc_registry.move @@ -0,0 +1,80 @@ +/// Example: KYC compliance with PAS. +/// +/// Demonstrates a KYC registry where users must pass verification +/// before they can receive tokens. +module kyc_example::kyc_registry; + +use kyc_example::my_coin::MY_COIN; +use pas::clawback_funds::ClawbackFunds; +use pas::request::Request; +use pas::send_funds::SendFunds; +use sui::balance::Balance; +use sui::vec_set::{Self, VecSet}; + +// ==== Error Codes ==== + +#[error] +const ENotKYCd: vector = b"Address has not passed KYC"; + +// ==== Structs ==== + +/// Witness stamp for approved transfers. +public struct TransferApproval() has drop; + +/// Witness stamp for approved clawbacks (burn). +public struct ClawbackApproval() has drop; + +/// On-chain KYC registry. +public struct KYCRegistry has key { + id: UID, + users: VecSet
, +} + +/// Admin capability for managing the registry. +public struct RegistryCap has key, store { id: UID } + +fun init(ctx: &mut TxContext) { + transfer::share_object(KYCRegistry { + id: object::new(ctx), + users: vec_set::empty(), + }); + transfer::transfer(RegistryCap { id: object::new(ctx) }, ctx.sender()); +} + +// ==== Public ==== + +/// Validates the recipient has passed KYC, then stamps the request. +public fun approve_transfer( + registry: &KYCRegistry, + request: &mut Request>>, +) { + assert!(registry.users.contains(&request.data().recipient()), ENotKYCd); + request.approve(TransferApproval()); +} + +/// Add a user to the KYC registry. +public fun add_user(registry: &mut KYCRegistry, _cap: &RegistryCap, user: address) { + registry.users.insert(user); +} + +/// Remove a user from the KYC registry. +public fun remove_user(registry: &mut KYCRegistry, _cap: &RegistryCap, user: address) { + registry.users.remove(&user); +} + +// ==== Package ==== + +/// Stamps the clawback request (no KYC check — issuer can always claw back). +public(package) fun approve_clawback(request: &mut Request>>) { + request.approve(ClawbackApproval()); +} + +/// Asserts user has passed KYC. +public(package) fun validate_mint(registry: &KYCRegistry, user: address) { + assert!(registry.users.contains(&user), ENotKYCd); +} + +/// Permit for TransferApproval (only this module can create it). +public(package) fun transfer_approval_permit(): internal::Permit { + internal::permit() +} diff --git a/packages/testing/kyc_compliance/sources/my_coin.move b/packages/testing/kyc_compliance/sources/my_coin.move new file mode 100644 index 0000000..1cdd5f9 --- /dev/null +++ b/packages/testing/kyc_compliance/sources/my_coin.move @@ -0,0 +1,22 @@ +/// MY_COIN currency type definition and creation. +module kyc_example::my_coin; + +use sui::coin_registry; + +public struct MY_COIN has drop {} + +fun init(otw: MY_COIN, ctx: &mut TxContext) { + let (initializer, cap) = coin_registry::new_currency_with_otw( + otw, + 6, + b"MYC".to_string(), + b"My Coin".to_string(), + b"Example regulated coin with KYC compliance".to_string(), + b"https://example.com".to_string(), + ctx, + ); + let metadata = initializer.finalize(ctx); + + transfer::public_transfer(cap, ctx.sender()); + transfer::public_transfer(metadata, ctx.sender()); +} diff --git a/packages/testing/kyc_compliance/sources/treasury.move b/packages/testing/kyc_compliance/sources/treasury.move new file mode 100644 index 0000000..90cac25 --- /dev/null +++ b/packages/testing/kyc_compliance/sources/treasury.move @@ -0,0 +1,89 @@ +/// Treasury operations for MY_COIN. +/// +/// Handles minting (deposit into Chest) and burning (clawback from Chest), +/// enforcing KYC compliance rules on all operations. +module kyc_example::treasury; + +use kyc_example::kyc_registry::{ + Self, + KYCRegistry, + TransferApproval, + ClawbackApproval, + approve_clawback +}; +use kyc_example::my_coin::MY_COIN; +use pas::chest::Chest; +use pas::clawback_funds::{Self, ClawbackFunds}; +use pas::namespace::Namespace; +use pas::policy::{Self, Policy}; +use pas::request::Request; +use pas::templates::Templates; +use ptb::ptb; +use std::type_name; +use sui::balance::Balance; +use sui::coin::TreasuryCap; + +// ==== Setup ==== + +/// One-time setup: PAS policy + compliance template. +/// Call after publishing (TreasuryCap is created in `my_token::init`). +#[allow(lint(self_transfer))] +public fun setup( + namespace: &mut Namespace, + templates: &mut Templates, + registry: &KYCRegistry, + treasury_cap: &mut TreasuryCap, + ctx: &mut TxContext, +) { + // 1. Create policy with clawback enabled + let (mut policy, policy_cap) = policy::new_for_currency( + namespace, + treasury_cap, + true, // clawback allowed (for burn) + ); + + // 2. Set required approvals per action + policy.set_required_approval<_, TransferApproval>(&policy_cap, "send_funds"); + policy.set_required_approval<_, ClawbackApproval>(&policy_cap, "clawback_funds"); + + // 3. Register template so the SDK can auto-construct approve_transfer calls + let type_name = type_name::with_defining_ids(); + + let cmd = ptb::move_call( + type_name.address_string().to_string(), + "kyc_registry", + "approve_transfer", + vector[ptb::object_by_id(object::id(registry)), ptb::ext_input("pas:request")], + vector[], + ); + + templates.set_template_command(kyc_registry::transfer_approval_permit(), cmd); + + policy.share(); + transfer::public_transfer(policy_cap, ctx.sender()); +} + +// ==== Mint & Burn ==== + +/// Mint tokens and deposit into a user's Chest. +public fun mint( + registry: &KYCRegistry, + to_chest: &Chest, + cap: &mut TreasuryCap, + amount: u64, +) { + registry.validate_mint(to_chest.owner()); + to_chest.deposit_balance(cap.mint_balance(amount)); +} + +/// Burn tokens from a user's Chest via clawback. +public fun burn( + policy: &Policy>, + cap: &mut TreasuryCap, + mut request: Request>>, + ctx: &mut TxContext, +) { + approve_clawback(&mut request); + let balance = clawback_funds::resolve(request, policy); + cap.burn(balance.into_coin(ctx)); +} From f54f8f8d3b1d6ac47600d380ed1c6762a6dcd213 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Mon, 9 Mar 2026 23:39:41 +0200 Subject: [PATCH 5/9] chore: remove acme example --- packages/testing/acme_compliance/Move.lock | 35 --- packages/testing/acme_compliance/Move.toml | 7 - .../sources/acme_compliance.move | 202 ------------------ .../acme_compliance/sources/acme_token.move | 22 -- .../sources/acme_treasury.move | 96 --------- .../kyc_compliance/sources/treasury.move | 2 +- 6 files changed, 1 insertion(+), 363 deletions(-) delete mode 100644 packages/testing/acme_compliance/Move.lock delete mode 100644 packages/testing/acme_compliance/Move.toml delete mode 100644 packages/testing/acme_compliance/sources/acme_compliance.move delete mode 100644 packages/testing/acme_compliance/sources/acme_token.move delete mode 100644 packages/testing/acme_compliance/sources/acme_treasury.move diff --git a/packages/testing/acme_compliance/Move.lock b/packages/testing/acme_compliance/Move.lock deleted file mode 100644 index ce7cda3..0000000 --- a/packages/testing/acme_compliance/Move.lock +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by move; do not edit -# This file should be checked in. - -[move] -version = 4 - -[pinned.testnet.MoveStdlib] -source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } -use_environment = "testnet" -manifest_digest = "C4FE4C91DE74CBF223B2E380AE40F592177D21870DC2D7EB6227D2D694E05363" -deps = {} - -[pinned.testnet.Sui] -source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "655576caa3d7faaed39ebbc15d1bcc91d0761aee" } -use_environment = "testnet" -manifest_digest = "7AFB66695545775FBFBB2D3078ADFD084244D5002392E837FDE21D9EA1C6D01C" -deps = { MoveStdlib = "MoveStdlib" } - -[pinned.testnet.acme_compliance] -source = { root = true } -use_environment = "testnet" -manifest_digest = "F42F13A0483640C91598349E0E0C125899BD5635A850639255F6EC2E598ADAF8" -deps = { pas = "pas", ptb = "ptb", std = "MoveStdlib", sui = "Sui" } - -[pinned.testnet.pas] -source = { local = "../../pas" } -use_environment = "testnet" -manifest_digest = "38AA62656ABE7551C444DA427ADBAA7751CB67250663D39FCDE36E938138EA7D" -deps = { ptb = "ptb", std = "MoveStdlib", sui = "Sui" } - -[pinned.testnet.ptb] -source = { local = "../../ptb" } -use_environment = "testnet" -manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87" -deps = { std = "MoveStdlib", sui = "Sui" } diff --git a/packages/testing/acme_compliance/Move.toml b/packages/testing/acme_compliance/Move.toml deleted file mode 100644 index 7e6e63b..0000000 --- a/packages/testing/acme_compliance/Move.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "acme_compliance" -edition = "2024.beta" - -[dependencies] -pas = { local = "../../pas" } -ptb = { local = "../../ptb" } diff --git a/packages/testing/acme_compliance/sources/acme_compliance.move b/packages/testing/acme_compliance/sources/acme_compliance.move deleted file mode 100644 index 142a637..0000000 --- a/packages/testing/acme_compliance/sources/acme_compliance.move +++ /dev/null @@ -1,202 +0,0 @@ -/// Example: Securities compliance with PAS. -/// -/// Demonstrates two common compliance rules for tokenized securities: -/// 1. Accredited investor checks (both sender and recipient must be accredited) -/// 2. Holding limits (min/max balance per investor) -/// -/// Balance tracking is maintained internally because PAS stores balances inside -/// Chests using Sui's address balances, which the compliance contract cannot -/// read directly during approval. -module acme_compliance::acme_compliance; - -use pas::clawback_funds::ClawbackFunds; -use pas::request::Request; -use pas::send_funds::SendFunds; -use sui::balance::Balance; -use sui::table::Table; -use acme_compliance::acme_token::ACME_TOKEN; - -// ==== Error Codes ==== - -#[error] -const ENotWhitelisted: vector = b"Address is not in the investor registry"; -#[error] -const ENotAccredited: vector = b"Investor is not accredited"; -#[error] -const EBelowMinBalance: vector = b"Balance would fall below minimum holding requirement"; -#[error] -const EAboveMaxBalance: vector = b"Balance would exceed maximum holding limit"; - -// ==== Witness ==== - -/// Witness stamp for approved transfers. -public struct TransferApproval() has drop; - -/// Witness stamp for approved clawbacks (burn). -public struct ClawbackApproval() has drop; - -// ==== Structs ==== - -/// On-chain registry of investor status and balances. -public struct InvestorRegistry has key { - id: UID, - investors: Table, - /// Minimum balance per investor (0 = no minimum) - min_balance: u64, - /// Maximum balance per investor (0 = no maximum) - max_balance: u64, -} - -public struct InvestorProfile has drop, store { - accredited: bool, - balance: u64, -} - -/// Admin capability for managing the registry -public struct RegistryCap has key, store { id: UID } - -// ==== Init ==== - -fun init(ctx: &mut TxContext) { - transfer::share_object(InvestorRegistry { - id: object::new(ctx), - investors: sui::table::new(ctx), - min_balance: 0, - max_balance: 0, - }); - transfer::transfer(RegistryCap { id: object::new(ctx) }, ctx.sender()); -} - -// ==== Approval Functions ==== - -/// Validates accreditation and holding limits for both parties, -/// updates internal balance tracking, then stamps the request. -public fun approve_transfer( - registry: &mut InvestorRegistry, - request: &mut Request>>, -) { - let sender = request.data().sender(); - let recipient = request.data().recipient(); - let amount = request.data().funds().value(); - - assert_eligible(registry, sender); - assert_eligible(registry, recipient); - - // Check sender's remaining balance meets minimum (if non-zero after transfer) - let sender_balance_after = registry.investors.borrow(sender).balance - amount; - if (sender_balance_after > 0 && registry.min_balance > 0) { - assert!(sender_balance_after >= registry.min_balance, EBelowMinBalance); - }; - - // Check recipient's new balance within limits - let recipient_balance_after = registry.investors.borrow(recipient).balance + amount; - assert_within_limits(registry, recipient_balance_after); - - // Update internal balance tracking - registry.investors.borrow_mut(sender).balance = sender_balance_after; - registry.investors.borrow_mut(recipient).balance = recipient_balance_after; - - request.approve(TransferApproval()); -} - -/// Validates accreditation and holding limits for a clawback, -/// updates internal balance tracking, then stamps the request. -public(package) fun approve_clawback( - registry: &mut InvestorRegistry, - request: &mut Request>>, -) { - let investor = request.data().owner(); - let amount = request.data().funds().value(); - - assert_eligible(registry, investor); - - // Allow burning to zero, otherwise check minimum - let new_balance = registry.investors.borrow(investor).balance - amount; - if (new_balance > 0 && registry.min_balance > 0) { - assert!(new_balance >= registry.min_balance, EBelowMinBalance); - }; - - registry.investors.borrow_mut(investor).balance = new_balance; - request.approve(ClawbackApproval()); -} - -/// Validates accreditation and holding limits for minting, -/// updates internal balance tracking. -public(package) fun validate_mint( - registry: &mut InvestorRegistry, - _cap: &RegistryCap, - investor: address, - amount: u64, -) { - assert_eligible(registry, investor); - - let new_balance = registry.investors.borrow(investor).balance + amount; - assert_within_limits(registry, new_balance); - - registry.investors.borrow_mut(investor).balance = new_balance; -} - -// ==== Permits ==== - -/// Permit for TransferApproval (only this module can create it). -public(package) fun transfer_approval_permit(): internal::Permit { - internal::permit() -} - -/// Permit for ClawbackApproval (only this module can create it). -public(package) fun clawback_approval_permit(): internal::Permit { - internal::permit() -} - -// ==== Admin ==== - -/// Register or update an investor's accreditation status. -public fun set_investor( - registry: &mut InvestorRegistry, - _cap: &RegistryCap, - investor: address, - accredited: bool, -) { - if (registry.investors.contains(investor)) { - registry.investors.borrow_mut(investor).accredited = accredited; - } else { - registry - .investors - .add( - investor, - InvestorProfile { - accredited, - balance: 0, - }, - ); - } -} - -/// Configure holding limits. -public fun set_holding_limits( - registry: &mut InvestorRegistry, - _cap: &RegistryCap, - min_balance: u64, - max_balance: u64, -) { - registry.min_balance = min_balance; - registry.max_balance = max_balance; -} - -// ==== Internal ==== - -/// Assert investor is registered and accredited. -fun assert_eligible(registry: &InvestorRegistry, investor: address) { - assert!(registry.investors.contains(investor), ENotWhitelisted); - assert!(registry.investors.borrow(investor).accredited, ENotAccredited); -} - -/// Assert balance is within configured min/max limits. -fun assert_within_limits(registry: &InvestorRegistry, balance: u64) { - if (registry.min_balance > 0) { - assert!(balance >= registry.min_balance, EBelowMinBalance); - }; - if (registry.max_balance > 0) { - assert!(balance <= registry.max_balance, EAboveMaxBalance); - }; -} diff --git a/packages/testing/acme_compliance/sources/acme_token.move b/packages/testing/acme_compliance/sources/acme_token.move deleted file mode 100644 index 33853b7..0000000 --- a/packages/testing/acme_compliance/sources/acme_token.move +++ /dev/null @@ -1,22 +0,0 @@ -/// ACME_TOKEN currency type definition and creation. -module acme_compliance::acme_token; - -use sui::coin_registry; - -public struct ACME_TOKEN has drop {} - -fun init(otw: ACME_TOKEN, ctx: &mut TxContext) { - let (initializer, cap) = coin_registry::new_currency_with_otw( - otw, - 6, - b"ACME".to_string(), - b"Acme Token".to_string(), - b"Acme security token".to_string(), - b"https://acme.example".to_string(), - ctx, - ); - let metadata = initializer.finalize(ctx); - - transfer::public_transfer(cap, ctx.sender()); - transfer::public_transfer(metadata, ctx.sender()); -} diff --git a/packages/testing/acme_compliance/sources/acme_treasury.move b/packages/testing/acme_compliance/sources/acme_treasury.move deleted file mode 100644 index 2425bdf..0000000 --- a/packages/testing/acme_compliance/sources/acme_treasury.move +++ /dev/null @@ -1,96 +0,0 @@ -/// Treasury operations for ACME_TOKEN. -/// -/// Handles minting (deposit into Chest) and burning (clawback from Chest), -/// enforcing the same compliance rules as transfers: accreditation and -/// holding limits. -module acme_compliance::acme_treasury; - -use acme_compliance::acme_compliance::{ - Self, - InvestorRegistry, - RegistryCap, - TransferApproval, - ClawbackApproval -}; -use acme_compliance::acme_token::ACME_TOKEN; -use pas::chest::Chest; -use pas::clawback_funds::{Self, ClawbackFunds}; -use pas::namespace::Namespace; -use pas::policy::{Self, Policy}; -use pas::request::Request; -use pas::templates::Templates; -use ptb::ptb; -use std::type_name; -use sui::balance::Balance; -use sui::coin::TreasuryCap; - -// ==== Setup ==== - -/// One-time setup: PAS policy + compliance template + holding limits. -/// Call after publishing (TreasuryCap is created in `acme_token::init`). -#[allow(lint(self_transfer), unused_mut_parameter)] -entry fun setup( - namespace: &mut Namespace, - templates: &mut Templates, - registry: &mut InvestorRegistry, - treasury_cap: &mut TreasuryCap, - registry_cap: &RegistryCap, - ctx: &mut TxContext, -) { - // 1. Create policy with clawback enabled - let (mut policy, policy_cap) = policy::new_for_currency( - namespace, - treasury_cap, - true, // clawback allowed (for burn) - ); - - // 2. Set required approvals per action - policy.set_required_approval<_, TransferApproval>(&policy_cap, "send_funds"); - policy.set_required_approval<_, ClawbackApproval>(&policy_cap, "clawback_funds"); - - // 3. Register template so the SDK can auto-construct approve_transfer calls - let type_name = type_name::with_defining_ids(); - - let cmd = ptb::move_call( - type_name.address_string().to_string(), - "acme_compliance", - "approve_transfer", - vector[ptb::ext_input("pas:request"), ptb::object_by_type()], - vector[(*type_name.as_string()).to_string()], - ); - - templates.set_template_command(acme_compliance::transfer_approval_permit(), cmd); - - policy.share(); - transfer::public_transfer(policy_cap, ctx.sender()); - - // 4. Configure holding limits: min 100 tokens, max 1M tokens (6 decimals) - registry.set_holding_limits(registry_cap, 100_000_000, 1_000_000_000_000); -} - -// ==== Mint & Burn ==== - -/// Mint tokens and deposit into an investor's Chest. -entry fun mint( - registry: &mut InvestorRegistry, - to_chest: &Chest, - cap: &mut TreasuryCap, - registry_cap: &RegistryCap, - amount: u64, -) { - registry.validate_mint(registry_cap, to_chest.owner(), amount); - to_chest.deposit_balance(cap.mint_balance(amount)); -} - -/// Burn tokens from an investor's Chest via clawback. -entry fun burn( - registry: &mut InvestorRegistry, - policy: &Policy>, - cap: &mut TreasuryCap, - mut request: Request>>, - ctx: &mut TxContext, -) { - registry.approve_clawback(&mut request); - let balance = clawback_funds::resolve(request, policy); - cap.burn(balance.into_coin(ctx)); -} diff --git a/packages/testing/kyc_compliance/sources/treasury.move b/packages/testing/kyc_compliance/sources/treasury.move index 90cac25..f4b4a3f 100644 --- a/packages/testing/kyc_compliance/sources/treasury.move +++ b/packages/testing/kyc_compliance/sources/treasury.move @@ -26,7 +26,7 @@ use sui::coin::TreasuryCap; // ==== Setup ==== /// One-time setup: PAS policy + compliance template. -/// Call after publishing (TreasuryCap is created in `my_token::init`). +/// Call after publishing (TreasuryCap is created in `my_coin::init`). #[allow(lint(self_transfer))] public fun setup( namespace: &mut Namespace, From 4b1049c71f2efefc9911de9ee57b0def03b4cd96 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Wed, 11 Mar 2026 18:21:11 +0200 Subject: [PATCH 6/9] chore: change chest to account --- .../kyc_compliance/sources/treasury.move | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/testing/kyc_compliance/sources/treasury.move b/packages/testing/kyc_compliance/sources/treasury.move index f4b4a3f..5c95540 100644 --- a/packages/testing/kyc_compliance/sources/treasury.move +++ b/packages/testing/kyc_compliance/sources/treasury.move @@ -1,6 +1,6 @@ /// Treasury operations for MY_COIN. /// -/// Handles minting (deposit into Chest) and burning (clawback from Chest), +/// Handles minting (deposit into Account) and burning (clawback from Account), /// enforcing KYC compliance rules on all operations. module kyc_example::treasury; @@ -12,12 +12,12 @@ use kyc_example::kyc_registry::{ approve_clawback }; use kyc_example::my_coin::MY_COIN; -use pas::chest::Chest; +use pas::account::Account; use pas::clawback_funds::{Self, ClawbackFunds}; use pas::namespace::Namespace; use pas::policy::{Self, Policy}; use pas::request::Request; -use pas::templates::Templates; +use pas::templates::{PAS, Templates}; use ptb::ptb; use std::type_name; use sui::balance::Balance; @@ -53,7 +53,7 @@ public fun setup( type_name.address_string().to_string(), "kyc_registry", "approve_transfer", - vector[ptb::object_by_id(object::id(registry)), ptb::ext_input("pas:request")], + vector[ptb::object_by_id(object::id(registry)), ptb::ext_input("request")], vector[], ); @@ -65,18 +65,18 @@ public fun setup( // ==== Mint & Burn ==== -/// Mint tokens and deposit into a user's Chest. +/// Mint tokens and deposit into a user's Account. public fun mint( registry: &KYCRegistry, - to_chest: &Chest, + to_account: &Account, cap: &mut TreasuryCap, amount: u64, ) { - registry.validate_mint(to_chest.owner()); - to_chest.deposit_balance(cap.mint_balance(amount)); + registry.validate_mint(to_account.owner()); + to_account.deposit_balance(cap.mint_balance(amount)); } -/// Burn tokens from a user's Chest via clawback. +/// Burn tokens from a user's Account via clawback. public fun burn( policy: &Policy>, cap: &mut TreasuryCap, From 6638c90375185cbc7b4f2803bab2c948f2b3acd6 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Fri, 13 Mar 2026 12:15:16 +0200 Subject: [PATCH 7/9] chore: function explicitly namespaced --- .../testing/kyc_compliance/sources/kyc_registry.move | 2 +- packages/testing/kyc_compliance/sources/treasury.move | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/testing/kyc_compliance/sources/kyc_registry.move b/packages/testing/kyc_compliance/sources/kyc_registry.move index 98283dd..4a2212d 100644 --- a/packages/testing/kyc_compliance/sources/kyc_registry.move +++ b/packages/testing/kyc_compliance/sources/kyc_registry.move @@ -13,7 +13,7 @@ use sui::vec_set::{Self, VecSet}; // ==== Error Codes ==== -#[error] +#[error(code = 0)] const ENotKYCd: vector = b"Address has not passed KYC"; // ==== Structs ==== diff --git a/packages/testing/kyc_compliance/sources/treasury.move b/packages/testing/kyc_compliance/sources/treasury.move index 5c95540..d2f1116 100644 --- a/packages/testing/kyc_compliance/sources/treasury.move +++ b/packages/testing/kyc_compliance/sources/treasury.move @@ -4,13 +4,7 @@ /// enforcing KYC compliance rules on all operations. module kyc_example::treasury; -use kyc_example::kyc_registry::{ - Self, - KYCRegistry, - TransferApproval, - ClawbackApproval, - approve_clawback -}; +use kyc_example::kyc_registry::{Self, KYCRegistry, TransferApproval, ClawbackApproval}; use kyc_example::my_coin::MY_COIN; use pas::account::Account; use pas::clawback_funds::{Self, ClawbackFunds}; @@ -83,7 +77,7 @@ public fun burn( mut request: Request>>, ctx: &mut TxContext, ) { - approve_clawback(&mut request); + kyc_registry::approve_clawback(&mut request); let balance = clawback_funds::resolve(request, policy); cap.burn(balance.into_coin(ctx)); } From 5788dc00743a8a05b7fc5e0417cd7a46d5310fad Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Fri, 13 Mar 2026 14:22:20 +0200 Subject: [PATCH 8/9] chore: change directory --- .../testing/kyc_compliance => examples/kyc}/Move.lock | 6 +++--- examples/kyc/Move.toml | 7 +++++++ .../kyc}/sources/kyc_registry.move | 0 .../kyc_compliance => examples/kyc}/sources/my_coin.move | 0 .../kyc_compliance => examples/kyc}/sources/treasury.move | 0 packages/testing/kyc_compliance/Move.toml | 7 ------- 6 files changed, 10 insertions(+), 10 deletions(-) rename {packages/testing/kyc_compliance => examples/kyc}/Move.lock (88%) create mode 100644 examples/kyc/Move.toml rename {packages/testing/kyc_compliance => examples/kyc}/sources/kyc_registry.move (100%) rename {packages/testing/kyc_compliance => examples/kyc}/sources/my_coin.move (100%) rename {packages/testing/kyc_compliance => examples/kyc}/sources/treasury.move (100%) delete mode 100644 packages/testing/kyc_compliance/Move.toml diff --git a/packages/testing/kyc_compliance/Move.lock b/examples/kyc/Move.lock similarity index 88% rename from packages/testing/kyc_compliance/Move.lock rename to examples/kyc/Move.lock index 8d351c4..c849840 100644 --- a/packages/testing/kyc_compliance/Move.lock +++ b/examples/kyc/Move.lock @@ -19,17 +19,17 @@ deps = { MoveStdlib = "MoveStdlib" } [pinned.testnet.kyc_example] source = { root = true } use_environment = "testnet" -manifest_digest = "F42F13A0483640C91598349E0E0C125899BD5635A850639255F6EC2E598ADAF8" +manifest_digest = "47EF3010014F759987D309DDFB106E1364EADE827E1E825AE4AD8BF7098CD83F" deps = { pas = "pas", ptb = "ptb", std = "MoveStdlib", sui = "Sui" } [pinned.testnet.pas] -source = { local = "../../pas" } +source = { local = "../../packages/pas" } use_environment = "testnet" manifest_digest = "38AA62656ABE7551C444DA427ADBAA7751CB67250663D39FCDE36E938138EA7D" deps = { ptb = "ptb", std = "MoveStdlib", sui = "Sui" } [pinned.testnet.ptb] -source = { local = "../../ptb" } +source = { local = "../../packages/ptb" } use_environment = "testnet" manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87" deps = { std = "MoveStdlib", sui = "Sui" } diff --git a/examples/kyc/Move.toml b/examples/kyc/Move.toml new file mode 100644 index 0000000..bd1b2c4 --- /dev/null +++ b/examples/kyc/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "kyc_example" +edition = "2024.beta" + +[dependencies] +pas = { local = "../../packages/pas" } +ptb = { local = "../../packages/ptb" } diff --git a/packages/testing/kyc_compliance/sources/kyc_registry.move b/examples/kyc/sources/kyc_registry.move similarity index 100% rename from packages/testing/kyc_compliance/sources/kyc_registry.move rename to examples/kyc/sources/kyc_registry.move diff --git a/packages/testing/kyc_compliance/sources/my_coin.move b/examples/kyc/sources/my_coin.move similarity index 100% rename from packages/testing/kyc_compliance/sources/my_coin.move rename to examples/kyc/sources/my_coin.move diff --git a/packages/testing/kyc_compliance/sources/treasury.move b/examples/kyc/sources/treasury.move similarity index 100% rename from packages/testing/kyc_compliance/sources/treasury.move rename to examples/kyc/sources/treasury.move diff --git a/packages/testing/kyc_compliance/Move.toml b/packages/testing/kyc_compliance/Move.toml deleted file mode 100644 index 767cc9c..0000000 --- a/packages/testing/kyc_compliance/Move.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "kyc_example" -edition = "2024.beta" - -[dependencies] -pas = { local = "../../pas" } -ptb = { local = "../../ptb" } From fb78ffef846fb6b4f15442fa429295bd784fdf99 Mon Sep 17 00:00:00 2001 From: Haris Katimertzis Date: Fri, 13 Mar 2026 14:29:16 +0200 Subject: [PATCH 9/9] chore: change directory --- examples/kyc/Move.toml | 7 ------- {examples => packages/examples}/kyc/Move.lock | 8 ++++---- packages/examples/kyc/Move.toml | 7 +++++++ .../examples}/kyc/sources/kyc_registry.move | 4 ++-- {examples => packages/examples}/kyc/sources/my_coin.move | 2 +- {examples => packages/examples}/kyc/sources/treasury.move | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 examples/kyc/Move.toml rename {examples => packages/examples}/kyc/Move.lock (86%) create mode 100644 packages/examples/kyc/Move.toml rename {examples => packages/examples}/kyc/sources/kyc_registry.move (97%) rename {examples => packages/examples}/kyc/sources/my_coin.move (95%) rename {examples => packages/examples}/kyc/sources/treasury.move (94%) diff --git a/examples/kyc/Move.toml b/examples/kyc/Move.toml deleted file mode 100644 index bd1b2c4..0000000 --- a/examples/kyc/Move.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "kyc_example" -edition = "2024.beta" - -[dependencies] -pas = { local = "../../packages/pas" } -ptb = { local = "../../packages/ptb" } diff --git a/examples/kyc/Move.lock b/packages/examples/kyc/Move.lock similarity index 86% rename from examples/kyc/Move.lock rename to packages/examples/kyc/Move.lock index c849840..1f93656 100644 --- a/examples/kyc/Move.lock +++ b/packages/examples/kyc/Move.lock @@ -16,20 +16,20 @@ use_environment = "testnet" manifest_digest = "7AFB66695545775FBFBB2D3078ADFD084244D5002392E837FDE21D9EA1C6D01C" deps = { MoveStdlib = "MoveStdlib" } -[pinned.testnet.kyc_example] +[pinned.testnet.kyc] source = { root = true } use_environment = "testnet" -manifest_digest = "47EF3010014F759987D309DDFB106E1364EADE827E1E825AE4AD8BF7098CD83F" +manifest_digest = "F42F13A0483640C91598349E0E0C125899BD5635A850639255F6EC2E598ADAF8" deps = { pas = "pas", ptb = "ptb", std = "MoveStdlib", sui = "Sui" } [pinned.testnet.pas] -source = { local = "../../packages/pas" } +source = { local = "../../pas" } use_environment = "testnet" manifest_digest = "38AA62656ABE7551C444DA427ADBAA7751CB67250663D39FCDE36E938138EA7D" deps = { ptb = "ptb", std = "MoveStdlib", sui = "Sui" } [pinned.testnet.ptb] -source = { local = "../../packages/ptb" } +source = { local = "../../ptb" } use_environment = "testnet" manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87" deps = { std = "MoveStdlib", sui = "Sui" } diff --git a/packages/examples/kyc/Move.toml b/packages/examples/kyc/Move.toml new file mode 100644 index 0000000..2e65f1d --- /dev/null +++ b/packages/examples/kyc/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "kyc" +edition = "2024.beta" + +[dependencies] +pas = { local = "../../pas" } +ptb = { local = "../../ptb" } diff --git a/examples/kyc/sources/kyc_registry.move b/packages/examples/kyc/sources/kyc_registry.move similarity index 97% rename from examples/kyc/sources/kyc_registry.move rename to packages/examples/kyc/sources/kyc_registry.move index 4a2212d..e9eb9e6 100644 --- a/examples/kyc/sources/kyc_registry.move +++ b/packages/examples/kyc/sources/kyc_registry.move @@ -2,9 +2,9 @@ /// /// Demonstrates a KYC registry where users must pass verification /// before they can receive tokens. -module kyc_example::kyc_registry; +module kyc::kyc_registry; -use kyc_example::my_coin::MY_COIN; +use kyc::my_coin::MY_COIN; use pas::clawback_funds::ClawbackFunds; use pas::request::Request; use pas::send_funds::SendFunds; diff --git a/examples/kyc/sources/my_coin.move b/packages/examples/kyc/sources/my_coin.move similarity index 95% rename from examples/kyc/sources/my_coin.move rename to packages/examples/kyc/sources/my_coin.move index 1cdd5f9..c135a72 100644 --- a/examples/kyc/sources/my_coin.move +++ b/packages/examples/kyc/sources/my_coin.move @@ -1,5 +1,5 @@ /// MY_COIN currency type definition and creation. -module kyc_example::my_coin; +module kyc::my_coin; use sui::coin_registry; diff --git a/examples/kyc/sources/treasury.move b/packages/examples/kyc/sources/treasury.move similarity index 94% rename from examples/kyc/sources/treasury.move rename to packages/examples/kyc/sources/treasury.move index d2f1116..a98c03c 100644 --- a/examples/kyc/sources/treasury.move +++ b/packages/examples/kyc/sources/treasury.move @@ -2,10 +2,10 @@ /// /// Handles minting (deposit into Account) and burning (clawback from Account), /// enforcing KYC compliance rules on all operations. -module kyc_example::treasury; +module kyc::treasury; -use kyc_example::kyc_registry::{Self, KYCRegistry, TransferApproval, ClawbackApproval}; -use kyc_example::my_coin::MY_COIN; +use kyc::kyc_registry::{Self, KYCRegistry, TransferApproval, ClawbackApproval}; +use kyc::my_coin::MY_COIN; use pas::account::Account; use pas::clawback_funds::{Self, ClawbackFunds}; use pas::namespace::Namespace;