Withdraw NFT
withdraw nft to layer1

EndPoint

POST api/v3/nft/withdrawal

Header

​
Field
Description
Example
X-API-KEY
ApiKey
"HlkcGxbqBeaF76j4rvPaOasyfPwnkQ6B6DQ6THZWbvrAGxzEdulXQvOKLrRWZLnN"
X-API-SIG
​ECDSA Signature, pay attention the signature type, sign the ecdsa hash​
"0xccf0a141fce2dc5cbbd4f802c52220e9e2ce260e86704d6258603eb346eefe2d 4a450005c362b223b2842d087f7065ea5eee0314531adf6a580fce64c25dca81c02"

Request

​
Query Param
Description
Example
exchange
exchangeAddress in exchange info​
​
owner
account owner address
​
accountId
sender accountId
10110
to
withdraw to address
​
token
​NftTAmountInfo, withdraw nft info
​
maxFee
​offchain fee, request type is 10. Note: if the tokenAddress haven't deployed, the fee is deploy fee + withdraw fee, and the tokenAddress will be deployed in withdraw.
​
storageId
offchainId of storage Id, sellTokenId is nft tokenId in nft balance
1
validUntil
Timestamp for transfer to become invalid, seconds
​
normally current time + 2 months
eddsaSignature
​eddsa signature of the eddsa hash​
​
counterFactualInfo
if it's counterFactual wallet, need pass the info
minGas
(Optional) min gas for on-chain withdraw, Loopring exchange allocates gas for each distribution, but people can also assign this min gas, so Loopring have to allocate higher gas value for this specific distribution, 0 means let Loopring choose the reasonable gas
0

Response

​
Field
Description
Example
hash
The hash identifier set by the user at the time of submission, can use this hash to get the transfer info
"0x1d923ca7834dc90484fa2eb611f0f0bc7e741bb107007ebea19ba8caeab4f9d3"
status
Whether the order was successfully submitted or not, please note, user may query after a while to get real process status, as most offchain requests are async processed Allowable : ['received', 'processing', 'processed', 'failed']
"received"
isIdempotent
Idempotent of submit transfer response, submit same transfer again idempotent will be true
"false"

Model

NftTokenAmountInfo

Wrapper object used to describe a token associated with a certain quantity.
Field
Description
Example
tokenId
The Loopring's NFT token identifier.
32769
amount
The amount of the NFT
token
"2"
nftData
The Loopring's NFT token data identifier which is a hash string of NFT token address and NFT_ID
"0xf7c932351186c3a9053f313eefa16209c018f7f1dba8aa 8ca7100400f7c31085"

TokenAmountInfo

Field
Description
Example
tokenId
The Loopring's ERC20 token identifier.
0
amount
The amount of the ERC20 token
"100000000000000000"

counterFactualInfo

counterFactual Wallet Info
Field
Description
Example
walletFactory
Counter factual wallet factory contract address
"0xbbbbca6a901c926f240b89eacb641d8aec7aeafd"
walletOwner
Counter factual wallet owner address, NOT the wallet address
"0xbbbbca6a901c926f240b89eacb641d8aec7aeafd"
walletSalt
Salt to generate address from owner & other related info
"1"

Compute ecdsa hash

const message = {
owner: data.owner,
accountID: data.accountId,
tokenID: data.token.tokenId,
amount: data.token.amount,
feeTokenID: data.maxFee.tokenId,
maxFee: data.maxFee.amount,
to: data.to,
extraData: data.extraData ? data.extraData : "",
minGas: data.minGas,
validUntil: data.validUntil,
storageID: data.storageId,
};
​
const typedData: EIP712TypedData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
],
Withdrawal: [
{ name: "owner", type: "address" },
{ name: "accountID", type: "uint32" },
{ name: "tokenID", type: "uint16" },
{ name: "amount", type: "uint96" },
{ name: "feeTokenID", type: "uint16" },
{ name: "maxFee", type: "uint96" },
{ name: "to", type: "address" },
{ name: "extraData", type: "bytes" },
{ name: "minGas", type: "uint256" },
{ name: "validUntil", type: "uint32" },
{ name: "storageID", type: "uint32" },
],
},
primaryType: "Withdrawal",
domain: {
name: "Loopring Protocol",
version: "3.6.0",
chainId: chainId,
verifyingContract: data.exchange,
},
message: message,
};

Compute eddsa hash

const onchainDataHash = abi
.soliditySHA3(
["uint256", "address", "bytes"],
[
request.minGas,
new BN(fm.clearHexPrefix(request.to), 16),
ethUtil.toBuffer(request.extraData),
]
)
.slice(0, 20);
​
const orderHashStr = fm.addHexPrefix(onchainDataHash.toString("hex"));
const inputs = [
new BN(ethUtil.toBuffer(request.exchange)).toString(),
request.accountId,
request.token.tokenId,
request.token.amount,
request.maxFee.tokenId,
request.maxFee.amount,
orderHashStr,
request.validUntil,
request.storageId,
];
const hasher = Poseidon.createHash(inputs.length + 1, 6, 53);
const hash = hasher(inputs).toString(10);

Example

Header

X-API-KEY = l4hd4CGLLGuZ9nEultG4sfhQZDjPp9sv0kMy13cyGgkJyIWDodVSM4S4ucb5WFKN
X-API-SIG = 0x8a9ed00eaf47deec677760a477c907746f9f40c53bf1e8b3b75a81e34b2911806817d9856fb987fba0a363b472db7a359dd54296e55befcf4f24605a138203e81b02

Request

POST api/v3/nft/withdrawal
{
"accountId": 10010,
"ecdsaSignature": "0x8a9ed00eaf47deec677760a477c907746f9f40c53bf1e8b3b75a81e34b2911806817d9856fb987fba0a363b472db7a359dd54296e55befcf4f24605a138203e81b02",
"eddsaSignature": "0x03120f328edbb2e40bfb47eb86a11697d796acfc364ba6617d62d060378c1cf4128f905bd8206e6420a9392806dd6df655489017d3d8ce9622c06e4b960447c41c1993f6c9f6c9a2a9a82c55b3e23c376db670c6a09e01fa4338bc3de3bc1065",
"exchange": "0x2e76EBd1c7c0C8e7c2B875b6d505a260C525d25e",
"extraData": "",
"maxFee": {
"tokenId": 2,
"amount": "34200000"
},
"minGas": 0,
"owner": "0x6b1029c9ae8aa5eea9e045e8ba3c93d380d5bdda",
"storageId": 3,
"to": "0xbB6924b24bA5c6ece81f056cF54E5d720846c183",
"token": {
"tokenId": 32789,
"nftData": "0x2d4a0fc05056c1cd0e2a059b28d2072dc16cd5d083f77b48ea7d397d05e3627a",
"amount": "2"
},
"validUntil": 1655874620
}

Response

{
"hash": "0x0c7fbf3eb9e3c154b34083def8f32b9467c0fa1e06ba2d5e683c4fc19edc93ef",
"status": "processing",
"isIdempotent": false,
"accountId": 10010,
"tokenId": 0,
"storageId": 3
}
​
​
Copy link
On this page
EndPoint
Header
Request
Response
Model
NftTokenAmountInfo
TokenAmountInfo
counterFactualInfo
Compute ecdsa hash
Compute eddsa hash
Example
Header
Request
Response