pub const BNS_CONTRACT: &'static str = ";;;; Errors\n(define-constant ERR_PANIC 0)\n(define-constant ERR_NAMESPACE_PREORDER_NOT_FOUND 1001)\n(define-constant ERR_NAMESPACE_PREORDER_EXPIRED 1002)\n(define-constant ERR_NAMESPACE_PREORDER_ALREADY_EXISTS 1003)\n(define-constant ERR_NAMESPACE_UNAVAILABLE 1004)\n(define-constant ERR_NAMESPACE_NOT_FOUND 1005)\n(define-constant ERR_NAMESPACE_ALREADY_EXISTS 1006)\n(define-constant ERR_NAMESPACE_NOT_LAUNCHED 1007)\n(define-constant ERR_NAMESPACE_PRICE_FUNCTION_INVALID 1008)\n(define-constant ERR_NAMESPACE_PREORDER_CLAIMABILITY_EXPIRED 1009)\n(define-constant ERR_NAMESPACE_PREORDER_LAUNCHABILITY_EXPIRED 1010)\n(define-constant ERR_NAMESPACE_OPERATION_UNAUTHORIZED 1011)\n(define-constant ERR_NAMESPACE_STX_BURNT_INSUFFICIENT 1012)\n(define-constant ERR_NAMESPACE_BLANK 1013)\n(define-constant ERR_NAMESPACE_ALREADY_LAUNCHED 1014)\n(define-constant ERR_NAMESPACE_HASH_MALFORMED 1015)\n(define-constant ERR_NAMESPACE_CHARSET_INVALID 1016)\n\n(define-constant ERR_NAME_PREORDER_NOT_FOUND 2001)\n(define-constant ERR_NAME_PREORDER_EXPIRED 2002)\n(define-constant ERR_NAME_PREORDER_FUNDS_INSUFFICIENT 2003)\n(define-constant ERR_NAME_UNAVAILABLE 2004)\n(define-constant ERR_NAME_OPERATION_UNAUTHORIZED 2006)\n(define-constant ERR_NAME_STX_BURNT_INSUFFICIENT 2007)\n(define-constant ERR_NAME_EXPIRED 2008)\n(define-constant ERR_NAME_GRACE_PERIOD 2009)\n(define-constant ERR_NAME_BLANK 2010)\n(define-constant ERR_NAME_ALREADY_CLAIMED 2011)\n(define-constant ERR_NAME_CLAIMABILITY_EXPIRED 2012)\n(define-constant ERR_NAME_NOT_FOUND 2013)\n(define-constant ERR_NAME_REVOKED 2014)\n(define-constant ERR_NAME_TRANSFER_FAILED 2015)\n(define-constant ERR_NAME_PREORDER_ALREADY_EXISTS 2016)\n(define-constant ERR_NAME_HASH_MALFORMED 2017)\n(define-constant ERR_NAME_PREORDERED_BEFORE_NAMESPACE_LAUNCH 2018)\n(define-constant ERR_NAME_NOT_RESOLVABLE 2019)\n(define-constant ERR_NAME_COULD_NOT_BE_MINTED 2020)\n(define-constant ERR_NAME_COULD_NOT_BE_TRANSFERED 2021)\n(define-constant ERR_NAME_CHARSET_INVALID 2022)\n\n(define-constant ERR_PRINCIPAL_ALREADY_ASSOCIATED 3001)\n(define-constant ERR_INSUFFICIENT_FUNDS 4001)\n\n(define-constant NAMESPACE_PREORDER_CLAIMABILITY_TTL u144)\n(define-constant NAMESPACE_LAUNCHABILITY_TTL u52595)\n(define-constant NAME_PREORDER_CLAIMABILITY_TTL u144)\n(define-constant NAME_GRACE_PERIOD_DURATION u5000)\n\n(define-data-var attachment-index uint u0)\n\n;; Price tables\n(define-constant NAMESPACE_PRICE_TIERS (list\n u640000000000\n u64000000000 u64000000000 \n u6400000000 u6400000000 u6400000000 u6400000000 \n u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000 u640000000))\n\n;;;; Data\n(define-map namespaces\n (buff 20)\n { namespace-import: principal,\n revealed-at: uint,\n launched-at: (optional uint),\n lifetime: uint,\n can-update-price-function: bool,\n price-function: {\n buckets: (list 16 uint),\n base: uint, \n coeff: uint, \n nonalpha-discount: uint, \n no-vowel-discount: uint\n }\n })\n\n(define-map namespace-preorders\n { hashed-salted-namespace: (buff 20), buyer: principal }\n { created-at: uint, claimed: bool, stx-burned: uint })\n\n(define-non-fungible-token names { name: (buff 48), namespace: (buff 20) })\n\n;; Rule 1-1 -> 1 principal, 1 name\n(define-map owner-name principal { name: (buff 48), namespace: (buff 20) })\n;; Only applies to non-revoked, non-expired names. \n;; A principal can own many expired names (but they will be transferred away once someone re-registers them), \n;; and can own many revoked names (but they do not resolve and cannot be transferred or updated).\n\n(define-map name-properties\n { name: (buff 48), namespace: (buff 20) }\n { registered-at: (optional uint),\n imported-at: (optional uint),\n revoked-at: (optional uint),\n zonefile-hash: (buff 20) })\n\n(define-map name-preorders\n { hashed-salted-fqn: (buff 20), buyer: principal }\n { created-at: uint, claimed: bool, stx-burned: uint })\n\n(define-private (min (a uint) (b uint))\n (if (<= a b) a b))\n\n(define-private (max (a uint) (b uint))\n (if (> a b) a b))\n\n(define-private (get-exp-at-index (buckets (list 16 uint)) (index uint))\n (unwrap-panic (element-at buckets index)))\n\n(define-private (is-digit (char (buff 1)))\n (or \n (is-eq char 0x30) ;; 0\n (is-eq char 0x31) ;; 1\n (is-eq char 0x32) ;; 2\n (is-eq char 0x33) ;; 3\n (is-eq char 0x34) ;; 4\n (is-eq char 0x35) ;; 5\n (is-eq char 0x36) ;; 6\n (is-eq char 0x37) ;; 7\n (is-eq char 0x38) ;; 8\n (is-eq char 0x39))) ;; 9\n\n(define-private (is-lowercase-alpha (char (buff 1)))\n (or \n (is-eq char 0x61) ;; a\n (is-eq char 0x62) ;; b\n (is-eq char 0x63) ;; c\n (is-eq char 0x64) ;; d\n (is-eq char 0x65) ;; e\n (is-eq char 0x66) ;; f\n (is-eq char 0x67) ;; g\n (is-eq char 0x68) ;; h\n (is-eq char 0x69) ;; i\n (is-eq char 0x6a) ;; j\n (is-eq char 0x6b) ;; k\n (is-eq char 0x6c) ;; l\n (is-eq char 0x6d) ;; m\n (is-eq char 0x6e) ;; n\n (is-eq char 0x6f) ;; o\n (is-eq char 0x70) ;; p\n (is-eq char 0x71) ;; q\n (is-eq char 0x72) ;; r\n (is-eq char 0x73) ;; s\n (is-eq char 0x74) ;; t\n (is-eq char 0x75) ;; u\n (is-eq char 0x76) ;; v\n (is-eq char 0x77) ;; w\n (is-eq char 0x78) ;; x\n (is-eq char 0x79) ;; y\n (is-eq char 0x7a))) ;; z\n\n(define-private (is-vowel (char (buff 1)))\n (or \n (is-eq char 0x61) ;; a\n (is-eq char 0x65) ;; e\n (is-eq char 0x69) ;; i\n (is-eq char 0x6f) ;; o\n (is-eq char 0x75) ;; u\n (is-eq char 0x79))) ;; y\n\n(define-private (is-special-char (char (buff 1)))\n (or \n (is-eq char 0x2d) ;; -\n (is-eq char 0x5f))) ;; _\n\n(define-private (is-char-valid (char (buff 1)))\n (or \n (is-lowercase-alpha char)\n (is-digit char)\n (is-special-char char)))\n\n(define-private (is-nonalpha (char (buff 1)))\n (or \n (is-digit char)\n (is-special-char char)))\n\n(define-private (has-vowels-chars (name (buff 48)))\n (> (len (filter is-vowel name)) u0))\n\n(define-private (has-nonalpha-chars (name (buff 48)))\n (> (len (filter is-nonalpha name)) u0))\n\n(define-private (has-invalid-chars (name (buff 48)))\n (< (len (filter is-char-valid name)) (len name)))\n\n(define-private (name-lease-started-at? (namespace-launched-at (optional uint)) \n (namespace-revealed-at uint)\n (name-props (tuple \n (registered-at (optional uint))\n (imported-at (optional uint))\n (revoked-at (optional uint))\n (zonefile-hash (buff 20)))))\n (let ((registered-at (get registered-at name-props))\n (imported-at (get imported-at name-props)))\n (if (is-none namespace-launched-at)\n (begin\n ;; The namespace must not be expired\n (asserts! \n (> (+ namespace-revealed-at NAMESPACE_LAUNCHABILITY_TTL) block-height) \n (err ERR_NAMESPACE_PREORDER_LAUNCHABILITY_EXPIRED))\n (ok (unwrap-panic imported-at)))\n (begin\n ;; The namespace must be launched\n (asserts! (is-some namespace-launched-at) (err ERR_NAMESPACE_NOT_LAUNCHED))\n ;; Sanity check: the name must have been either be registered or imported\n (asserts! (is-eq (xor \n (match registered-at res 1 0)\n (match imported-at res 1 0)) 1) (err ERR_PANIC))\n ;; If the name was launched, then started-at will come from registered-at\n (if (is-some registered-at)\n ;; The name was registered - We return the registration block height\n (ok (unwrap-panic registered-at))\n ;; The name was imported\n (if (and (>= (unwrap-panic imported-at) namespace-revealed-at)\n (<= (unwrap-panic imported-at) (unwrap-panic namespace-launched-at)))\n ;; The name was imported after revealing the namespace and before launching the namespace - We return the launch block height\n (ok (unwrap-panic namespace-launched-at))\n (ok u0)))))))\n\n;; Note: the following method is used in name-import and name-register. The latter ensure that the name\n;; can be registered, the former does not. \n(define-private (mint-or-transfer-name? (namespace (buff 20)) (name (buff 48)) (beneficiary principal))\n (let (\n (current-owner (nft-get-owner? names (tuple (name name) (namespace namespace)))))\n ;; The principal can register a name\n (asserts!\n (try! (can-receive-name beneficiary))\n (err ERR_PRINCIPAL_ALREADY_ASSOCIATED))\n (if (is-none current-owner)\n ;; This is a new name, let\'s mint it\n (begin\n (unwrap! \n (nft-mint?\n names \n { name: name, namespace: namespace }\n beneficiary)\n (err ERR_NAME_COULD_NOT_BE_MINTED))\n (map-set owner-name\n beneficiary\n { name: name, namespace: namespace })\n (ok true))\n (update-name-ownership? namespace name (unwrap-panic current-owner) beneficiary))))\n\n(define-private (update-name-ownership? (namespace (buff 20)) \n (name (buff 48)) \n (from principal) \n (to principal))\n (if (is-eq from to)\n (ok true)\n (begin\n (unwrap!\n (nft-transfer? names { name: name, namespace: namespace } from to)\n (err ERR_NAME_COULD_NOT_BE_TRANSFERED))\n (map-delete owner-name from)\n (map-set owner-name\n to\n { name: name, namespace: namespace })\n (ok true))))\n\n(define-private (update-zonefile-and-props (namespace (buff 20))\n (name (buff 48))\n (registered-at (optional uint)) \n (imported-at (optional uint)) \n (revoked-at (optional uint)) \n (zonefile-hash (buff 20))\n (op (string-ascii 16)))\n (let \n ((current-index (var-get attachment-index)))\n ;; Emit event used as a system hinter\n (print {\n attachment: {\n hash: zonefile-hash,\n attachment-index: current-index,\n metadata: {\n name: name,\n namespace: namespace,\n tx-sender: tx-sender,\n op: op\n }\n }})\n ;; Update cursor\n (var-set attachment-index (+ u1 current-index))\n (map-set name-properties\n { name: name, namespace: namespace }\n { registered-at: registered-at,\n imported-at: imported-at,\n revoked-at: revoked-at,\n zonefile-hash: zonefile-hash })))\n\n(define-private (is-namespace-available (namespace (buff 20)))\n (match (map-get? namespaces namespace) namespace-props\n (begin\n ;; Is the namespace launched?\n (if (is-some (get launched-at namespace-props)) \n false\n (> block-height (+ (get revealed-at namespace-props) NAMESPACE_LAUNCHABILITY_TTL)))) ;; Is the namespace expired?\n true))\n\n(define-private (compute-name-price (name (buff 48))\n (price-function (tuple (buckets (list 16 uint)) \n (base uint) \n (coeff uint) \n (nonalpha-discount uint) \n (no-vowel-discount uint))))\n (let (\n (exponent (get-exp-at-index (get buckets price-function) (min u15 (- (len name) u1))))\n (no-vowel-discount (if (not (has-vowels-chars name)) (get no-vowel-discount price-function) u1))\n (nonalpha-discount (if (has-nonalpha-chars name) (get nonalpha-discount price-function) u1)))\n (*\n (/\n (*\n (get coeff price-function)\n (pow (get base price-function) exponent))\n (max nonalpha-discount no-vowel-discount))\n u10)))\n\n;;;; NAMESPACES\n;; NAMESPACE_PREORDER\n;; This step registers the salted hash of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency.\n;; Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent\n;; consensus hash in the transaction.\n;; Returns pre-order\'s expiration date (in blocks).\n(define-public (namespace-preorder (hashed-salted-namespace (buff 20))\n (stx-to-burn uint))\n (let \n ((former-preorder \n (map-get? namespace-preorders { hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender })))\n ;; Ensure eventual former pre-order expired \n (asserts! \n (if (is-none former-preorder)\n true\n (>= block-height (+ NAMESPACE_PREORDER_CLAIMABILITY_TTL\n (unwrap-panic (get created-at former-preorder)))))\n (err ERR_NAMESPACE_PREORDER_ALREADY_EXISTS))\n ;; Ensure that the hashed namespace is 20 bytes long\n (asserts! (is-eq (len hashed-salted-namespace) u20) (err ERR_NAMESPACE_HASH_MALFORMED))\n ;; Ensure that user will be burning a positive amount of tokens\n (asserts! (> stx-to-burn u0) (err ERR_NAMESPACE_STX_BURNT_INSUFFICIENT))\n ;; Burn the tokens\n (unwrap! (stx-burn? stx-to-burn tx-sender) (err ERR_INSUFFICIENT_FUNDS))\n ;; Register the preorder\n (map-set namespace-preorders\n { hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender }\n { created-at: block-height, claimed: false, stx-burned: stx-to-burn })\n (ok (+ block-height NAMESPACE_PREORDER_CLAIMABILITY_TTL))))\n\n;; NAMESPACE_REVEAL\n;; This second step reveals the salt and the namespace ID (pairing it with its NAMESPACE_PREORDER). It reveals how long\n;; names last in this namespace before they expire or must be renewed, and it sets a price function for the namespace\n;; that determines how cheap or expensive names its will be.\n(define-public (namespace-reveal (namespace (buff 20))\n (namespace-salt (buff 20))\n (p-func-base uint)\n (p-func-coeff uint)\n (p-func-b1 uint)\n (p-func-b2 uint)\n (p-func-b3 uint)\n (p-func-b4 uint)\n (p-func-b5 uint)\n (p-func-b6 uint)\n (p-func-b7 uint)\n (p-func-b8 uint)\n (p-func-b9 uint)\n (p-func-b10 uint)\n (p-func-b11 uint)\n (p-func-b12 uint)\n (p-func-b13 uint)\n (p-func-b14 uint)\n (p-func-b15 uint)\n (p-func-b16 uint)\n (p-func-non-alpha-discount uint)\n (p-func-no-vowel-discount uint)\n (lifetime uint)\n (namespace-import principal))\n ;; The salt and namespace must hash to a preorder entry in the `namespace_preorders` table.\n ;; The sender must match the principal in the preorder entry (implied)\n (let (\n (hashed-salted-namespace (hash160 (concat namespace namespace-salt)))\n (price-function (tuple \n (buckets (list\n p-func-b1\n p-func-b2\n p-func-b3\n p-func-b4\n p-func-b5\n p-func-b6\n p-func-b7\n p-func-b8\n p-func-b9\n p-func-b10\n p-func-b11\n p-func-b12\n p-func-b13\n p-func-b14\n p-func-b15\n p-func-b16))\n (base p-func-base)\n (coeff p-func-coeff)\n (nonalpha-discount p-func-non-alpha-discount)\n (no-vowel-discount p-func-no-vowel-discount)))\n (preorder (unwrap!\n (map-get? namespace-preorders { hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender })\n (err ERR_NAMESPACE_PREORDER_NOT_FOUND)))\n (namespace-price (try! (get-namespace-price namespace))))\n ;; The namespace must only have valid chars\n (asserts!\n (not (has-invalid-chars namespace))\n (err ERR_NAMESPACE_CHARSET_INVALID))\n ;; The namespace must not exist in the `namespaces` table, or be expired\n (asserts! \n (is-namespace-available namespace)\n (err ERR_NAMESPACE_ALREADY_EXISTS))\n ;; The amount burnt must be equal to or greater than the cost of the namespace\n (asserts!\n (>= (get stx-burned preorder) namespace-price)\n (err ERR_NAMESPACE_STX_BURNT_INSUFFICIENT))\n ;; This transaction must arrive within 24 hours of its `NAMESPACE_PREORDER`\n (asserts!\n (< block-height (+ (get created-at preorder) NAMESPACE_PREORDER_CLAIMABILITY_TTL))\n (err ERR_NAMESPACE_PREORDER_CLAIMABILITY_EXPIRED))\n ;; The preorder record for this namespace will be marked as \"claimed\"\n (map-set namespace-preorders\n { hashed-salted-namespace: hashed-salted-namespace, buyer: tx-sender }\n { created-at: (get created-at preorder), claimed: true, stx-burned: (get stx-burned preorder) })\n ;; The namespace will be set as \"revealed\" but not \"launched\", its price function, its renewal rules, its version,\n ;; and its import principal will be written to the `namespaces` table.\n (map-set namespaces\n namespace\n { namespace-import: namespace-import,\n revealed-at: block-height,\n launched-at: none,\n lifetime: lifetime,\n can-update-price-function: true,\n price-function: price-function })\n (ok true)))\n\n;; NAME_IMPORT\n;; Once a namespace is revealed, the user has the option to populate it with a set of names. Each imported name is given\n;; both an owner and some off-chain state. This step is optional; Namespace creators are not required to import names.\n(define-public (name-import (namespace (buff 20))\n (name (buff 48))\n (beneficiary principal)\n (zonefile-hash (buff 20)))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND))))\n ;; The name must only have valid chars\n (asserts!\n (not (has-invalid-chars name))\n (err ERR_NAME_CHARSET_INVALID))\n ;; The sender principal must match the namespace\'s import principal\n (asserts!\n (is-eq (get namespace-import namespace-props) tx-sender)\n (err ERR_NAMESPACE_OPERATION_UNAUTHORIZED))\n ;; The name\'s namespace must not be launched\n (asserts!\n (is-none (get launched-at namespace-props))\n (err ERR_NAMESPACE_ALREADY_LAUNCHED))\n ;; Less than 1 year must have passed since the namespace was \"revealed\"\n (asserts!\n (< block-height (+ (get revealed-at namespace-props) NAMESPACE_LAUNCHABILITY_TTL))\n (err ERR_NAMESPACE_PREORDER_LAUNCHABILITY_EXPIRED))\n ;; Mint the new name\n (try! (mint-or-transfer-name? namespace name beneficiary))\n ;; Update zonefile and props\n (update-zonefile-and-props\n namespace \n name \n none\n (some block-height) ;; Set imported-at\n none\n zonefile-hash\n \"name-import\")\n (ok true)))\n\n;; NAMESPACE_READY\n;; The final step of the process launches the namespace and makes the namespace available to the public. Once a namespace\n;; is launched, anyone can register a name in it if they pay the appropriate amount of cryptocurrency.\n(define-public (namespace-ready (namespace (buff 20)))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND))))\n ;; The sender principal must match the namespace\'s import principal\n (asserts!\n (is-eq (get namespace-import namespace-props) tx-sender)\n (err ERR_NAMESPACE_OPERATION_UNAUTHORIZED))\n ;; The name\'s namespace must not be launched\n (asserts!\n (is-none (get launched-at namespace-props))\n (err ERR_NAMESPACE_ALREADY_LAUNCHED))\n ;; Less than 1 year must have passed since the namespace was \"revealed\"\n (asserts!\n (< block-height (+ (get revealed-at namespace-props) NAMESPACE_LAUNCHABILITY_TTL))\n (err ERR_NAMESPACE_PREORDER_LAUNCHABILITY_EXPIRED)) \n (let ((namespace-props-updated (merge namespace-props { launched-at: (some block-height) })))\n ;; The namespace will be set to \"launched\"\n (map-set namespaces namespace namespace-props-updated)\n ;; Emit an event\n (print { namespace: namespace, status: \"ready\", properties: namespace-props-updated })\n (ok true))))\n\n;; NAMESPACE_UPDATE_FUNCTION_PRICE\n(define-public (namespace-update-function-price (namespace (buff 20))\n (p-func-base uint)\n (p-func-coeff uint)\n (p-func-b1 uint)\n (p-func-b2 uint)\n (p-func-b3 uint)\n (p-func-b4 uint)\n (p-func-b5 uint)\n (p-func-b6 uint)\n (p-func-b7 uint)\n (p-func-b8 uint)\n (p-func-b9 uint)\n (p-func-b10 uint)\n (p-func-b11 uint)\n (p-func-b12 uint)\n (p-func-b13 uint)\n (p-func-b14 uint)\n (p-func-b15 uint)\n (p-func-b16 uint)\n (p-func-non-alpha-discount uint)\n (p-func-no-vowel-discount uint))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND)))\n (price-function (tuple \n (buckets (list\n p-func-b1\n p-func-b2\n p-func-b3\n p-func-b4\n p-func-b5\n p-func-b6\n p-func-b7\n p-func-b8\n p-func-b9\n p-func-b10\n p-func-b11\n p-func-b12\n p-func-b13\n p-func-b14\n p-func-b15\n p-func-b16))\n (base p-func-base)\n (coeff p-func-coeff)\n (nonalpha-discount p-func-non-alpha-discount)\n (no-vowel-discount p-func-no-vowel-discount))))\n ;; The sender principal must match the namespace\'s import principal\n (asserts!\n (is-eq (get namespace-import namespace-props) tx-sender)\n (err ERR_NAMESPACE_OPERATION_UNAUTHORIZED))\n ;; The namespace price function must still be editable\n (asserts!\n (get can-update-price-function namespace-props)\n (err ERR_NAMESPACE_OPERATION_UNAUTHORIZED))\n (map-set namespaces\n namespace\n (merge namespace-props { price-function: price-function }))\n (ok true)))\n\n;; NAMESPACE_REVOKE_PRICE_EDITION\n(define-public (namespace-revoke-function-price-edition (namespace (buff 20)))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND))))\n ;; The sender principal must match the namespace\'s import principal\n (asserts!\n (is-eq (get namespace-import namespace-props) tx-sender)\n (err ERR_NAMESPACE_OPERATION_UNAUTHORIZED))\n (map-set namespaces\n namespace\n (merge namespace-props { can-update-price-function: false }))\n (ok true)))\n\n;; NAME_PREORDER\n;; This is the first transaction to be sent. It tells all BNS nodes the salted hash of the BNS name,\n;; and it burns the registration fee.\n(define-public (name-preorder (hashed-salted-fqn (buff 20))\n (stx-to-burn uint))\n (let \n ((former-preorder \n (map-get? name-preorders { hashed-salted-fqn: hashed-salted-fqn, buyer: tx-sender })))\n ;; Ensure eventual former pre-order expired \n (asserts! \n (if (is-none former-preorder)\n true\n (>= block-height (+ NAME_PREORDER_CLAIMABILITY_TTL\n (unwrap-panic (get created-at former-preorder)))))\n (err ERR_NAME_PREORDER_ALREADY_EXISTS))\n (asserts! (> stx-to-burn u0) (err ERR_NAMESPACE_STX_BURNT_INSUFFICIENT)) \n ;; Ensure that the hashed fqn is 20 bytes long\n (asserts! (is-eq (len hashed-salted-fqn) u20) (err ERR_NAME_HASH_MALFORMED))\n ;; Ensure that user will be burning a positive amount of tokens\n (asserts! (> stx-to-burn u0) (err ERR_NAME_STX_BURNT_INSUFFICIENT))\n ;; Burn the tokens\n (unwrap! (stx-burn? stx-to-burn tx-sender) (err ERR_INSUFFICIENT_FUNDS))\n ;; Register the pre-order\n (map-set name-preorders\n { hashed-salted-fqn: hashed-salted-fqn, buyer: tx-sender }\n { created-at: block-height, stx-burned: stx-to-burn, claimed: false })\n (ok (+ block-height NAME_PREORDER_CLAIMABILITY_TTL))))\n\n;; NAME_REGISTRATION\n;; This is the second transaction to be sent. It reveals the salt and the name to all BNS nodes,\n;; and assigns the name an initial public key hash and zone file hash\n(define-public (name-register (namespace (buff 20))\n (name (buff 48))\n (salt (buff 20))\n (zonefile-hash (buff 20)))\n (let (\n (hashed-salted-fqn (hash160 (concat (concat (concat name 0x2e) namespace) salt)))\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND)))\n (preorder (unwrap!\n (map-get? name-preorders { hashed-salted-fqn: hashed-salted-fqn, buyer: tx-sender })\n (err ERR_NAME_PREORDER_NOT_FOUND))))\n ;; The name can be registered\n (asserts! (try! (can-name-be-registered namespace name))\n (err ERR_NAME_UNAVAILABLE))\n ;; The preorder must have been created after the launch of the namespace\n (asserts!\n (> (get created-at preorder) (unwrap-panic (get launched-at namespace-props)))\n (err ERR_NAME_PREORDERED_BEFORE_NAMESPACE_LAUNCH))\n ;; The preorder entry must be unclaimed\n (asserts!\n (is-eq (get claimed preorder) false)\n (err ERR_NAME_ALREADY_CLAIMED))\n ;; Less than 24 hours must have passed since the name was preordered\n (asserts!\n (< block-height (+ (get created-at preorder) NAME_PREORDER_CLAIMABILITY_TTL))\n (err ERR_NAME_CLAIMABILITY_EXPIRED))\n ;; The amount burnt must be equal to or greater than the cost of the name\n (asserts!\n (>= (get stx-burned preorder) (compute-name-price name (get price-function namespace-props)))\n (err ERR_NAME_STX_BURNT_INSUFFICIENT))\n ;; Mint the name if new, transfer the name otherwise.\n (try! (mint-or-transfer-name? namespace name tx-sender))\n ;; Update name\'s metadata / properties\n (update-zonefile-and-props\n namespace \n name\n (some block-height)\n none\n none\n zonefile-hash\n \"name-register\")\n (ok true)))\n\n;; NAME_UPDATE\n;; A NAME_UPDATE transaction changes the name\'s zone file hash. You would send one of these transactions \n;; if you wanted to change the name\'s zone file contents. \n;; For example, you would do this if you want to deploy your own Gaia hub and want other people to read from it.\n(define-public (name-update (namespace (buff 20))\n (name (buff 48))\n (zonefile-hash (buff 20)))\n (let (\n (data (try! (check-name-ops-preconditions namespace name))))\n ;; Update the zonefile\n (update-zonefile-and-props\n namespace \n name \n (get registered-at (get name-props data))\n (get imported-at (get name-props data))\n none\n zonefile-hash\n \"name-update\")\n (ok true)))\n\n;; NAME_TRANSFER\n;; A NAME_TRANSFER transaction changes the name\'s public key hash. You would send one of these transactions if you wanted to:\n;; - Change your private key\n;; - Send the name to someone else\n;; When transferring a name, you have the option to also clear the name\'s zone file hash (i.e. set it to null). \n;; This is useful for when you send the name to someone else, so the recipient\'s name does not resolve to your zone file.\n(define-public (name-transfer (namespace (buff 20))\n (name (buff 48))\n (new-owner principal)\n (zonefile-hash (optional (buff 20))))\n (let (\n (data (try! (check-name-ops-preconditions namespace name)))\n (can-new-owner-get-name (try! (can-receive-name new-owner))))\n ;; The new owner does not own a name\n (asserts!\n can-new-owner-get-name\n (err ERR_PRINCIPAL_ALREADY_ASSOCIATED))\n ;; Transfer the name\n (unwrap!\n (update-name-ownership? namespace name tx-sender new-owner)\n (err ERR_NAME_TRANSFER_FAILED))\n ;; Update or clear the zonefile\n (update-zonefile-and-props\n namespace \n name \n (get registered-at (get name-props data))\n (get imported-at (get name-props data))\n none\n (if (is-none zonefile-hash)\n 0x\n (unwrap-panic zonefile-hash))\n \"name-transfer\")\n (ok true)))\n\n;; NAME_REVOKE\n;; A NAME_REVOKE transaction makes a name unresolvable. The BNS consensus rules stipulate that once a name \n;; is revoked, no one can change its public key hash or its zone file hash. \n;; The name\'s zone file hash is set to null to prevent it from resolving.\n;; You should only do this if your private key is compromised, or if you want to render your name unusable for whatever reason.\n(define-public (name-revoke (namespace (buff 20))\n (name (buff 48)))\n (let (\n (data (try! (check-name-ops-preconditions namespace name))))\n ;; Clear the zonefile\n (update-zonefile-and-props\n namespace \n name \n (get registered-at (get name-props data))\n (get imported-at (get name-props data))\n (some block-height)\n 0x\n \"name-revoke\")\n (ok true)))\n\n;; NAME_RENEWAL\n;; Depending in the namespace rules, a name can expire. For example, names in the .id namespace expire after 2 years. \n;; You need to send a NAME_RENEWAL every so often to keep your name.\n;; You will pay the registration cost of your name to the namespace\'s designated burn address when you renew it.\n;; When a name expires, it enters a month-long \"grace period\" (5000 blocks). \n;; It will stop resolving in the grace period, and all of the above operations will cease to be honored by the BNS consensus rules.\n;; You may, however, send a NAME_RENEWAL during this grace period to preserve your name.\n;; If your name is in a namespace where names do not expire, then you never need to use this transaction.\n(define-public (name-renewal (namespace (buff 20))\n (name (buff 48))\n (stx-to-burn uint)\n (new-owner (optional principal))\n (zonefile-hash (optional (buff 20))))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND)))\n (owner (unwrap!\n (nft-get-owner? names { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND))) ;; The name must exist\n (name-props (unwrap!\n (map-get? name-properties { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND)))) ;; The name must exist\n ;; The namespace must be launched\n (asserts!\n (is-some (get launched-at namespace-props))\n (err ERR_NAMESPACE_NOT_LAUNCHED))\n ;; The namespace should require renewals\n (asserts!\n (> (get lifetime namespace-props) u0)\n (err ERR_NAME_OPERATION_UNAUTHORIZED))\n ;; The sender must match the name\'s current owner\n (asserts!\n (is-eq owner tx-sender)\n (err ERR_NAME_OPERATION_UNAUTHORIZED))\n ;; If expired, the name must be in the renewal grace period.\n (if (try! (is-name-lease-expired namespace name))\n (asserts!\n (is-eq (try! (is-name-in-grace-period namespace name)) true)\n (err ERR_NAME_EXPIRED))\n true)\n ;; The amount burnt must be equal to or greater than the cost of the namespace\n (asserts!\n (>= stx-to-burn (compute-name-price name (get price-function namespace-props)))\n (err ERR_NAME_STX_BURNT_INSUFFICIENT))\n ;; The name must not be revoked\n (asserts!\n (is-none (get revoked-at name-props))\n (err ERR_NAME_REVOKED))\n ;; Transfer the name, if any new-owner\n (if (is-none new-owner)\n true \n (try! (can-receive-name (unwrap-panic new-owner))))\n ;; Update the zonefile, if any.\n (if (is-none zonefile-hash)\n (map-set name-properties\n { name: name, namespace: namespace }\n { registered-at: (some block-height),\n imported-at: none,\n revoked-at: none,\n zonefile-hash: (get zonefile-hash name-props) })\n (update-zonefile-and-props\n namespace \n name\n (some block-height)\n none\n none\n (unwrap-panic zonefile-hash)\n \"name-renewal\")) \n (ok true)))\n\n;; Additionals public methods\n\n(define-read-only (get-namespace-price (namespace (buff 20)))\n (let ((namespace-len (len namespace)))\n (asserts!\n (> namespace-len u0)\n (err ERR_NAMESPACE_BLANK))\n (ok (unwrap-panic\n (element-at NAMESPACE_PRICE_TIERS (min u7 (- namespace-len u1)))))))\n\n(define-read-only (get-name-price (namespace (buff 20)) (name (buff 48)))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND))))\n (ok (compute-name-price name (get price-function namespace-props)))))\n\n(define-read-only (check-name-ops-preconditions (namespace (buff 20)) (name (buff 48)))\n (let (\n (owner (unwrap!\n (nft-get-owner? names { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND))) ;; The name must exist\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND)))\n (name-props (unwrap!\n (map-get? name-properties { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND)))) ;; The name must exist\n ;; The namespace must be launched\n (asserts!\n (is-some (get launched-at namespace-props))\n (err ERR_NAMESPACE_NOT_LAUNCHED))\n ;; The sender must match the name\'s current owner\n (asserts!\n (is-eq owner tx-sender)\n (err ERR_NAME_OPERATION_UNAUTHORIZED))\n ;; The name must not be in the renewal grace period\n (asserts!\n (is-eq (try! (is-name-in-grace-period namespace name)) false)\n (err ERR_NAME_GRACE_PERIOD))\n ;; The name must not be expired\n (asserts!\n (is-eq (try! (is-name-lease-expired namespace name)) false)\n (err ERR_NAME_EXPIRED))\n ;; The name must not be revoked\n (asserts!\n (is-none (get revoked-at name-props))\n (err ERR_NAME_REVOKED))\n (ok { namespace-props: namespace-props, name-props: name-props, owner: owner })))\n\n(define-read-only (can-namespace-be-registered (namespace (buff 20)))\n (ok (is-namespace-available namespace)))\n\n(define-read-only (is-name-lease-expired (namespace (buff 20)) (name (buff 48)))\n (let (\n (namespace-props (unwrap! \n (map-get? namespaces namespace) \n (err ERR_NAMESPACE_NOT_FOUND)))\n (name-props (unwrap! \n (map-get? name-properties { name: name, namespace: namespace }) \n (err ERR_NAME_NOT_FOUND)))\n (lease-started-at (try! (name-lease-started-at? (get launched-at namespace-props) (get revealed-at namespace-props) name-props)))\n (lifetime (get lifetime namespace-props)))\n (if (is-eq lifetime u0)\n (ok false)\n (ok (> block-height (+ lifetime lease-started-at))))))\n\n(define-read-only (is-name-in-grace-period (namespace (buff 20)) (name (buff 48)))\n (let (\n (namespace-props (unwrap! \n (map-get? namespaces namespace) \n (err ERR_NAMESPACE_NOT_FOUND)))\n (name-props (unwrap! \n (map-get? name-properties { name: name, namespace: namespace }) \n (err ERR_NAME_NOT_FOUND)))\n (lease-started-at (try! (name-lease-started-at? (get launched-at namespace-props) (get revealed-at namespace-props) name-props)))\n (lifetime (get lifetime namespace-props)))\n (if (is-eq lifetime u0)\n (ok false)\n (ok (and \n (> block-height (+ lifetime lease-started-at)) \n (<= block-height (+ (+ lifetime lease-started-at) NAME_GRACE_PERIOD_DURATION)))))))\n\n(define-read-only (resolve-principal (owner principal))\n (match (map-get? owner-name owner)\n name (match (name-resolve (get namespace name) (get name name))\n resolved-name (ok name)\n error (err {code: error, name: (some name)}))\n (err {code: ERR_NAME_NOT_FOUND, name: none})))\n\n(define-read-only (can-receive-name (owner principal))\n (let ((current-owned-name (map-get? owner-name owner)))\n (if (is-none current-owned-name)\n (ok true)\n (let (\n (namespace (unwrap-panic (get namespace current-owned-name)))\n (name (unwrap-panic (get name current-owned-name))))\n (if (is-namespace-available namespace)\n (ok true)\n (begin\n ;; Early return if lease is expired\n (asserts! \n (not (try! (is-name-lease-expired namespace name)))\n (ok true))\n (let (\n (name-props (unwrap-panic (map-get? name-properties { name: name, namespace: namespace }))))\n ;; Has name been revoked?\n (asserts! (is-some (get revoked-at name-props)) (ok false))\n (ok true))))))))\n\n(define-read-only (can-name-be-registered (namespace (buff 20)) (name (buff 48)))\n (let (\n (wrapped-name-props (map-get? name-properties { name: name, namespace: namespace }))\n (namespace-props (unwrap! (map-get? namespaces namespace) (ok false))))\n ;; The name must only have valid chars\n (asserts!\n (not (has-invalid-chars name))\n (err ERR_NAME_CHARSET_INVALID))\n ;; Ensure that namespace has been launched \n (unwrap! (get launched-at namespace-props) (ok false))\n ;; Early return - Name has never be minted\n (asserts! (is-some (nft-get-owner? names { name: name, namespace: namespace })) (ok true))\n (let ((name-props (unwrap-panic wrapped-name-props)))\n ;; Integrity check - Ensure that the name was either \"imported\" or \"registered\".\n (asserts! (is-eq (xor \n (match (get registered-at name-props) res 1 0)\n (match (get imported-at name-props) res 1 0)) 1) (err ERR_PANIC))\n ;; Is lease expired?\n (is-name-lease-expired namespace name))))\n\n(define-read-only (name-resolve (namespace (buff 20)) (name (buff 48)))\n (let (\n (owner (unwrap!\n (nft-get-owner? names { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND))) ;; The name must exist\n (name-props (unwrap!\n (map-get? name-properties { name: name, namespace: namespace })\n (err ERR_NAME_NOT_FOUND)))\n (namespace-props (unwrap! \n (map-get? namespaces namespace) \n (err ERR_NAMESPACE_NOT_FOUND))))\n ;; The name must not be in grace period\n (asserts!\n (not (try! (is-name-in-grace-period namespace name)))\n (err ERR_NAME_GRACE_PERIOD))\n ;; The name must not be expired\n (asserts! \n (not (try! (is-name-lease-expired namespace name)))\n (err ERR_NAME_EXPIRED))\n ;; The name must not be revoked\n (asserts!\n (is-none (get revoked-at name-props))\n (err ERR_NAME_REVOKED))\n ;; Get the zonefile\n (let (\n (lease-started-at (try! (name-lease-started-at? (get launched-at namespace-props) (get revealed-at namespace-props) name-props))))\n (ok { \n zonefile-hash: (get zonefile-hash name-props), \n owner: owner,\n lease-started-at: lease-started-at,\n lease-ending-at: (if (is-eq (get lifetime namespace-props) u0) none (some (+ lease-started-at (get lifetime namespace-props))))\n }))))\n\n(define-read-only (get-namespace-properties (namespace (buff 20)))\n (let (\n (namespace-props (unwrap!\n (map-get? namespaces namespace)\n (err ERR_NAMESPACE_NOT_FOUND))))\n (ok { namespace: namespace, properties: namespace-props })))\n";