(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[5396],{57305:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/blogchain/2021/mint-a-marketplace-nfts-on-kadena-marmalade-part-2-2021-12-03",function(){return t(26516)}])},26516:function(e,n,t){"use strict";t.r(n),t.d(n,{__N_SSG:function(){return i}});var s=t(39980),a=t(73274);function _createMdxContent(e){let n=Object.assign({div:"div",h1:"h1",h2:"h2",p:"p",a:"a",strong:"strong",ul:"ul",li:"li",em:"em",img:"img"},(0,a.ah)(),e.components);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.div,{}),"\n",(0,s.jsx)(n.h1,{children:"Mint a Marketplace: NFTs on Kadena Marmalade (Part 2)"}),"\n",(0,s.jsx)(n.h2,{children:"Part 2: Technical Details of the new NFT Standard and Smart Contracts"}),"\n",(0,s.jsxs)(n.p,{children:["In the\n",(0,s.jsx)(n.a,{href:"./mint-a-marketplace-nfts-on-kadena-marmalade-part-1-2021-12-02",children:"previous article"}),",\nwe showed how Kadena ",(0,s.jsx)(n.a,{href:"http://marmalade.art",children:"Marmalade"})," is revolutionizing how\nNFTs are transacted on-chain with multi-step pacts controlling sale, and token\npolicies offering “pluggable” marketplace implementations for creators to choose\nfrom, or write their own! In this article we will go deep into the actual\nstandards and Pact implementations so builders can start minting marketplaces\nright away ",(0,s.jsx)(n.a,{href:"https://kadena-io.github.io/marmalade/",children:"on testnet"}),"!"]}),"\n",(0,s.jsx)(n.h2,{children:"Version 2 of the poly-fungible standard"}),"\n",(0,s.jsxs)(n.p,{children:["Kadena’s initial NFT standard is inspired by ERC-1155, the “multi-token\nstandard” on Ethereum. Like the ERC version, it mainly specifies transfer\noperations and limited metadata (the ",(0,s.jsx)(n.strong,{children:"uri"})," string value).\n",(0,s.jsx)(n.a,{href:"https://github.com/kadena-io/KIPs/pull/20",children:"Version 2"})," turbocharges this with\nthe full Kadena vision of truly decentralized on-chain NFTs:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Haber Content Manifests."})," This replaces ",(0,s.jsx)(n.strong,{children:"uri"})," with cryptographically\nverifiable on-chain data, employing elements of Stuart Haber’s Content\nIntegrity designs. This can be anything from a simple Data URI or DID\n(Decentralized Identifier) to any structured data, including image or document\ndata on-chain!"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"“t:” Token Identifiers."})," These incorporate the Content Manifest hash to\nmake a token ID that cryptographically identifies the actual NFT. No more\nrandom addresses and duplicate NFTs!"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"The “sale” pact."})," As introduced in the last article, this is the\ntwo-step-with-rollback trustless escrow sale pact that enables policy-driven\nmarkets. No more exchange lock-in!"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Token policy specification."})," The “pluggable” logic that makes it possible\nfor creators to specify every last detail of issuance, transfer and sale.\nPolicies are how you “mint a marketplace”."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{children:"Understanding the “sale” trustless-escrow pact"}),"\n",(0,s.jsx)(n.p,{children:"Pacts in Kadena define a multi-step operation. They are used to handle\ncross-chain transfers and, behind the scenes, even handle the automatic gas\npurchase->redeem process on the Kadena blockchain!"}),"\n",(0,s.jsxs)(n.p,{children:["In the sale pact, two steps are specified: **offer **and **buy. **The offer\noperation also has a “rollback step” that allows the seller to **withdraw **the\nsale. The sale pact uses a special feature of pacts, “pact guards”, to govern\nthe ",(0,s.jsx)(n.em,{children:"trustless escrow"})," of the NFT sale. Once an asset is transferred to an\naccount governed by a pact guard, only that particular execution of the pact, as\nidentified by its “pact ID”, has the right to manage that asset in subsequent\nsteps."]}),"\n",(0,s.jsx)(n.p,{children:"Note that a sale can only occur after token creation and minting. A sale is how\nan existing NFT token that is owned by a “seller” finds a “buyer” who, upon\nsuccess, will receive the token."}),"\n",(0,s.jsx)(n.h2,{children:"Step 1: Offer"}),"\n",(0,s.jsx)(n.img,{src:"/assets/blog/0_lOGA7REb1MsdjAQX.png",alt:"Example of an “offer” step. Bob has offered to sell NFT1, which transfers the NFT to the escrow account associated with the sale ID. The NFT uses a token policy that allows quoting a coin price, so Bob quotes 50 KDA."}),"\n",(0,s.jsx)(n.p,{children:"The first step of the sale pact **offers the NFT for sale. **This step handles\nthe transfer of the NFT into the escrow account, and the fresh Pact ID assigned\nto the particular sale execution is considered the “sale ID” in the SALE event\nthat gets emitted."}),"\n",(0,s.jsx)(n.p,{children:"It’s important that the NFT be escrowed for sale, as it commits the seller to\n“play by the rules.” This allows buyers to pay (or bid) with confidence that the\nseller can’t rug-pull the NFT between offer and purchase or other shady\nbusiness. By initiating the sale, **the seller actually loses custody of the\ntoken **unless the buyer does not materialize, at which point the seller can\nroll back the sale with the **withdraw **process described below."}),"\n",(0,s.jsx)(n.p,{children:"The token policy is responsible for any specific behavior needed, as specified\nin the **init-sale **operation. The sale pact itself does nothing other than\nescrowing the pact and capturing a timeout value. Policies would here quote a\nprice in some coin, or enforce a floor price: whatever is needed for the\nparticular marketplace."}),"\n",(0,s.jsx)(n.h2,{children:"Step 2: Buy"}),"\n",(0,s.jsx)(n.img,{src:"/assets/blog/0_vzGX8d_AGRxODoZN.png",alt:"Example of an “buy” step. Alice sends a continuation of the sale:1 pact in order to transfer the NFT out of escrow to Alice’s NFT account. The NFT token policy first debits the sale price of 50.0 from Alice’s KDA account to credit Bob."}),"\n",(0,s.jsx)(n.p,{children:"If a buyer wants to acquire the token offered in the first step, they send a\n**continuation message **of the Pact ID (or “sale ID”) initiated in the first\nstep into the blockchain. Buyer recipient data for the token is specified in the\nmessage payload in the **buyer **and **buyer-guard **fields."}),"\n",(0,s.jsx)(n.p,{children:"At this point, the token policy is responsible for enacting whatever offsetting\ntransaction is needed to allow the release of the escrowed NFT to the buyer, in\nthe **enforce-sale **operation. While the sale pact handles transferring the NFT\nout of escrow (and enforcing the timeout), everything else is “pluggable”, be\nthat an offsetting coin transfer, royalty redemption, or whatever you can\nimagine!"}),"\n",(0,s.jsx)(n.h2,{children:"Step 1 Rollback: Withdraw"}),"\n",(0,s.jsx)(n.p,{children:"The timeout captured in the **offer **step allows a sender to withdraw from the\nsale if nobody shows up to buy the token. The timeout is measured in blocks,\nsuch that if a seller sets the timeout to 30 blocks, they cannot pull out of the\nsale until 30 blocks have been mined on-chain."}),"\n",(0,s.jsx)(n.p,{children:"Once the timeout has passed, the seller (or anybody, as the only authority\ngoverning the rollback is the Pact code itself) sends a special “rollback”\ncontinuation message for the sale ID. The **withdraw **operation simply\ntransfers the token out of the escrow account back to the seller."}),"\n",(0,s.jsxs)(n.p,{children:["Note that all of the logic surrounding the step-wise operation of the sale pact\nis automatically handled by the Pact language itself (and the blockchain hosting\nit). This ensures that step 2 can only happen after step 1, and only if step 1\nhas not been rolled back, and only if step 2 has not already happened; likewise\na rollback can’t occur if step 1 hasn’t happened, or if step 2 has already\nhappened. As you can see, left to programmers this would inevitably result in\nnumerous bugs. Instead with Pact it’s ",(0,s.jsx)(n.strong,{children:"impossible to have a bug in the\nsequencing logic."})]}),"\n",(0,s.jsx)(n.h2,{children:"Token Policies"}),"\n",(0,s.jsxs)(n.p,{children:["The sale pact is the critical piece of logic that powers mintable marketplaces,\nsince it introduces a fully autonomous and enforceable way to offer tokens for\nsale within the standard. However, the ",(0,s.jsx)(n.strong,{children:"token policy"})," handles critical aspects\nof the sale, such as how does money change hands? How might a royalty be\nimplemented? And also, doesn’t ",(0,s.jsx)(n.strong,{children:"transfer"})," still undermine everything?"]}),"\n",(0,s.jsx)(n.p,{children:"Token policies don’t just govern sales, but transfer, minting, and burning as\nwell. This is necessary to make a truly enforceable token policy:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Creation."})," The token policy is invoked when a token is created (this is\ndistinct from minting, which actually establishes ownership of the NFT). This\nis where something like a royalty rate or other “permanent” data would be\ncaptured."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Minting."})," One thing about ERC-1155 (and poly-fungible-v1 too) is the lack\nof a way to lock down issuance. With the minting policy, a token can declare\nitself to be a true 1-of-1, or limited series, or a fully fungible coin."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Burning."})," Burning is already a head-scratcher for NFTs, but can obviously\nmake sense for fungible coins. Burn policies allow prevention of burns in\n1-of-1 and limited-series NFTs, as well as other rules a creator may desire."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Transfer."})," Transfer can finally be tamed with the transfer policy! For most\nNFTs it gets banned altogether, but it also serves other use cases like\ntransfer restrictions, minimum or maximum order sizes, etc."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Sale."})," Sale policies have separate operations for the offer and buy steps\nof the sale pact. Offer is where you might quote a price, and buy is where an\noffsetting transaction can be executed."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{children:"Example: a “Fixed Quote Royalty” policy"}),"\n",(0,s.jsx)(n.p,{children:"To give a simple but powerful example of policies in action, let’s consider a\ncreator offering a token that implements a policy that enforces scarcity,\nrequires sales for transfer, and pays a royalty."}),"\n",(0,s.jsx)(n.img,{src:"/assets/blog/0_-eWnPctZqoX1I1Gv.png",alt:"Creator “Carol” creates NFT7, a 1-of-1 with a 5% royalty, and mints it to herself."}),"\n",(0,s.jsxs)(n.p,{children:["In token ",(0,s.jsx)(n.strong,{children:"creation"}),", a ",(0,s.jsx)(n.strong,{children:"fixed max supply"})," is captured, which along with the\nstandard notion of ",(0,s.jsx)(n.strong,{children:"precision,"})," allows creating a true 1-for-1 NFT (supply\n1.0, precision 0), a limited series of say 5 (supply 5.0, precision 0), or any\nfixed issuance."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Minting"})," enforces the max supply (precision is automatically enforced in the\nledger), to prevent minting once the max supply is reached. For a 1-of-1 this\nwould allow a single mint only. ",(0,s.jsx)(n.strong,{children:"Burning is prohibited"})," altogether."]}),"\n",(0,s.jsx)(n.img,{src:"/assets/blog/0_ccqAMUoU0CfHj2Sx.png",alt:"The current owner of NFT7, “Bob”, initiates a sale, quoting a price of 100 KDA. NFT7 is transferred to the trustless escrow account for the sale ID <s17>"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.strong,{children:"sale"})," ",(0,s.jsx)(n.strong,{children:"initiation"})," policy requires the seller to quote a price in some\ncoin. This puts the NFT into the trustless escrow. ",(0,s.jsx)(n.strong,{children:"Transfer is prohibited\naltogether"})," to prevent offline sales without royalty enforcement."]}),"\n",(0,s.jsx)(n.img,{src:"/assets/blog/0_cDJKu9bnL-K9TR_f.png",alt:"“Alice” pays the 100.0 KDA to receive NFT7 from the trustless escrow, with 95.0 going to Bob, and 5.0 going to Carol."}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.strong,{children:"sale completion"})," policy computes the royalty from the quoted price,\ntransfers the royalty to the creator, and the balance to the seller, before\nreleasing the escrowed token to the buyer."]}),"\n",(0,s.jsxs)(n.p,{children:["Note that ",(0,s.jsx)(n.strong,{children:"all sales going forward have to respect this process."})," The buyer\ncan only resell using the exact same quoting process and royalty, with no\npossibility of back-handed transfers behind the scenes."]}),"\n",(0,s.jsx)(n.h2,{children:"Conclusion: An Open Standard for Token Sales"}),"\n",(0,s.jsxs)(n.p,{children:["Finally, NFTs can have rich on-chain metadata, verifiable IDs, and a true sale\nprocess for enforcing a policy-driven marketplace. Check out the\n",(0,s.jsx)(n.a,{href:"https://github.com/kadena-io/KIPs/pull/20",children:"KIP-0013"})," proposal where we’re\nhammering out the new standard, and come check out our smart contracts\n",(0,s.jsx)(n.a,{href:"https://kadena-io.github.io/marmalade/",children:"on testnet"})," and\n",(0,s.jsx)(n.a,{href:"https://github.com/kadena-io/hft",children:"on Github"})," to see how you can “mint a\nmarketplace” and drive innovation in NFTs on Kadena!"]}),"\n",(0,s.jsx)(n.div,{}),"\n",(0,s.jsx)(n.div,{})]})}var i=!0;n.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:n}=Object.assign({},(0,a.ah)(),e.components);return n?(0,s.jsx)(n,Object.assign({},e,{children:(0,s.jsx)(_createMdxContent,e)})):_createMdxContent(e)}}},function(e){e.O(0,[9774,2888,179],function(){return e(e.s=57305)}),_N_E=e.O()}]);