Primary Sale

Creating new tokens on chain during a sale

πŸ”­ Guide Overview

In this guide you will create a sell order for an item that is not already on chain. The idea is that when the item finds a buyer who submits a buy order, the item will be minted on chain as well as transferred to the buyer in a single transaction. This helps save minting cost by only minting items that are bought. See here for further explanation ↗️. You will need to create a client ↗️ unless you have already done that.

🏷️ Use-case Examples

  • Sale of a new collectible series on your platform
  • Purchase of limited edition battle pass on your platform
  • and many more... think of all the mint pages that can be created, this allows you to do that

πŸ—ΊοΈ Implementation Overview

  • We first deploy contract that is ERC-1155 which holds both the FT and NFT tokens
  • Then we create a FT token metadata and send to the buyer wallet
  • Create the NFT metadata which will be sold

This prepares the tokens for the primary sale

  • To start the sale, you will send a call with X-API-KEY (probably from your backend) to start the sale
  • Finally make the buy order for the NFT from the buyer wallet

🧱 Implementation Steps

  1. Client X-API-KEY: Get the client x-api-key to be used in the following steps
  2. Deploy contract: We need to first deploy a contract which will hold the ERC1155 tokens. Choose chain mumbai and type OpenGlipERC1155. We will support the others soon.

The above API with an example, see the API reference ↗️ for code snippet in lots of languages and more information about the API and the metadata (name, symbol, description...)

Request

> curl --request POST \
     --url https://be.namasteapis.com/blockchain/v1/contract/create \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'x-api-key: TheCompanyAPIkey' \
     --data '
{
     "name": "SomeName",
     "symbol": "SomeSymbol",
     "description": "SomeDescription",
     "chain": "mumbai",
     "image": "someimageurl.jpeg",
     "externalUrl": "someimageurl.jpeg",
     "type": "OpenGlipERC1155"
}
'

Response

{
  "data": {
    "confirmed": true,
    "id": "62a38b9b08992327f2634b00",
    "name": "SomeName",
    "description": "SomeDescription",
    "chain": "mumbai",
    "image": "someimageurl.jpeg",
    "externalUrl": "someimageurl.jpeg",
    "media": [
      {
        "type": "number",
        "value": "1"
      }
    ],
    "type": "OpenGlipERC1155",
    "contractAddress": "0xe9F3a256Beda25e4a30Cc65C61B108D74791A103",
    "transactionHash": "0x5e3bd8135074fd594582ed70878d1222e53dd9242e1ba60e4d14fe7da7611944",
    "deployer": "0xF1b6fceac6784a26360056973C41e0017DeE12e4",
    "factory": "0x0405aA9fef3986fd56470107D38f2a554E1856fa",
    "creatorId": "62335548760f50d618bc7b35",
    "owner": "0xF1b6fceac6784a26360056973C41e0017DeE12e4",
  },
  "success": true,
  "message": "Contract created"
}

You can try it yourself 😎 here!

  1. Create & send FT to buyer wallet: To buy the NFT on primary sale the buyer must first have some FTs. We will create the token metadata for the FT and send some FTs to the wallet before we start with the NFT creation steps. In this example the FT will be a token in the same contract, however any other contract will also work. Follow the Guide to Create & send FT to see in detail ↗️. Here we will cover only the steps required.
    1. Create the token metadata for FT in the same contract: Use the id from the above as your contractDataId. In this case it is 62a38b9b08992327f2634b00 and use the following API, see API Reference ↗️ for more languages snippets. Since, ERC1155 combines both fungible and non-fungible types, just setting the supply to any number greater than 1 would make that token id a FT. We will set it to 1000 on line #16 in the example below.

      πŸ“˜

      Token Metadata - Rich Properties of NFTs

      Attributes help attach rich features/properties to the NFTs. They may signify scores, levels, traits, history, evolution of the NFT. Investors factor in attributes while pricing the token while gamers value the attributes because they may unlock features in a game.

      Croak allows 2 ways to set metadata - hosted by Croak or self-hosted.
      More details in the Guide here ↗️

    > curl --request POST \
         --url https://be.namasteapis.com/blockchain/v1/token-data/create \
         --header 'Accept: application/json' \
         --header 'Content-Type: application/json' \
         --header 'x-api-key: TheCompanyAPIkey' \
         --data '
    {
         "metadata": {
              "name": "SomeName",
              "description": "SomeDescription",
              "image": "SomeImage.jpeg",
              "external_url": "SomeWebsite.com",
              "animation_url": "SomeVideo.mp4",
              "attributes": "[]"
         },
         "supply": 1000,
         "assetContractId": "62a38b9b08992327f2634b00"
    }
    '
    Truncated response
    {
      "data": {
        "id": "62a38cb708992327f2634b36",
        "creatorId": "62335548760f50d618bc7b35",
        "type": "ERC1155_LAZY",
        "name": "SomeName",
        "description": "SomeDescription",
        "externalUri": "SomeWebsite.com",
        "imageUri": "SomeImage.jpeg",
        "videoUri": "SomeVideo.mp4",
        "attributes": "[]",
        "supply": 1,
        "reserveTokenDataId": "62a369c43a45893dcf7bae66",
        "reserveTokenDataAmount": 10,
        "assetContractId": "62a38b9b08992327f2634b00",
        "tokenId": "50773715742106732018698306139051929138629421045594680327232414164177859221168",
      },
      "success": true,
      "message": "Token data saved"
    }
    
    You can try it yourself 😎 here!

ii. Send FT to buyer wallet: Pick the id of the metadata from the response above; this is your tokenDataId - 62a38cb708992327f2634b36 in this example. Get the walletId of the user to send the token to, 627cb7ea2cd263018f2adfb7 in this example. We will send 500 out of the 1000 maximum supply to the wallet by setting amount to 500 on line #12 in the code below. Use the api to send the token to any wallet id. See API Reference for code snippets in more languages ↗️

> curl --request POST \
     --url https://be.namasteapis.com/blockchain/v1/airdrop/token-data \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'x-api-key: TheCompanyAPIkey' \
     --data '
{
     "destinations": [
          "627cb7ea2cd263018f2adfb7"
     ],
     "amounts": [
          500
     ],
     "tokenDataId": "62a38cb708992327f2634b36"
}
'


{
  "data": [
    {
      "amount": 1,
      "status": "success",
      "cancelled": false,
      "isClaimed": false,
      "_id": "62a38d5108992327f2634b56",
      "creatorId": "62335548760f50d618bc7b35",
      "tokenDataId": "62a38cb708992327f2634b36",
      "error": "",
      "exchangeContract": "0x3B2A17fd2c4C3Bb968Efa91ae63AAfe8A7c5E69E",
      "mintSaleType": "airdrop",
      "minted": true,
      "mintTxId": "0xef096055f6f59bead13bb247701b2af22ec86b3acf37e058c46c5683775d705b",
      "mintTxStatus": "done",
      "mintedAt": "2022-06-10T18:28:33.190Z",
      "mintedPrice": "0",
      "mintedCurrency": "USD",
      "mintedTo": "0x8E8132a63EeD858CB8ABB3b7D0Bd3c4DF9E1B6bd",
      "walletId": "627cb7ea2cd263018f2adfb7",
      "id": "62a38d5108992327f2634b56"
    }
  ],
  "success": true,
  "message": "Token minting started"
}

You can try it yourself 😎 here!

Now that we've sent some FT to a wallet we'll proceed with creating the NFT metadata and starting a sale order on it.

  1. Create the NFT Metadata: Use the id from Step 2 as your contractDataId. In this case it is 62a38b9b08992327f2634b00. Create the token metadata using the following API, see API Reference ↗️ for more languages snippets and details on each field.

πŸ“˜

Reserve Token Price

See line #17 and #18 in the code below.

A reserve price or a reservation price is the minimum amount that a seller will accept as the winning bid. Alternatively, it is less commonly known as the highest price a buyer is willing to pay for a good or service. The reserve price prevents a bidder who offers a price lower than what the owner will accept from winning the auction.

In the following request it is specified by reserveTokenDataId and reserveTokenDataAmount respectively. Set them to be the tokenDataId of the FT token metadata created in Step 3.i above. And set the reserveTokenDataAmount to be any number between 0 and 500.

The reserve token data is the minimum selling price of the token. You may create multiple sell orders at prices above this selling price for the same token.

To know the textbook definition of Reserve Price see this link ↗️

> curl --request POST \
     --url https://be.namasteapis.com/blockchain/v1/token-data/create \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'x-api-key: TheCompanyAPIkey' \
     --data '
{
     "metadata": {
          "name": "SomeName",
          "description": "SomeDescription",
          "image": "SomeImage.jpeg",
          "external_url": "SomeWebsite.com",
          "animation_url": "SomeVideo.mp4",
          "attributes": "[]"
     },
     "supply": 1,
     "reserveTokenDataId": "62a38d5108992327f2634b56",
     "reserveTokenDataAmount": 10,
     "assetContractId": "62a38b9b08992327f2634b00"
}
'
# Response
{
  "data": {
    "id": "62a38cb708992327f2634b36",
    "creatorId": "62335548760f50d618bc7b35",
    "type": "ERC1155_LAZY",
    "name": "SomeName",
    "description": "SomeDescription",
    "externalUri": "SomeWebsite.com",
    "imageUri": "SomeImage.jpeg",
    "videoUri": "SomeVideo.mp4",
    "attributes": "[]",
    "supply": 1,
    "reserveTokenDataId": "62a369c43a45893dcf7bae66",
    "reserveTokenDataAmount": 10,
    "assetContractId": "62a38b9b08992327f2634b00",
    "tokenId": "50773715742106732018698306139051929138629421045594680327232414164177859221168",
  },
  "success": true,
  "message": "Token data saved"
}

You can try it yourself 😎 here!

  1. Initiate a sell order : Now that you have created the token metadata and added the reserve price information, all that is left is to create a sell order on the NFT token metadata from Step 4. You can make the following API call to make the sell order, see API Reference ↗️ for more languages snippets and details on each field.

πŸ“˜

takeAmount: It is the price at which you want to make the sale at

> curl --request POST \
     --url https://be.namasteapis.com/blockchain/v1/market/create-mint-sell-order \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'x-api-key: Your API Key' \
     --data '
{
     "tokenDataId": "62a38cb708992327f2634b36",
     "takeAmount": 1000
}
'


{
  "data": {
    "id": "62dee9cd908167125627a033",
    "form": "{\"types\":{\"AssetType\":[{\"name\":\"assetClass\",\"type\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"Asset\":[{\"name\":\"assetType\",\"type\":\"AssetType\"},{\"name\":\"value\",\"type\":\"uint256\"}],\"Order\":[{\"name\":\"maker\",\"type\":\"address\"},{\"name\":\"makeAsset\",\"type\":\"Asset\"},{\"name\":\"taker\",\"type\":\"address\"},{\"name\":\"takeAsset\",\"type\":\"Asset\"},{\"name\":\"salt\",\"type\":\"uint256\"},{\"name\":\"start\",\"type\":\"uint256\"},{\"name\":\"end\",\"type\":\"uint256\"},{\"name\":\"dataType\",\"type\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\"}]},\"domain\":{\"name\":\"Exchange\",\"version\":\"1\",\"chainId\":\"80001\",\"verifyingContract\":\"0x2D0f4752B7016A28D3D7F7d42DF31A67ddCd2b78\"},\"primaryType\":\"Order\",\"message\":{\"maker\":\"0x32b475c0c634f664948a5479e9e6b5820423765b\",\"makeAsset\":{\"assetType\":{\"assetClass\":\"0x1cdfaa40\",\"data\":\"0x0000000000000000000000006608f7d00c3334dc7fef8515c00dec23c3f02551000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003000000000000000000000000006608f7d00c3334dc7fef8515c00dec23c3f02551000000000000000000000000000000000000000000000000000000000000004037ddb6dcc56da43f7024806313cebb4a8fbdbae20b668575041769e2c4c9f6dc000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000648ae85d8400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000005f7b5f16ae63b0f5c7b0df63e6142c9c7e0c152400000000000000000000000000000000000000000000000000000000000000010000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000041066fdfcb69251755c53ac9547630dee4fce46df93ed6465e99cbc15bde5e508e68450f2ff3fc294b8a551653f09130a72b14f3bc17a6ca85c2c98ea27a533f001c00000000000000000000000000000000000000000000000000000000000000\"},\"value\":1},\"taker\":\"0x0000000000000000000000000000000000000000\",\"takeAsset\":{\"assetType\":{\"assetClass\":\"0x8ae85d84\",\"data\":\"0x0000000000000000000000005f7b5f16ae63b0f5c7b0df63e6142c9c7e0c1524\"},\"value\":1000},\"salt\":\"30529624354371180003297373560005209747611623465446485703643482904121408893079\",\"start\":0,\"end\":0,\"dataType\":\"0x4c234266\",\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b0000000000000000000000000000000000000000000000000000000000000000\"}}"
  },
  "success": true,
  "message": "Mint sell order created!"
}

You can try it yourself 😎 here!

  1. Check the sale order created : Ensure that the sell order is created and recorded in the system. You can make the following API call see API Reference ↗️ for more languages snippets and details on each field. You can save the id of the sell order recieved.
> curl --request GET \
     --url 'https://be.namasteapis.com/blockchain/v1/market/list-sell-orders?size=50' \
     --header 'Accept: application/json' \
     --header 'x-api-key: test_key.U6ZnqkIv7~piiqElYkyO'
     

{
  "data": {
    "sellOrders": [
      {
        "type": "MINT_DIRECT_SALE",
        "status": "SIGNED",
        "id": "62dee9cd908167125627a033",
        "makerWalletId": "62de50119081671256277625",
        "makerWalletType": "CUSTODIAL",
        "takerWalletId": "62de50119081671256277625",
        "takerWalletType": "CUSTODIAL",
        "makeTokenDataId": "62dee93a908167125627a01b",
        "takeTokenDataId": "62de50159081671256277629",
        "companyId": "62de50119081671256277626",
        "makeAmount": 1,
        "takeAmount": 1000,
        "form": {
          "types": {
            "AssetType": [
              {
                "name": "assetClass",
                "type": "bytes4"
              },
              {
                "name": "data",
                "type": "bytes"
              }
            ],
            "Asset": [
              {
                "name": "assetType",
                "type": "AssetType"
              },
              {
                "name": "value",
                "type": "uint256"
              }
            ],
            "Order": [
              {
                "name": "maker",
                "type": "address"
              },
              {
                "name": "makeAsset",
                "type": "Asset"
              },
              {
                "name": "taker",
                "type": "address"
              },
              {
                "name": "takeAsset",
                "type": "Asset"
              },
              {
                "name": "salt",
                "type": "uint256"
              },
              {
                "name": "start",
                "type": "uint256"
              },
              {
                "name": "end",
                "type": "uint256"
              },
              {
                "name": "dataType",
                "type": "bytes4"
              },
              {
                "name": "data",
                "type": "bytes"
              }
            ]
          },
          "domain": {
            "name": "Exchange",
            "version": "1",
            "chainId": "80001",
            "verifyingContract": "0x2D0f4752B7016A28D3D7F7d42DF31A67ddCd2b78"
          },
          "primaryType": "Order",
          "message": {
            "maker": "0x32b475c0c634f664948a5479e9e6b5820423765b",
            "makeAsset": {
              "assetType": {
                "assetClass": "0x1cdfaa40",
                "data": "0x0000000000000000000000006608f7d00c3334dc7fef8515c00dec23c3f02551000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003000000000000000000000000006608f7d00c3334dc7fef8515c00dec23c3f02551000000000000000000000000000000000000000000000000000000000000004037ddb6dcc56da43f7024806313cebb4a8fbdbae20b668575041769e2c4c9f6dc000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000648ae85d8400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000005f7b5f16ae63b0f5c7b0df63e6142c9c7e0c152400000000000000000000000000000000000000000000000000000000000000010000000000000000000000008e8132a63eed858cb8abb3b7d0bd3c4df9e1b6bd00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000041066fdfcb69251755c53ac9547630dee4fce46df93ed6465e99cbc15bde5e508e68450f2ff3fc294b8a551653f09130a72b14f3bc17a6ca85c2c98ea27a533f001c00000000000000000000000000000000000000000000000000000000000000"
              },
              "value": 1
            },
            "taker": "0x0000000000000000000000000000000000000000",
            "takeAsset": {
              "assetType": {
                "assetClass": "0x8ae85d84",
                "data": "0x0000000000000000000000005f7b5f16ae63b0f5c7b0df63e6142c9c7e0c1524"
              },
              "value": 1000
            },
            "salt": "30529624354371180003297373560005209747611623465446485703643482904121408893079",
            "start": 0,
            "end": 0,
            "dataType": "0x4c234266",
            "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000000100000000000000000000000032b475c0c634f664948a5479e9e6b5820423765b0000000000000000000000000000000000000000000000000000000000000000"
          }
        },
        "startTime": 0,
        "endTime": 0,
        "createdAt": "2022-07-25T19:06:53.533Z",
        "updatedAt": "2022-07-25T19:06:53.589Z",
        "__v": 0,
        "signature": "0xe89af133d9f6a0bba9d42a8277a3972e8aae4bcb073bb1723c2033a60baffd38106d5186c96f20a876da1a5185a0137e10a4cc970f5d7fa5e98eb50dd2dd38591b",
        "id": "62dee9cd908167125627a033"
      }
    ],
    "lastId": "62dee9c4908167125627a030"
  },
  "success": true,
  "message": "SellOrders"
}

You can try it yourself 😎 here!

  1. Make the Buy order from the buyer wallet : Login with the buyer wallet (social login) using the following code. The sellOrderId can be used from above response (eg. 62dee9cd908167125627a033).
// Buy function exposed by the croak wallet
/**
 * `buyNFT` is a function that takes in a sell order ID, a maker token data ID, a maker amount, a
 * taker token data ID, and a taker amount, and then uses the `buyNFTBackend` function to buy the
 * NFT
 * @param {any} sellOrderId - The sell order id that you want to buy from.
 * @param {any} makeTokenDataId - The ID of the NFT you want to offer. 
 * @param {any} makeAmount - The amount of the NFT you want to offer.
 * @param {any} takeTokenDataId - The id of the NFT you want to buy.
 * @param {any} takeAmount - The amount of the token you want to buy.
 */
await glipAuthGlobal.buyNFT(
  "62dee9cd908167125627a033",
  "62a38cb708992327f2634b36", 500, 
  "62a369c43a45893dcf7bae66", 1);

  1. That's it you're done 🏁

πŸ“Œ Code example and further queries

For any queries or guidance, join https://croak.discord.com or write to [email protected]