The order payload is a string of encode data containing the necessary information to create a new order. Follow the steps below to generate the payload.
Encode token data
// ERC-721
const data = ethers.utils.defaultAbiCoder.encode(
[`tuple(address token, uint256 tokenId)[]`],
[[{ token: tokenAddress, tokenId: tokenId}]]
)
// ERC-1155
const data = ethers.utils.defaultAbiCoder.encode(
[`tuple(address token, uint256 tokenId, uint256 amount)[]`],
[[{ token: tokenAddress, tokenId: tokenId, amount: 1}]] //ERC-1155 listing only accepts amount of 1.
)
Generate dataMask
The dataMask
needs to be generated when creating a collection offer.
Otherwise, it should be 0x
.
// Generate dataMask for EC-721 collection offer
const dataMask = ethers.utils.defaultAbiCoder.encode(
[`tuple(address token, uint256 tokenId)[]`],
[{ token: ethers.constants.AddressZero, tokenId: '0x' + '1'.repeat(64)}]
)
// Generate dataMask for EC-1155 collection offer
const dataMask = ethers.utils.defaultAbiCoder.encode(
[`tuple(address token, uint256 tokenId, uint256 amount)[]`],
[{ token: ethers.constants.AddressZero, tokenId: '0x' + '1'.repeat(64), amount: 1}]
)
// Otherwise
const dataMask = '0x'
Generate order hash
Price limitation
Order price must be no less than 0.0001 ETH and not more than 100000000 ETH.
const items = [{
price: '1000000000000000000', // String, price in wei, e.g. '1000000000000000000' for 1 ETH
data
}]
const order = {
salt, // Random string at a recommended length of 64 characters.
user, // Order maker's address
network: 1, // 1: Mainnet; 5: Goerli testnet
intent: 1, // 1: Create listing or change listing price; 3: Create offer or collection offer
delegateType: 1, // 1: ERC-721; 2: ERC-1155
deadline: 1668738550, // number, the unix timestamp when the listing will expire, in seconds. Must be at least 15 minutes later from now.
currency: '0x0000000000000000000000000000000000000000', // Use ETH for new listing, use WETH for new offer
dataMask: dataMask,
items,
r: '',
s: '',
v: 0,
signVersion: 1,
}
// encode order data
const orderData: string = ethers.utils.defaultAbiCoder.encode(
[
`uint256`,
`address`,
`uint256`,
`uint256`,
`uint256`,
`uint256`,
`address`,
`bytes`,
`uint256`,
`tuple(uint256 price, bytes data)[]`
],
[
order.salt,
order.user,
order.network,
order.intent,
order.delegateType,
order.deadline,
order.currency,
order.dataMask,
order.items.length,
order.items,
]
)
const orderHash = ethers.utils.keccak256(orderData)
Generate user signature and save it in order data
This step will ask the order maker's wallet to sign the order data.
const orderSig = (await web3Provider.send('personal_sign', [
orderHash,
order.user,
])) as string
order.r = `0x${orderSig.slice(2, 66)}`
order.s = `0x${orderSig.slice(66, 130)}`
order.v = parseInt(orderSig.slice(130, 132), 16)
// in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
// signature malleability if version is 0/1
// see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
if (order.v < 27) {
order.v = order.v + 27
}
Encode order data
const orderPayload = ethers.utils.defaultAbiCoder.encode(
[`tuple(uint256 salt, address user, uint256 network, uint256 intent, uint256 delegateType, uint256 deadline, address currency, bytes dataMask, ${orderItemParamType}[] items, bytes32 r, bytes32 s, uint8 v, uint8 signVersion)`],
[order]
)