Put an NFT on sale
This page describes the flow in putting an item up for sale on the market.
The Market API will be discontinued, in Q3 2024 we will be sunsetting this product
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
orAUCTION
- 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 returns
approvalPreparationTransactions
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:
- Use the Signatures API
- Use the Widget
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
}
}
Updated 6 months ago