diff --git a/contrib/sbtc/token-key-admin/contracts/sbtc-token-key-admin.clar b/contrib/sbtc/token-key-admin/contracts/sbtc-token-key-admin.clar index 6d8ab228b12..112afad5891 100644 --- a/contrib/sbtc/token-key-admin/contracts/sbtc-token-key-admin.clar +++ b/contrib/sbtc/token-key-admin/contracts/sbtc-token-key-admin.clar @@ -21,29 +21,29 @@ ;; data vars ;; -(define-data-var coordinator (optional principal) none) +(define-data-var coordinator (optional {addr: principal, key: (buff 33)}) none) ;; data maps ;; -(define-map signers uint principal) +(define-map signers uint {addr: principal, key: (buff 33)}) ;; public functions ;; -(define-public (set-coordinator-key (key principal)) +(define-public (set-coordinator-data (data {addr: principal, key: (buff 33)})) (if (is-valid-caller) - (ok (var-set coordinator (some key))) + (ok (var-set coordinator (some data))) err-invalid-caller ) ) -(define-public (set-signer-key (id uint) (key principal)) +(define-public (set-signer-data (id uint) (data {addr: principal, key: (buff 33)})) (if (is-valid-caller) - (ok (map-set signers id key)) + (ok (map-set signers id data)) err-invalid-caller ) ) -(define-public (delete-signer-key (id uint)) +(define-public (delete-signer-data (id uint)) (if (is-valid-caller) (ok (map-delete signers id)) err-invalid-caller @@ -57,6 +57,13 @@ ) ) +(define-public (burn! (amount uint)) + (if (is-valid-caller) + (token-debit! tx-sender amount) + err-invalid-caller + ) +) + (define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34)))) (begin (asserts! (is-eq tx-sender sender) err-not-token-owner) @@ -68,11 +75,11 @@ ;; read only functions ;; -(define-read-only (get-coordinator-key) +(define-read-only (get-coordinator-data) (var-get coordinator) ) -(define-read-only (get-signer-key (signer uint)) +(define-read-only (get-signer-data (signer uint)) (map-get? signers signer) ) @@ -113,3 +120,7 @@ (define-private (token-credit! (account principal) (amount uint)) (ft-mint? sbtc amount account) ) + +(define-private (token-debit! (account principal) (amount uint)) + (ft-burn? sbtc amount account) +) diff --git a/contrib/sbtc/token-key-admin/tests/sbtc-token-key-admin_test.ts b/contrib/sbtc/token-key-admin/tests/sbtc-token-key-admin_test.ts index 5fb480c9e64..755486dfa1a 100644 --- a/contrib/sbtc/token-key-admin/tests/sbtc-token-key-admin_test.ts +++ b/contrib/sbtc/token-key-admin/tests/sbtc-token-key-admin_test.ts @@ -7,11 +7,9 @@ Clarinet.test({ async fn(chain: Chain, accounts: Map) { let deployer = accounts.get("deployer")!; - let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-coordinator-key", [], deployer.address); + let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-coordinator-data", [], deployer.address); coordinator.result.expectNone(); - - //assertEquals(block.height, 3); }, }); @@ -21,19 +19,16 @@ Clarinet.test({ let deployer = accounts.get("deployer")!; let block = chain.mineBlock([ - // Generate a contract call to count-up from the deployer address. - Tx.contractCall("sbtc-token-key-admin", "set-coordinator-key", [types.principal(deployer.address)], deployer.address), + Tx.contractCall("sbtc-token-key-admin", "set-coordinator-data", [types.tuple({addr: types.principal(deployer.address), key: types.buff(0x000000000000000000000000000000000000000000000000000000000000000000)})], deployer.address), ]); - // Get the first (and only) transaction receipt. let [receipt] = block.receipts; - // Assert that the returned result is a boolean true. receipt.result.expectOk().expectBool(true); - let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-coordinator-key", [], deployer.address); + let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-coordinator-data", [], deployer.address); - coordinator.result.expectSome(deployer.address); + coordinator.result.expectSome({addr: deployer.address, key: 0x000000000000000000000000000000000000000000000000000000000000000000}); }, }); @@ -43,17 +38,14 @@ Clarinet.test({ let deployer = accounts.get("deployer")!; let block = chain.mineBlock([ - // Generate a contract call to count-up from the deployer address. - Tx.contractCall("sbtc-token-key-admin", "set-signer-key", [types.uint(1), types.principal(deployer.address)], deployer.address), + Tx.contractCall("sbtc-token-key-admin", "set-signer-data", [types.uint(1), types.tuple({addr: types.principal(deployer.address), key: types.buff(0x000000000000000000000000000000000000000000000000000000000000000000)})], deployer.address), ]); - // Get the first (and only) transaction receipt. let [receipt] = block.receipts; - // Assert that the returned result is a boolean true. - receipt.result.expectOk().expectBool(true); + receipt.result.expectOk(); - let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-key", [types.uint(1)], deployer.address); + let coordinator = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-data", [types.uint(1)], deployer.address); coordinator.result.expectSome(deployer.address); }, @@ -65,32 +57,26 @@ Clarinet.test({ let deployer = accounts.get("deployer")!; let block_set = chain.mineBlock([ - // Generate a contract call to count-up from the deployer address. - Tx.contractCall("sbtc-token-key-admin", "set-signer-key", [types.uint(1), types.principal(deployer.address)], deployer.address), + Tx.contractCall("sbtc-token-key-admin", "set-signer-data", [types.uint(1), types.tuple({addr: types.principal(deployer.address), key: types.buff(0x000000000000000000000000000000000000000000000000000000000000000000)})], deployer.address), ]); - // Get the first (and only) transaction receipt. let [receipt_set] = block_set.receipts; - // Assert that the returned result is a boolean true. - receipt_set.result.expectOk().expectBool(true); + receipt_set.result.expectOk(); - let coordinator_set = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-key", [types.uint(1)], deployer.address); + let coordinator_set = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-data", [types.uint(1)], deployer.address); coordinator_set.result.expectSome(deployer.address); let block_delete = chain.mineBlock([ - // Generate a contract call to count-up from the deployer address. - Tx.contractCall("sbtc-token-key-admin", "delete-signer-key", [types.uint(1)], deployer.address), + Tx.contractCall("sbtc-token-key-admin", "delete-signer-data", [types.uint(1)], deployer.address), ]); - // Get the first (and only) transaction receipt. let [receipt_delete] = block_delete.receipts; - // Assert that the returned result is a boolean true. - receipt_delete.result.expectOk().expectBool(true); + receipt_delete.result.expectOk(); - let coordinator_delete = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-key", [types.uint(1)], deployer.address); + let coordinator_delete = chain.callReadOnlyFn("sbtc-token-key-admin", "get-signer-data", [types.uint(1)], deployer.address); coordinator_delete.result.expectNone(); }, @@ -106,14 +92,11 @@ Clarinet.test({ balance.result.expectOk().expectUint(0); let block = chain.mineBlock([ - // Generate a contract call to count-up from the deployer address. Tx.contractCall("sbtc-token-key-admin", "mint!", [types.uint(1234)], deployer.address), ]); - // Get the first (and only) transaction receipt. let [receipt] = block.receipts; - // Assert that the returned result is a boolean true. receipt.result.expectOk().expectBool(true); balance = chain.callReadOnlyFn("sbtc-token-key-admin", "get-balance", [types.principal(deployer.address)], deployer.address); @@ -121,3 +104,38 @@ Clarinet.test({ balance.result.expectOk().expectUint(1234); }, }); + +Clarinet.test({ + name: "Ensure we can burn tokens", + async fn(chain: Chain, accounts: Map) { + let deployer = accounts.get("deployer")!; + + let balance = chain.callReadOnlyFn("sbtc-token-key-admin", "get-balance", [types.principal(deployer.address)], deployer.address); + + balance.result.expectOk().expectUint(0); + + let block = chain.mineBlock([ + Tx.contractCall("sbtc-token-key-admin", "mint!", [types.uint(1234)], deployer.address), + ]); + + let [receipt] = block.receipts; + + receipt.result.expectOk().expectBool(true); + + balance = chain.callReadOnlyFn("sbtc-token-key-admin", "get-balance", [types.principal(deployer.address)], deployer.address); + + balance.result.expectOk().expectUint(1234); + + block = chain.mineBlock([ + Tx.contractCall("sbtc-token-key-admin", "burn!", [types.uint(4)], deployer.address), + ]); + + [receipt] = block.receipts; + + receipt.result.expectOk().expectBool(true); + + balance = chain.callReadOnlyFn("sbtc-token-key-admin", "get-balance", [types.principal(deployer.address)], deployer.address); + + balance.result.expectOk().expectUint(1230); + }, +});