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";