diff --git a/contracts/Clarinet.toml b/contracts/Clarinet.toml index 160217d..288109b 100644 --- a/contracts/Clarinet.toml +++ b/contracts/Clarinet.toml @@ -110,6 +110,11 @@ path = 'contracts/l1/bridge-v1.clar' clarity_version = 2 epoch = 2.1 +[contracts.community-handles-v2] +path = 'contracts/external/community-handles-v2.clar' +clarity_version = 2 +epoch = 2.1 + [repl.analysis] passes = ['check_checker'] diff --git a/contracts/contracts/external/community-handles-v2.clar b/contracts/contracts/external/community-handles-v2.clar new file mode 100644 index 0000000..559e413 --- /dev/null +++ b/contracts/contracts/external/community-handles-v2.clar @@ -0,0 +1,134 @@ +;; @contract Community Handles +;; @version 2 + +(define-constant err-not-authorized (err u403)) +(define-constant internal-price-high u999999999999999999999999999999) +(define-constant name-salt 0x00) +(define-fungible-token danger-zone-token) + +(define-map namespace-controller (buff 20) principal) + +;; variables for iteration functions +(define-data-var ctx-bulk-registration-namespace (buff 20) 0x00) + +;; @desc preorder the namespace on-chain +;; @param hashed-salted-namespace; ripdem160 hash of namespace concat with salt +;; @param stx-to-burn; namespace price in ustx +(define-public (namespace-preorder (hashed-salted-namespace (buff 20)) (stx-to-burn uint)) + (contract-call? 'SP000000000000000000002Q6VF78.bns + namespace-preorder hashed-salted-namespace stx-to-burn)) + +;; @desc reveal the namespace +;; @param namespace; namespace to register +;; @param salt; salt used during preorder +;; @param lifetime; number of blocks until a name expires +;; @param controller; optional principal set as the first namespace controller +;; defaults to contract-caller +(define-public (namespace-reveal (namespace (buff 20)) (salt (buff 20)) (lifetime uint) (controller (optional principal))) + (begin + (map-set namespace-controller namespace (default-to contract-caller controller)) + (try! (contract-call? 'SP000000000000000000002Q6VF78.bns + namespace-reveal + namespace + salt + internal-price-high u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 + lifetime + (as-contract tx-sender))) + (try! (as-contract (contract-call? 'SP000000000000000000002Q6VF78.bns + namespace-ready namespace))) + (ok true))) + +;; @desc register name for 1 ustx by namespace controller only +;; @param namespace; controlled namespace +;; @param name; name in the controlled namespace +;; @param zonefile-hash; hash of the attachment/zonefile for the name +;; @param owner; principal owning the name after registration +(define-public (name-register (namespace (buff 20)) + (name (buff 48)) + (owner principal) + (zonefile-hash (buff 20))) + (let ((hash (hash160 (concat (concat (concat name 0x2e) namespace) name-salt)))) + (try! (is-contract-caller-namespace-controller namespace)) + (try! (to-uint-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-preorder hash u1))) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u1 u1)))) + (try! (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-register namespace name name-salt zonefile-hash))) + (try! (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-transfer namespace name owner (some zonefile-hash)))) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace internal-price-high u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1)))) + (ok true))) + +;; @desc renew a name for 1 ustx by namespace controller only +;; @param namespace; controlled namespace +;; @param name; name in the controlled namespace +;; @param new-owner; optional new owner of name after renewal +;; @param zonefile-hash; optional new zonefile hash after renewal +(define-public (name-renewal (namespace (buff 20)) + (name (buff 48)) + (new-owner (optional principal)) + (zonefile-hash (optional (buff 20)))) + (let ((original-owner tx-sender)) + (try! (is-contract-caller-namespace-controller namespace)) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u1 u1)))) + (try! (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-renewal namespace name u1 new-owner zonefile-hash))) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace internal-price-high u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1)))) + (ok true))) + + +;; iterator for bulk-name-register +(define-private (bulk-name-register-iter (entry {name: (buff 48), owner: principal, zonefile-hash: (buff 20)}) (prev (response bool uint))) + (let ((namespace (var-get ctx-bulk-registration-namespace)) + (name (get name entry)) + (hash (hash160 (concat (concat (concat name 0x2e) namespace) name-salt)))) + (try! prev) + (try! (to-uint-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-preorder hash u1))) + (try! (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-register namespace name name-salt (get zonefile-hash entry)))) + (try! (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns name-transfer namespace name (get owner entry) (some (get zonefile-hash entry))))) + (ok true))) + +;; @desc register multiple namens for 1 ustx by namespace controller only +;; @param namespace; controlled namespace +;; @param names; list of names with owner and hash of the attachment/zonefile for the name +(define-public (bulk-name-register (namespace (buff 20)) (names (list 1000 {name: (buff 48), owner: principal, zonefile-hash: (buff 20)}))) + (begin + (try! (is-contract-caller-namespace-controller namespace)) + (var-set ctx-bulk-registration-namespace namespace) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u1 u1)))) + (try! (fold bulk-name-register-iter names (ok true))) + (var-set ctx-bulk-registration-namespace 0x00) + (try! (as-contract (to-bool-response (contract-call? 'SP000000000000000000002Q6VF78.bns namespace-update-function-price namespace internal-price-high u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1 u1)))) + (ok true))) + +;; convert response to standard uint response with uint error +;; (response uint int) (response uint uint) +(define-private (to-uint-response (value (response uint int))) + (match value + success (ok success) + error (err (to-uint error)))) + +;; convert response to standard bool response with uint error +;; (response bool int) (response bool uint) +(define-private (to-bool-response (value (response bool int))) + (match value + success (ok success) + error (err (to-uint error)))) + +(define-private (is-contract-caller-namespace-controller (namespace (buff 20))) + (ok (asserts! (is-eq (map-get? namespace-controller namespace) (some contract-caller)) err-not-authorized))) + +(define-read-only (get-namespace-controller (namespace (buff 20))) + (map-get? namespace-controller namespace)) + +;; @desc set new namespace controller, by current namespace owner only +;; +;; It is the responsibility of the namespace controller to +;; ensure that the new controller can manage the namespace. +;; Otherwise, it might happen that new names can NOT be registered anymore. +;; +;; @param namespace; controlled namespace by contract caller +;; @param new-controller; new namespace controller +(define-public (set-namespace-controller (namespace (buff 20)) (new-controller principal)) + (begin + (try! (is-contract-caller-namespace-controller namespace)) + (try! (ft-mint? danger-zone-token u1 tx-sender)) + (try! (ft-burn? danger-zone-token u1 tx-sender)) + (map-set namespace-controller namespace new-controller) + (ok true))) \ No newline at end of file diff --git a/contracts/contracts/proposals/proposal-migrator-v2.clar b/contracts/contracts/proposals/proposal-migrator-v2.clar index 45252c2..a1b2377 100644 --- a/contracts/contracts/proposals/proposal-migrator-v2.clar +++ b/contracts/contracts/proposals/proposal-migrator-v2.clar @@ -8,9 +8,6 @@ (try! (contract-call? .bnsx-extensions set-extensions (list { extension: .wrapper-migrator-v2, enabled: true } - ;; { extension: DEPLOYER, enabled: false } - ;; { extension: .test-utils, enabled: false } - ;; { extension: .fake-multisafe, enabled: true } ) )) diff --git a/contracts/deployments/default.mainnet-plan.yaml b/contracts/deployments/default.mainnet-plan.yaml index 3dc598a..eaabd48 100644 --- a/contracts/deployments/default.mainnet-plan.yaml +++ b/contracts/deployments/default.mainnet-plan.yaml @@ -82,4 +82,32 @@ plan: anchor_block_only: false parameters: - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.proposal-bootstrap" + - contract-publish: + contract-name: wrapper-migrator-v2 + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 83190 + path: contracts/testnet/wrapper-migrator-v2.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: proposal-migrator-v2 + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 13970 + path: contracts/proposals/proposal-migrator-v2.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: l1-registry + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 83190 + path: contracts/l1/registry.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: l1-bridge-v1 + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 83190 + path: contracts/l1/bridge-v1.clar + anchor-block-only: true + clarity-version: 2 epoch: "2.0" diff --git a/contracts/deployments/l1-migration.mainnet-plan.yaml b/contracts/deployments/l1-migration.mainnet-plan.yaml new file mode 100644 index 0000000..6184dd0 --- /dev/null +++ b/contracts/deployments/l1-migration.mainnet-plan.yaml @@ -0,0 +1,27 @@ +--- +id: 0 +name: Register helper - mainnet +network: mainnet +stacks-node: "https://stacks-node-api.mainnet.stacks.co" +bitcoin-node: "http://blockstack:blockstacksystem@bitcoin.blockstack.com:8332" +plan: + batches: + - id: 0 + transactions: + - contract-call: + contract-id: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.bnsx-extensions + method: execute + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 100000 + anchor_block_only: false + parameters: + - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.proposal-migrator-v2" + - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60" + - contract-call: + contract-id: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.wrapper-migrator-v2 + method: execute + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 100000 + anchor_block_only: false + parameters: + - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60" \ No newline at end of file diff --git a/contracts/deployments/l1.mainnet-plan.yaml b/contracts/deployments/l1.mainnet-plan.yaml new file mode 100644 index 0000000..e80b10b --- /dev/null +++ b/contracts/deployments/l1.mainnet-plan.yaml @@ -0,0 +1,47 @@ +--- +id: 0 +name: Register helper - mainnet +network: mainnet +stacks-node: "https://stacks-node-api.mainnet.stacks.co" +bitcoin-node: "http://blockstack:blockstacksystem@bitcoin.blockstack.com:8332" +plan: + batches: + - id: 0 + transactions: + - contract-publish: + contract-name: wrapper-migrator-v2 + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 200000 + path: contracts/wrapper-migrator-v2.clar + anchor-block-only: false + clarity-version: 2 + # - contract-publish: + # contract-name: proposal-migrator-v2 + # expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + # cost: 200000 + # path: contracts/proposals/proposal-migrator-v2.clar + # anchor-block-only: true + # clarity-version: 2 + # - contract-publish: + # contract-name: l1-registry + # expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + # cost: 200000 + # path: contracts/l1/registry.clar + # anchor-block-only: true + # clarity-version: 2 + - contract-publish: + contract-name: l1-bridge-v1 + expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + cost: 200000 + path: contracts/l1/bridge-v1.clar + anchor-block-only: false + clarity-version: 2 + # - contract-call: + # contract-id: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.bnsx-extensions + # method: execute + # expected-sender: SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60 + # cost: 100000 + # anchor_block_only: false + # parameters: + # - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.proposal-migrator-v2" + # - "'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60" \ No newline at end of file diff --git a/contracts/scripts/l1-migration.ts b/contracts/scripts/l1-migration.ts new file mode 100644 index 0000000..ff7d1c3 --- /dev/null +++ b/contracts/scripts/l1-migration.ts @@ -0,0 +1,84 @@ +import 'cross-fetch/polyfill'; +import { config } from 'dotenv'; +import { + AnchorMode, + broadcastTransaction, + PostConditionMode, + makeContractCall, +} from 'micro-stacks/transactions'; +import { c32addressDecode } from 'micro-stacks/crypto'; +import { + contracts, + deployer, + getControllerAddress, + getNonce, + network, + networkKey, +} from './script-utils'; +import { bytesToHex, hexToBytes } from 'micro-stacks/common'; + +const migrator = contracts.wrapperMigrator; + +config(); + +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +const privateKey = process.env.DEPLOYER_KEY!; + +const [signer] = process.argv.slice(2); + +async function run() { + console.log('Network:', networkKey); + console.log('Signer:', signer); + console.log('Migrator:', migrator.identifier); + const controller = getControllerAddress(privateKey); + console.log('Controller:', controller); + console.log('Deployer:', deployer); + + const nonce = await getNonce(); + + const proposalTx = await makeContractCall({ + ...contracts.bnsxExtensions.execute(contracts.proposalMigratorV2.identifier, controller), + nonce, + fee: 100000, + network, + senderKey: privateKey, + anchorMode: AnchorMode.Any, + }); + + const migratorTx = await makeContractCall({ + ...contracts.wrapperMigratorV2.setSigners([ + { + signer, + enabled: true, + }, + ]), + nonce: nonce + 1, + fee: 100000, + network, + senderKey: privateKey, + anchorMode: AnchorMode.Any, + }); + + const bridgeTx = await makeContractCall({ + ...contracts.l1BridgeV1.updateSigner(signer), + nonce: nonce + 2, + fee: 100000, + network, + senderKey: privateKey, + anchorMode: AnchorMode.Any, + }); + + if (networkKey !== 'devnet') { + throw 'Safe exit'; + } + + console.log(await broadcastTransaction(proposalTx, network)); + console.log(await broadcastTransaction(migratorTx, network)); + console.log(await broadcastTransaction(bridgeTx, network)); +} + +run() + .catch(console.error) + .finally(() => { + process.exit(); + }); diff --git a/contracts/scripts/script-utils.ts b/contracts/scripts/script-utils.ts index def77f4..11128dc 100644 --- a/contracts/scripts/script-utils.ts +++ b/contracts/scripts/script-utils.ts @@ -1,9 +1,12 @@ import 'cross-fetch/polyfill'; +import { config } from 'dotenv'; +config(); import { project, contracts as _contracts } from '@bns-x/core'; import { projectFactory, contractFactory } from '@clarigen/core'; import type { StacksNetwork } from 'micro-stacks/network'; import { StacksMainnet, StacksMocknet, StacksTestnet } from 'micro-stacks/network'; import { privateKeyToStxAddress, StacksNetworkVersion } from 'micro-stacks/crypto'; +import { fetchAccountNonces } from 'micro-stacks/api'; export let networkKey: 'devnet' | 'testnet' | 'mainnet' = 'devnet'; export let network: StacksNetwork = new StacksMocknet({ @@ -44,3 +47,12 @@ export function getControllerAddress(privateKey: string) { } return privateKeyToStxAddress(privateKey, version, false); } + +export async function getNonce() { + const nonces = await fetchAccountNonces({ + url: network.getCoreApiUrl(), + // principal: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + principal: deployer, + }); + return nonces.possible_next_nonce; +} diff --git a/contracts/tests/clarigen-types.ts b/contracts/tests/clarigen-types.ts index f5f1d8e..25037c3 100644 --- a/contracts/tests/clarigen-types.ts +++ b/contracts/tests/clarigen-types.ts @@ -2661,6 +2661,296 @@ export const contracts = { 'clarity_version': 'Clarity1', contractName: 'bnsx-registry', }, + communityHandlesV2: { + 'functions': { + bulkNameRegisterIter: { + 'name': 'bulk-name-register-iter', + 'access': 'private', + 'args': [{ + 'name': 'entry', + 'type': { + 'tuple': [ + { 'name': 'name', 'type': { 'buffer': { 'length': 48 } } }, + { 'name': 'owner', 'type': 'principal' }, + { + 'name': 'zonefile-hash', + 'type': { 'buffer': { 'length': 20 } }, + }, + ], + }, + }, { + 'name': 'prev', + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction<[ + entry: TypedAbiArg<{ + 'name': Uint8Array; + 'owner': string; + 'zonefileHash': Uint8Array; + }, 'entry'>, + prev: TypedAbiArg, 'prev'>, + ], Response>, + isContractCallerNamespaceController: { + 'name': 'is-contract-caller-namespace-controller', + 'access': 'private', + 'args': [{ + 'name': 'namespace', + 'type': { 'buffer': { 'length': 20 } }, + }], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [namespace: TypedAbiArg], + Response + >, + toBoolResponse: { + 'name': 'to-bool-response', + 'access': 'private', + 'args': [{ + 'name': 'value', + 'type': { 'response': { 'ok': 'bool', 'error': 'int128' } }, + }], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [value: TypedAbiArg, 'value'>], + Response + >, + toUintResponse: { + 'name': 'to-uint-response', + 'access': 'private', + 'args': [{ + 'name': 'value', + 'type': { 'response': { 'ok': 'uint128', 'error': 'int128' } }, + }], + 'outputs': { + 'type': { 'response': { 'ok': 'uint128', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [ + value: TypedAbiArg< + Response, + 'value' + >, + ], + Response + >, + bulkNameRegister: { + 'name': 'bulk-name-register', + 'access': 'public', + 'args': [{ + 'name': 'namespace', + 'type': { 'buffer': { 'length': 20 } }, + }, { + 'name': 'names', + 'type': { + 'list': { + 'type': { + 'tuple': [ + { 'name': 'name', 'type': { 'buffer': { 'length': 48 } } }, + { 'name': 'owner', 'type': 'principal' }, + { + 'name': 'zonefile-hash', + 'type': { 'buffer': { 'length': 20 } }, + }, + ], + }, + 'length': 1000, + }, + }, + }], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + names: TypedAbiArg<{ + 'name': Uint8Array; + 'owner': string; + 'zonefileHash': Uint8Array; + }[], 'names'>, + ], + Response + >, + nameRegister: { + 'name': 'name-register', + 'access': 'public', + 'args': [ + { 'name': 'namespace', 'type': { 'buffer': { 'length': 20 } } }, + { 'name': 'name', 'type': { 'buffer': { 'length': 48 } } }, + { 'name': 'owner', 'type': 'principal' }, + { 'name': 'zonefile-hash', 'type': { 'buffer': { 'length': 20 } } }, + ], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + name: TypedAbiArg, + owner: TypedAbiArg, + zonefileHash: TypedAbiArg, + ], + Response + >, + nameRenewal: { + 'name': 'name-renewal', + 'access': 'public', + 'args': [ + { 'name': 'namespace', 'type': { 'buffer': { 'length': 20 } } }, + { 'name': 'name', 'type': { 'buffer': { 'length': 48 } } }, + { 'name': 'new-owner', 'type': { 'optional': 'principal' } }, + { + 'name': 'zonefile-hash', + 'type': { 'optional': { 'buffer': { 'length': 20 } } }, + }, + ], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + name: TypedAbiArg, + newOwner: TypedAbiArg, + zonefileHash: TypedAbiArg, + ], + Response + >, + namespacePreorder: { + 'name': 'namespace-preorder', + 'access': 'public', + 'args': [{ + 'name': 'hashed-salted-namespace', + 'type': { 'buffer': { 'length': 20 } }, + }, { 'name': 'stx-to-burn', 'type': 'uint128' }], + 'outputs': { + 'type': { 'response': { 'ok': 'uint128', 'error': 'int128' } }, + }, + } as TypedAbiFunction< + [ + hashedSaltedNamespace: TypedAbiArg< + Uint8Array, + 'hashedSaltedNamespace' + >, + stxToBurn: TypedAbiArg, + ], + Response + >, + namespaceReveal: { + 'name': 'namespace-reveal', + 'access': 'public', + 'args': [ + { 'name': 'namespace', 'type': { 'buffer': { 'length': 20 } } }, + { 'name': 'salt', 'type': { 'buffer': { 'length': 20 } } }, + { 'name': 'lifetime', 'type': 'uint128' }, + { 'name': 'controller', 'type': { 'optional': 'principal' } }, + ], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'int128' } }, + }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + salt: TypedAbiArg, + lifetime: TypedAbiArg, + controller: TypedAbiArg, + ], + Response + >, + setNamespaceController: { + 'name': 'set-namespace-controller', + 'access': 'public', + 'args': [{ + 'name': 'namespace', + 'type': { 'buffer': { 'length': 20 } }, + }, { 'name': 'new-controller', 'type': 'principal' }], + 'outputs': { + 'type': { 'response': { 'ok': 'bool', 'error': 'uint128' } }, + }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + newController: TypedAbiArg, + ], + Response + >, + getNamespaceController: { + 'name': 'get-namespace-controller', + 'access': 'read_only', + 'args': [{ + 'name': 'namespace', + 'type': { 'buffer': { 'length': 20 } }, + }], + 'outputs': { 'type': { 'optional': 'principal' } }, + } as TypedAbiFunction< + [namespace: TypedAbiArg], + string | null + >, + }, + 'maps': { + namespaceController: { + 'name': 'namespace-controller', + 'key': { 'buffer': { 'length': 20 } }, + 'value': 'principal', + } as TypedAbiMap, + }, + 'variables': { + errNotAuthorized: { + name: 'err-not-authorized', + type: { + response: { + ok: 'none', + error: 'uint128', + }, + }, + access: 'constant', + } as TypedAbiVariable>, + internalPriceHigh: { + name: 'internal-price-high', + type: 'uint128', + access: 'constant', + } as TypedAbiVariable, + nameSalt: { + name: 'name-salt', + type: { + buffer: { + length: 1, + }, + }, + access: 'constant', + } as TypedAbiVariable, + ctxBulkRegistrationNamespace: { + name: 'ctx-bulk-registration-namespace', + type: { + buffer: { + length: 20, + }, + }, + access: 'variable', + } as TypedAbiVariable, + }, + constants: { + errNotAuthorized: { + isOk: false, + value: 403n, + }, + internalPriceHigh: 999999999999999999999999999999n, + nameSalt: Uint8Array.from([0]), + ctxBulkRegistrationNamespace: Uint8Array.from([0]), + }, + 'non_fungible_tokens': [], + 'fungible_tokens': [{ 'name': 'danger-zone-token' }], + 'epoch': 'Epoch21', + 'clarity_version': 'Clarity2', + contractName: 'community-handles-v2', + }, extensionTrait: { 'functions': {}, 'maps': {}, @@ -3877,7 +4167,7 @@ export const contracts = { isOk: false, value: 10002n, }, - wrapperIdVar: 3n, + wrapperIdVar: 2n, }, 'non_fungible_tokens': [], 'fungible_tokens': [], @@ -4153,7 +4443,7 @@ export const contracts = { isOk: false, value: 10002n, }, - wrapperIdVar: 2n, + wrapperIdVar: 3n, }, 'non_fungible_tokens': [], 'fungible_tokens': [], @@ -5955,6 +6245,8 @@ export const identifiers = { 'bnsV1': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.bns-v1', 'bnsxExtensions': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.bnsx-extensions', 'bnsxRegistry': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.bnsx-registry', + 'communityHandlesV2': + 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.community-handles-v2', 'extensionTrait': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.extension-trait', 'fakeFt': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.fake-ft', 'fakeNft': 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.fake-nft', diff --git a/contracts/tests/clarigen.ts b/contracts/tests/clarigen.ts index b9f958a..5b058e9 100644 --- a/contracts/tests/clarigen.ts +++ b/contracts/tests/clarigen.ts @@ -11,6 +11,7 @@ export const { bnsV1, bnsxExtensions, bnsxRegistry, + communityHandlesV2, extensionTrait, fakeFt, fakeNft, diff --git a/packages/core/src/clarigen.ts b/packages/core/src/clarigen.ts index 690e62d..7f80b7a 100644 --- a/packages/core/src/clarigen.ts +++ b/packages/core/src/clarigen.ts @@ -2422,6 +2422,253 @@ export const contracts = { clarity_version: 'Clarity1', contractName: 'bnsx-registry', }, + communityHandlesV2: { + functions: { + bulkNameRegisterIter: { + name: 'bulk-name-register-iter', + access: 'private', + args: [ + { + name: 'entry', + type: { + tuple: [ + { name: 'name', type: { buffer: { length: 48 } } }, + { name: 'owner', type: 'principal' }, + { name: 'zonefile-hash', type: { buffer: { length: 20 } } }, + ], + }, + }, + { name: 'prev', type: { response: { ok: 'bool', error: 'uint128' } } }, + ], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [ + entry: TypedAbiArg< + { + name: Uint8Array; + owner: string; + zonefileHash: Uint8Array; + }, + 'entry' + >, + prev: TypedAbiArg, 'prev'> + ], + Response + >, + isContractCallerNamespaceController: { + name: 'is-contract-caller-namespace-controller', + access: 'private', + args: [{ name: 'namespace', type: { buffer: { length: 20 } } }], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [namespace: TypedAbiArg], + Response + >, + toBoolResponse: { + name: 'to-bool-response', + access: 'private', + args: [{ name: 'value', type: { response: { ok: 'bool', error: 'int128' } } }], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [value: TypedAbiArg, 'value'>], + Response + >, + toUintResponse: { + name: 'to-uint-response', + access: 'private', + args: [{ name: 'value', type: { response: { ok: 'uint128', error: 'int128' } } }], + outputs: { type: { response: { ok: 'uint128', error: 'uint128' } } }, + } as TypedAbiFunction< + [value: TypedAbiArg, 'value'>], + Response + >, + bulkNameRegister: { + name: 'bulk-name-register', + access: 'public', + args: [ + { name: 'namespace', type: { buffer: { length: 20 } } }, + { + name: 'names', + type: { + list: { + type: { + tuple: [ + { name: 'name', type: { buffer: { length: 48 } } }, + { name: 'owner', type: 'principal' }, + { name: 'zonefile-hash', type: { buffer: { length: 20 } } }, + ], + }, + length: 1000, + }, + }, + }, + ], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + names: TypedAbiArg< + { + name: Uint8Array; + owner: string; + zonefileHash: Uint8Array; + }[], + 'names' + > + ], + Response + >, + nameRegister: { + name: 'name-register', + access: 'public', + args: [ + { name: 'namespace', type: { buffer: { length: 20 } } }, + { name: 'name', type: { buffer: { length: 48 } } }, + { name: 'owner', type: 'principal' }, + { name: 'zonefile-hash', type: { buffer: { length: 20 } } }, + ], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + name: TypedAbiArg, + owner: TypedAbiArg, + zonefileHash: TypedAbiArg + ], + Response + >, + nameRenewal: { + name: 'name-renewal', + access: 'public', + args: [ + { name: 'namespace', type: { buffer: { length: 20 } } }, + { name: 'name', type: { buffer: { length: 48 } } }, + { name: 'new-owner', type: { optional: 'principal' } }, + { name: 'zonefile-hash', type: { optional: { buffer: { length: 20 } } } }, + ], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + name: TypedAbiArg, + newOwner: TypedAbiArg, + zonefileHash: TypedAbiArg + ], + Response + >, + namespacePreorder: { + name: 'namespace-preorder', + access: 'public', + args: [ + { name: 'hashed-salted-namespace', type: { buffer: { length: 20 } } }, + { name: 'stx-to-burn', type: 'uint128' }, + ], + outputs: { type: { response: { ok: 'uint128', error: 'int128' } } }, + } as TypedAbiFunction< + [ + hashedSaltedNamespace: TypedAbiArg, + stxToBurn: TypedAbiArg + ], + Response + >, + namespaceReveal: { + name: 'namespace-reveal', + access: 'public', + args: [ + { name: 'namespace', type: { buffer: { length: 20 } } }, + { name: 'salt', type: { buffer: { length: 20 } } }, + { name: 'lifetime', type: 'uint128' }, + { name: 'controller', type: { optional: 'principal' } }, + ], + outputs: { type: { response: { ok: 'bool', error: 'int128' } } }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + salt: TypedAbiArg, + lifetime: TypedAbiArg, + controller: TypedAbiArg + ], + Response + >, + setNamespaceController: { + name: 'set-namespace-controller', + access: 'public', + args: [ + { name: 'namespace', type: { buffer: { length: 20 } } }, + { name: 'new-controller', type: 'principal' }, + ], + outputs: { type: { response: { ok: 'bool', error: 'uint128' } } }, + } as TypedAbiFunction< + [ + namespace: TypedAbiArg, + newController: TypedAbiArg + ], + Response + >, + getNamespaceController: { + name: 'get-namespace-controller', + access: 'read_only', + args: [{ name: 'namespace', type: { buffer: { length: 20 } } }], + outputs: { type: { optional: 'principal' } }, + } as TypedAbiFunction<[namespace: TypedAbiArg], string | null>, + }, + maps: { + namespaceController: { + name: 'namespace-controller', + key: { buffer: { length: 20 } }, + value: 'principal', + } as TypedAbiMap, + }, + variables: { + errNotAuthorized: { + name: 'err-not-authorized', + type: { + response: { + ok: 'none', + error: 'uint128', + }, + }, + access: 'constant', + } as TypedAbiVariable>, + internalPriceHigh: { + name: 'internal-price-high', + type: 'uint128', + access: 'constant', + } as TypedAbiVariable, + nameSalt: { + name: 'name-salt', + type: { + buffer: { + length: 1, + }, + }, + access: 'constant', + } as TypedAbiVariable, + ctxBulkRegistrationNamespace: { + name: 'ctx-bulk-registration-namespace', + type: { + buffer: { + length: 20, + }, + }, + access: 'variable', + } as TypedAbiVariable, + }, + constants: { + errNotAuthorized: { + isOk: false, + value: 403n, + }, + internalPriceHigh: 999999999999999999999999999999n, + nameSalt: Uint8Array.from([0]), + ctxBulkRegistrationNamespace: Uint8Array.from([0]), + }, + non_fungible_tokens: [], + fungible_tokens: [{ name: 'danger-zone-token' }], + epoch: 'Epoch21', + clarity_version: 'Clarity2', + contractName: 'community-handles-v2', + }, extensionTrait: { functions: {}, maps: {}, @@ -3512,7 +3759,7 @@ export const contracts = { isOk: false, value: 10002n, }, - wrapperIdVar: 3n, + wrapperIdVar: 2n, }, non_fungible_tokens: [], fungible_tokens: [], @@ -3778,7 +4025,7 @@ export const contracts = { isOk: false, value: 10002n, }, - wrapperIdVar: 2n, + wrapperIdVar: 3n, }, non_fungible_tokens: [], fungible_tokens: [], @@ -5396,6 +5643,12 @@ export const deployments = { testnet: 'STQSAQN4XGY5SE0GGXF9QXZYWWG0Q8A6SDX206PG.bnsx-registry', mainnet: 'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.bnsx-registry', }, + communityHandlesV2: { + devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.community-handles-v2', + simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.community-handles-v2', + testnet: null, + mainnet: null, + }, extensionTrait: { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.extension-trait', simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.extension-trait', @@ -5418,13 +5671,13 @@ export const deployments = { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.l1-bridge-v1', simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.l1-bridge-v1', testnet: null, - mainnet: null, + mainnet: 'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.l1-bridge-v1', }, l1Registry: { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.l1-registry', simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.l1-registry', testnet: null, - mainnet: null, + mainnet: 'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.l1-registry', }, nameRegistrar: { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.name-registrar', @@ -5466,7 +5719,7 @@ export const deployments = { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-migrator-v2', simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-migrator-v2', testnet: null, - mainnet: null, + mainnet: 'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.proposal-migrator-v2', }, proposalTrait: { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-trait', @@ -5496,7 +5749,7 @@ export const deployments = { devnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.wrapper-migrator-v2', simnet: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.wrapper-migrator-v2', testnet: null, - mainnet: null, + mainnet: 'SP1JTCR202ECC6333N7ZXD7MK7E3ZTEEE1MJ73C60.wrapper-migrator-v2', }, } as const;