Put an NFT on sale

This page describes the flow in putting an item up for sale on the market.

Flow

Put NFT on Sale - Flow

Put NFT on Sale - Flow

Context

To be able to sell items on the market, Venly takes the item for sale into custody. This means that Venly moves the NFT from the seller's address to a Venly-owned and managed wallet. At the end of a sale, Venly will correctly move the NFT to the buyer's wallet, or return the NFT to the sender's wallet when no sale is made.

To be able to move the NFT (from the seller's wallet, to in custody, to the buyer's wallet), Venly needs approval on the (blockchain) contract. So, before an item can be put on the market, an approval and signature flow needs to be done by the seller.

Detailed Steps

1. Create and configure your offer

In the first step, you create the Offer that you want to put on sale. Use the endpoint:

Request Endpoint: reference

POST /offers

In the offer you have to configure the:

  • The NFT that you want to put on sale
  • The type of the offer: SALE or AUCTION
  • The (starting-)price of the offer
  • (optional) the number of items for sale in case of fungible items
  • (optional) a specific end date
  • (optional) making the offer private (unlisted on the market)

Once created, you will receive an Offer with state NEW (see Offer states for reference).

Example:

Request: Create Offer
POST https://api.venly.market/offers

{
    "type": "SALE",
    "nft":
    {
        "tokenId": "13",
        "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
        "chain": "BSC"
    },
    "sellerAddress": "0x5CF94a2ff1e4B283eb051BB059182F6c32F7D184",
    "privateOffer": false,
    "price": 10,
    "endDate": "2022-09-02T11:40:22.147Z"
}
Response: Create Offer
{
    "success": true,
    "result":
    {
        "id": "1fd99c92-abe4-4ac9-8eac-03233e998768",
        "nft":
        {
            "id": "13",
            "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
            "chain": "BSC",
            "name": "Swordquest House",
            "description": "A fantastic house branded after your favorite Atari game!!",
            "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "url": "https://alphaverse.com/atari/",
            "imagePreviewUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "imageThumbnailUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "animationUrls":
            [],
            "fungible": false,
            "attributes":
            [
                {
                    "type": "system",
                    "name": "tokenTypeId",
                    "value": "13"
                },
                {
                    "type": "property",
                    "name": "maxSupply",
                    "value": "200"
                }
            ],
            "contract":
            {
                "chain": "BSC",
                "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
                "count": 0,
                "name": "AlphaVerse / Atari AlphaVerse",
                "description": "Atari AlphaVerse is a metaverse, part of the AlphaVerse, offering whole experience around the Atari brand.",
                "symbol": "ATAR",
                "url": "https://alphaverse.com/atari/",
                "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png",
                "media":
                [
                    {
                        "type": "image",
                        "value": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png"
                    }
                ],
                "verified": false,
                "premium": false,
                "categories":
                []
            },
            "collectionIdentifier": "3876696d-b953-483c-89ff-ca41f0b2abe9"
        },
        "sellerId": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "sellerNickname": "Unknown",
        "sellerAddress": "0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184",
        "startDate": "2022-06-02T11:43:16.207344Z",
        "endDate": "2022-09-02T11:40:22.147000Z",
        "type": "SALE",
        "status": "NEW",
        "dataToSign": "1fd99c92-abe4-4ac9-8eac-03233e998768_0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184_0xfCAFfcc7d5e04e6CD016357846570095c3595CE3_13",
        "createdOn": "2022-06-02T11:43:16.208429Z",
        "createdBy": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "modifiedOn": "2022-06-02T11:43:16.208429Z",
        "modifiedBy": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "signed": false,
        "currency": "USDC",
        "privateOffer": false,
        "seller":
        {
            "id": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
            "nickname": "Unknown"
        },
        "amountPurchased": 0,
        "amountReimbursed": 0,
        "amountTerminated": 0,
        "price": 10,
        "amount": 1,
        "remainingAmount": 1,
        "minBuyAmount": 1
    }
}

2. Retrieve preparation information

The next step in putting your item on sale is for Venly to take the item into custody. To do this, Venly needs approval on the contract of the NFT. This means that a contract call needs to be done.

There are currently however a lot of different ways to get approval on a collection or NFT. This depends on the NFT-ERC standard, the chain, etc.

They help determine which contract call needs to be done. You can call the Get prepared Approve Tx endpoint. This will give all the information needed to execute the necessary contract call.

Moreover, it will also determine if an actual contract call needs to be executed. Some NFT-contracts allow for meta transactions. A meta-transaction allows Venly to perform the contract call itself. This has an advantage that Venly performs the approval-contract call and pays for the necessary GAS fees. Read more about meta-transactions.

If no meta transaction can be done, it is the user itself that has to execute the approval contract call. This means that the user needs to pay for the GAS fees and therefore also needs to have enough ETH, HBAR, and BSC, ... to execute the approval call.

In summary, the Get prepared Approve TX will return one of the following:

  • signableMessages
    A meta-transaction can be done and Venly will pay the GAS-fee for the approval-transaction. The user only needs to sign a data-object.
  • approvalPreparationTransactions
    The contract of the NFT does not allow meta-transactions. The user therefore has to execute the approval-contract call themselves and pay for the necessary GAS-fees.
  • empty
    An approval on the collection was already given in the past. It does not need to be done again. You can immediately go to step 5

Example:

Request: Prepare Information
GET https://api.venly.market/offers/03262eaa-8817-4785-817f-523359a526c9/preparation/transactions?walletId=:walletId
Response: Prepare information
{
    "success": true,
    "result": {
        "signableMessages": [
            {
                "walletId": "355351bd-41ae-41fa-8f36-12675f056759",
                "secretType": "MATIC",
                "data": {
                    "types": {
                        "MetaTransaction": [
                            {
                                "type": "uint256",
                                "name": "nonce"
                            },
                            {
                                "type": "address",
                                "name": "from"
                            },
                            {
                                "type": "bytes",
                                "name": "functionSignature"
                            }
                        ],
                        "EIP712Domain": [
                            {
                                "type": "string",
                                "name": "name"
                            },
                            {
                                "type": "string",
                                "name": "version"
                            },
                            {
                                "type": "address",
                                "name": "verifyingContract"
                            },
                            {
                                "type": "bytes32",
                                "name": "salt"
                            }
                        ]
                    },
                    "domain": {
                        "name": "Birds 2",
                        "version": "1",
                        "verifyingContract": "0x004ecbb14bc21e988e859dd96e6759ebae085498",
                        "salt": "0x0000000000000000000000000000000000000000000000000000000000013881"
                    },
                    "primaryType": "MetaTransaction",
                    "message": {
                        "nonce": 0,
                        "from": "0xb538acdcf1ded376f44edfeb5cf6a299314ea36a",
                        "functionSignature": "0xa22cb465000000000000000000000000e885A1cD1b67bDC352A113AB2e6A5Fc6C924F8880000000000000000000000000000000000000000000000000000000000000001"
                    }
                }
            }
        ]
    }
}

Since the response contains a signableMessages , in this case a meta transaction is supported.

3. Approve transaction

🚧

Approve transaction only needs to be done when the preparation information returnsapprovalPreparationTransactions as result.

3.1. Execute approval transaction on the contract

The user needs to execute the contract call. To do this one of the following methods can be used:

  • Use the Execute a contract call API:
    • You have to ask the user for its Venly-wallet PIN number, whereafter Venly can execute the call on the user's wallet.
  • Use the Widget to execute the contract call.

3b. Approve the transaction on the market

To move forward, the market also needs to know the parameters of the contract call.

Execute the tx Approval call with the transactionHash you got as response of the execute contract call.

4. Approve meta transaction

🚧

Approve transaction only needs to be done when the preparation information returns signableMessages as result.

4.1 Sign transaction message

In the case of a meta-transaction, no contract call needs to be executed by the user, only a message needs to be signed.

One of the following methods can be used to sign the message:

The message that needs to be signed can be found in the response of the preparation call.

For example, in the response to the preparation call you will find:

"signableMessages": [ { ...} ]

The entire message block needs to be passed into the Signatures API (the content of signableMessages). You now use this information to sign a EIP712 message:

{
    "pincode": 121212,
    "signatureRequest":
    {
        "type": "EIP712",

     ... HERE COMES THE CONTENT OF "SIGNABLEMESSAGES" ...
    
    }
}

4.2 Approve the meta transaction on the market

To move forward, the market also needs to know the parameters of the contract call.

Execute the (meta) tx Approval call with the r , s, v and signature you got as a response of the signature call (Step 4a). Note that for a meta-transaction the signature parameter that you get as the response to the signing step, needs to be transmitted as the functionSignature parameter in the tx-approval step

Example:

Request: Sign meta transaction
POST https://api-wallet.venly.io/api/signatures
(NOTE: this request is being send to WALLET)

{
    "pincode": 1234,
    "signatureRequest":
    {
        "type": "EIP712",
        "walletId": "355351bd-41ae-41fa-8f36-12675f056759",
        "secretType": "MATIC",
        "data":
        {
            "types":
            {
                "MetaTransaction":
                [
                    {
                        "type": "uint256",
                        "name": "nonce"
                    },
                    {
                        "type": "address",
                        "name": "from"
                    },
                    {
                        "type": "bytes",
                        "name": "functionSignature"
                    }
                ],
                "EIP712Domain":
                [
                    {
                        "type": "string",
                        "name": "name"
                    },
                    {
                        "type": "string",
                        "name": "version"
                    },
                    {
                        "type": "address",
                        "name": "verifyingContract"
                    },
                    {
                        "type": "bytes32",
                        "name": "salt"
                    }
                ]
            },
            "domain":
            {
                "name": "Birds 2",
                "version": "1",
                "verifyingContract": "0x004ecbb14bc21e988e859dd96e6759ebae085498",
                "salt": "0x0000000000000000000000000000000000000000000000000000000000013881"
            },
            "primaryType": "MetaTransaction",
            "message":
            {
                "nonce": 0,
                "from": "0xb538acdcf1ded376f44edfeb5cf6a299314ea36a",
                "functionSignature": "0xa22cb465000000000000000000000000e885A1cD1b67bDC352A113AB2e6A5Fc6C924F8880000000000000000000000000000000000000000000000000000000000000001"
            }
        }
    }
}
Response: Sign meta transaction
{
    "success": true,
    "result": {
        "type": "HEX_SIGNATURE",
        "r": "0x753edd7051ecefb548dd7f9efeb4ba5278821df6306889539a05a0e379c78c85",
        "s": "0x34d4e1ded2f5985261b375bafba631188f180e0e1a61c4357064b99948da32b5",
        "v": "0x1b",
        "signature": "0x753edd7051ecefb548dd7f9efeb4ba5278821df6306889539a05a0e379c78c8534d4e1ded2f5985261b375bafba631188f180e0e1a61c4357064b99948da32b51b"
    }
}
Request: Send approval
PUT https://api.venly.market/offers/1fd99c92-abe4-4ac9-8eac-03233e998768/metaTxApprove

{
        "r": "0x753edd7051ecefb548dd7f9efeb4ba5278821df6306889539a05a0e379c78c85",
        "s": "0x34d4e1ded2f5985261b375bafba631188f180e0e1a61c4357064b99948da32b5",
        "v": "0x1b",
        "functionSignature": "0xa22cb465000000000000000000000000e885A1cD1b67bDC352A113AB2e6A5Fc6C924F8880000000000000000000000000000000000000000000000000000000000000001"
}

🚧

Warning: functionSignature should be extracted from the message that was signed, not the signature of the message itself.
See Retrieve Preparation Information -> Response: Prepare information -> result.signableMessages.[].data.message.functionsignature).

Response: Send approval
{
    "success": true,
    "result": {
        "id": "1fd99c92-abe4-4ac9-8eac-03233e998768",
        "nft": {
            "id": "13",
            "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
            "chain": "BSC",
            "name": "Swordquest House",
            "description": "A fantastic house branded after your favorite Atari game!!",
            "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "url": "https://alphaverse.com/atari/",
            "imagePreviewUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "imageThumbnailUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "animationUrls": [],
            "fungible": false,
            "attributes": [
                {
                    "type": "system",
                    "name": "tokenTypeId",
                    "value": "13"
                },
                {
                    "type": "property",
                    "name": "maxSupply",
                    "value": "200"
                }
            ],
            "contract": {
                "chain": "BSC",
                "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
                "count": 0,
                "name": "AlphaVerse / Atari AlphaVerse",
                "description": "Atari AlphaVerse is a metaverse, part of the AlphaVerse, offering whole experience around the Atari brand.",
                "symbol": "ATAR",
                "url": "https://alphaverse.com/atari/",
                "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png",
                "media": [
                    {
                        "type": "image",
                        "value": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png"
                    }
                ],
                "verified": false,
                "premium": false,
                "categories": []
            },
            "collectionIdentifier": "3876696d-b953-483c-89ff-ca41f0b2abe9"
        },
        "sellerId": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "sellerNickname": "Unknown",
        "sellerAddress": "0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184",
        "startDate": "2022-06-02T11:43:16.207344Z",
        "endDate": "2022-09-02T11:40:22.147000Z",
        "type": "SALE",
        "status": "NEW",
        "dataToSign": "1fd99c92-abe4-4ac9-8eac-03233e998768_0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184_0xfCAFfcc7d5e04e6CD016357846570095c3595CE3_13",
        "txApprove": "0xcf02dfb5699b011b8f3e40cf09cd71fc91e496057c4d2944ef640a894102076a",
        "createdOn": "2022-06-02T11:43:16.208429Z",
        "createdBy": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "modifiedOn": "2022-06-02T11:43:16.368041Z",
        "modifiedBy": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
        "signed": false,
        "currency": "USDC",
        "privateOffer": false,
        "seller": {
            "id": "4917b6fa-2657-4bdd-b8e8-fa5dd8bd4057",
            "nickname": "Unknown"
        },
        "amountPurchased": 0,
        "amountReimbursed": 0,
        "amountTerminated": 0,
        "price": 10,
        "amount": 1,
        "remainingAmount": 1,
        "minBuyAmount": 1
    }
}

5. Take NFT into custody

By now, Venly has all the information to take the NFT into custody. However, to be sure that the user is really requesting a specific NFT to be put on sale, an extra signature is needed.

5.1 Sign the offer data

Perform the signature call to sign the Offer.dataToSign data. Or use the Widget to perform this action.

5.2 Send the signature to the offer

Perform the Update offer: signature call to update the Offer and let Venly take the NFT into custody.

The status of the Offer will change to INITIATING_OFFER. When the NFT is taken into custody, the Offer will have status READY and is available on the marketplace!

Example:

Request: Sign
POST https://api-wallet.venly.io/api/signatures

{
    "pincode" : "1234",
    "signatureRequest" : 
    {
        "type": "MESSAGE",
        "walletId": "355351bd-41ae-41fa-8f36-12675f056759",
        "secretType": "MATIC",
        "data" : "1fd99c92-abe4-4ac9-8eac-03233e998768_0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184_0xfCAFfcc7d5e04e6CD016357846570095c3595CE3_13"
    }
}
Response: Sign
{
    "success": true,
    "result": {
        "type": "HEX_SIGNATURE",
        "r": "0x892b531cf8a2e71bb81fb3cc2c572ff6ecd4987c03c522147f69f7443f962239",
        "s": "0x3cb350a2a0884f20675d9882a0c9dd03ff6eb8a0c7b6273b30790378e722c8e6",
        "v": "0x1b",
        "signature": "0x892b531cf8a2e71bb81fb3cc2c572ff6ecd4987c03c522147f69f7443f9622393cb350a2a0884f20675d9882a0c9dd03ff6eb8a0c7b6273b30790378e722c8e61b"
    }
}
Request: place signature (take NFT in custody / on sale)
PATCH https://api.venly.market/offers/1fd99c92-abe4-4ac9-8eac-03233e99876/signature

{
    "signature": "0x155e3b3c7cb444dcaa353c0d0d28765bd2747fb7deeb9d2c0edad3913c4b5c36571baf054f31e2eeb441acf6d8e605b97c6f34916d4f5874a8b01533beaaf8641c"
}
Response: place signature (take NFT in custody / on sale)
{
    "success": true,
    "result": {
        "id": "d8425b4d-319a-4313-80dc-053894820057",
        "nft": {
            "id": "13",
            "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
            "chain": "BSC",
            "name": "Swordquest House",
            "description": "A fantastic house branded after your favorite Atari game!!",
            "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "url": "https://alphaverse.com/atari/",
            "imagePreviewUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "imageThumbnailUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/ATA+4+Swordquest+House.jpg",
            "animationUrls": [],
            "fungible": false,
            "attributes": [
                {
                    "type": "system",
                    "name": "tokenTypeId",
                    "value": "13"
                },
                {
                    "type": "property",
                    "name": "maxSupply",
                    "value": "200"
                }
            ],
            "contract": {
                "chain": "BSC",
                "address": "0x225f099870ea881f2165a475c2696ecb2d21d0c3",
                "count": 0,
                "name": "AlphaVerse / Atari AlphaVerse",
                "description": "Atari AlphaVerse is a metaverse, part of the AlphaVerse, offering whole experience around the Atari brand.",
                "symbol": "ATAR",
                "url": "https://alphaverse.com/atari/",
                "imageUrl": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png",
                "media": [
                    {
                        "type": "image",
                        "value": "https://storage-qa.venly.io/applications/05a51091-54b8-43aa-9c12-142e2b3d9c04/Logo+Atari-AlphaVerse.png"
                    }
                ],
                "verified": false,
                "premium": false,
                "categories": []
            },
            "collectionIdentifier": "3876696d-b953-483c-89ff-ca41f0b2abe9"
        },
        "sellerId": "e38336b6-3307-4737-bf82-3a3a39269147",
        "sellerNickname": "Pieter",
        "sellerAddress": "0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184",
        "startDate": "2022-06-03T15:18:13.992128Z",
        "endDate": "2022-09-02T11:40:22.147000Z",
        "type": "SALE",
        "status": "INITIATING_OFFER",
        "dataToSign": "d8425b4d-319a-4313-80dc-053894820057_0x5cf94a2ff1e4b283eb051bb059182f6c32f7d184_0xfCAFfcc7d5e04e6CD016357846570095c3595CE3_13",
        "createdOn": "2022-06-03T15:18:13.992869Z",
        "createdBy": "e38336b6-3307-4737-bf82-3a3a39269147",
        "modifiedOn": "2022-06-03T15:19:40.208912Z",
        "modifiedBy": "e38336b6-3307-4737-bf82-3a3a39269147",
        "signed": true,
        "currency": "USDC",
        "privateOffer": false,
        "seller": {
            "id": "e38336b6-3307-4737-bf82-3a3a39269147",
            "nickname": "Pieter"
        },
        "amountPurchased": 0,
        "amountReimbursed": 0,
        "amountTerminated": 0,
        "price": 10,
        "amount": 1,
        "remainingAmount": 1,
        "minBuyAmount": 1
    }
}