List an NFT on Polygon
The following tutorial is done in Python.
Step 1: Define parameters
import time
import json
import requests
# Reach out to us for a token: https://forms.gle/VyCZPCBi4ECVQJ4U8
api_token = "ask-us-for-a-token"
# Maker is willing to sell #200 of 0xc9F07b9B359fA16e1af9df6fAC5540FbDa658e8E for 10 MATIC
maker_address = "0x487bFB4e3A69cf34adddA893EEC6fDdEF19aDAfA"
nft_address = "0xeC6F34d2052D9Da956295F0Bf8034b2B900C9D54"
nft_id = "200"
# Purchase price is 10 MATIC (MATIC has 18 decimals)
purchase_price = str(int(10 * 1e18))
# Expires in 1 hour
expiry_epoch = int(time.time() + 3600)
# TODO: add real API domain below.
acilia_api_domain = "api.acilia.llc"
Step 2: Request listing call-data
payload = json.dumps({
"chain": "POLYGON",
"maker": {
"type": "ERC721",
"owner": maker_address,
"tokenId": nft_id,
"tokenAddress": nft_address
},
"taker": {
"type": "NATIVE",
"baseUnitAmount": purchase_price,
},
"timeout": {
"type": "ABSOLUTE",
"value": expiry_epoch
}
})
headers = {
'Authorization': f'Bearer {api_token}',
'Content-Type': 'application/json'
}
response = requests.request(
"POST",
f"https://{acilia_api_domain}/v1/order/list",
headers=headers,
data=payload
)
response = response.json()
Let's look at the data coming back from the API. Inline is an explanation of each field:
{
// The `uid` field is a unique identifier for the Acilia API. You can use this UID field to load this same order
// back into the API and generate useful calldata for the taker
"aciliaId": "85LbktFBFtSyuQgaeE5gtoexjW33ysnuPdkYbLwzxJfaZew6mZxgf3JKXcNJvegNQHaBJZcvEHfmHSAbCGjKGKktwyEJDp3W5DfFPQdU2F4pzyzdzPDEsNFkNhJr2cVzBseagap4gzPe6G1zsUYzNpKXKbMEqXFbEyQpiScGcCFu8n19w5sm2A9os1AQ3e9FdFKMnC6DnFbSv7XYtZUoY3igYHmhpXTAZ92qFDdh8nqAhYu6NcPo9jpiJj3ojw2zoQEKXz4cMVsGai8iSDGDM1a",
// The order field is the NFT V4 order generated by the API. See more here:
// https://protocol.0x.org/en/latest/basics/orders.html#erc721-orders
"order": {
"direction": "SELL",
"chain": "POLYGON",
"maker": "0x487bFB4e3A69cf34adddA893EEC6fDdEF19aDAfA",
"taker": "0x0000000000000000000000000000000000000000",
"erc721TokenId": "2",
"erc721Token": "0xeC6F34d2052D9Da956295F0Bf8034b2B900C9D54",
"fees": [],
"status": "FILLABLE",
"erc20Token": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"erc20TokenAmount": "20000000000000000000",
"hash": "0x1216a1e07abfcbc223bdbc17c86dd770ef03f196599b4e830d57f756380239e8",
"expiry": "1846785190",
"nonce": "100131415900000000000000000000000000000108258336074355952321641756238660820183"
},
// Below are a list of transactions that are to be sent by the maker in order
// to list this NFT on-chain.
// Step 1 is SET_ALLOWANCE: allows the 0x protocol to swap NFTs for the address you specified
// Step 2 is LIST_NFT: lists your NFT on-chain.
"operation": {
"success": true,
// listingInstructions will only appear if success is true. These are to be executed in order
"listingInstructions": [
{
"step": "SET_ALLOWANCE",
"transaction": {
"from": "0x487bFB4e3A69cf34adddA893EEC6fDdEF19aDAfA",
"to": "0xeC6F34d2052D9Da956295F0Bf8034b2B900C9D54",
"data": "0xa22cb465000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff0000000000000000000000000000000000000000000000000000000000000001",
"value": "0"
}
},
{
"step": "LIST_NFT",
"transaction": {
"from": "0x487bFB4e3A69cf34adddA893EEC6fDdEF19aDAfA",
"to": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF",
"data": "0x462103af00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000487bFB4e3A69cf34adddA893EEC6fDdEF19aDAfA0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e13b4a6dd605f7d554cc445cede96d76a09099069e569173872ba2f87f3a6683828dcd7000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000eC6F34d2052D9Da956295F0Bf8034b2B900C9D540000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"value": "0"
}
}
]
}
}
Most of the data in the API response is not actionable and is meant for the developer to do spot-checks. The listingInstructions
contain transactions that can be submitted on-chain to perform the listing.
Step 3: Execute the call-data as the maker
def send_transaction(tx_fields, private_key):
"""
Sends a transaction for a user
:param tx_fields: a dictionary containing fields "from", "to", "data", "value"
:param private_key: the private key for the address at tx_fields["from"]
"""
# Fetch new nonce for user
nonce_field = web3_client.eth.getTransactionCount(from_address)
# Fetch fields to, value, data from the transaction
to_field = tx_fields['to']
data_field = tx_fields['data']
value_field = int(tx_fields['value'])
# Generate the signed transaction
signed_transaction = web3_client.eth.account.sign_transaction({
# For the purpose of this demo, the first few parameters are set as safe defaults
'chainId': 137,
'gasPrice': int(200 * 1e9),
'from': web3.Web3.toChecksumAddress(from_address),
'to': web3.Web3.toChecksumAddress(to_field),
'value': value_field,
'data': data_field,
'nonce': nonce_field,
}, private_key)
# Wait for transaction to settle
tx_receipt = web3_client.eth.sendRawTransaction(signed_transaction.rawTransaction)
web3_client.eth.waitForTransactionReceipt(tx_receipt)
print(f"Transaction {tx_receipt.hex()} was successfully mined.")
# NOTE: Remember always to spot-check the data coming back from the response before it is submitted!
# Check our guide on "Spot checks"
assert result['operation']['success'] == true
for operation in result['operation']['listingInstructions']:
send_transaction(operation['transaction'], ALICE_PK)
Congratulations! your NFT was listed on-chain! You can now use the UID in the response to fill or cancel the listing!
Last updated