description |
---|
Sending ERC20 tokens from your Loopring L2 to another Loopring L2 address. |
POST api/v3/transfer
Field | Description | Example | Type | Required |
---|---|---|---|---|
X-API-KEY | ApiKey | "HlkcGxbqBeaF76j4rvPaOasyfPwnkQ6B6DQ6THZWbvrGxzEdulXQvOKLrRWZLnN" | Y | |
X-API-SIG | ECDSA Signature, pay attention the signature type, sign the ecdsa hash | "0xccf0a141fce2dc5cbbd4f802c52220e9e2ce260e86704d6258603eb346eefe2d4a450005c362b223b2842d087f7065ea5eee0314531adf6a580fce64c25dca81c02" | Y |
Query Param | Description | Example | |||
---|---|---|---|---|---|
exchange | exchangeAddress in exchange info | ||||
payerAddr | payer address | ||||
payerId | payer account ID | 10110 | |||
payeeAddr | payee address | ||||
payeeId | payee account ID | 10111,can set to 0 if dont have | |||
token | tokenVolume,transfer tokenId and volume | ||||
maxFee | tokenVolume from offchain fee | ||||
storageId | offchainId of storage Id, sellTokenId is the transfer tokenId | 1 | |||
validUntil | Timestamp for transfer to become invalid, seconds | normally current time + 2 months | |||
eddsaSignature | eddsa signature of the transfer eddsa hash | ||||
memo | (Optional) memo | ||||
payPayeeUpdateAccount | (Optional) transfer to pay payee updateAccount fee , true or false, default is false | true | |||
counterFactualInfo | (Optional) counterfactual Wallet Info, if it's a counterfactual wallet, need to pass the info |
Field | Description | Example | Type | Required |
---|---|---|---|---|
hash | The hash identifier set by the user at the time of submission, can use this hash to get the transfer info | "0x1d923ca7834dc90484fa2eb611f0f0bc7e741bb107007ebea19ba8caeab4f9d3" | string | Y |
status | Whether the order was successfully submitted or not, please note, the user may query after a while to get the real process status, as most off-chain requests are asynchronously processed Allowable : ['received', 'processing', 'processed', 'failed'] | "received" | string | Y |
isIdempotent | Idempotent of submit transfer response, submit same transfer again idempotent will be true | "false" | boolean | Y |
Wrapper object used to describe a token associated with a certain quantity.
Field | Description | Example | Type | Required |
---|---|---|---|---|
tokenId | The Loopring's token identifier. | 0 | integer | Y |
volume | The volume of the token | "100000000000 0" | string | Y |
Counterfactual wallet information.
Field | Description | Example | Type | Required |
---|---|---|---|---|
walletFactory | Counterfactual wallet factory contract address | "0xbbbbca6a901c926f240b89eacb641d8aec7aeafd" | string | Y |
walletOwner | Counterfactual wallet owner address, NOT the wallet address | "0xbbbbca6a901c926f240b89eacb641d8aec7aeafd" | string | Y |
walletSalt | Salt to generate address from owner & other related info | "1" | string | Y |
const message = {
from: data.payerAddr,
to: data.payeeAddr,
tokenID: data.token.tokenId,
amount: data.token.volume,
feeTokenID: data.maxFee.tokenId,
maxFee: data.maxFee.volume,
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" },
],
Transfer: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "tokenID", type: "uint16" },
{ name: "amount", type: "uint96" },
{ name: "feeTokenID", type: "uint16" },
{ name: "maxFee", type: "uint96" },
{ name: "validUntil", type: "uint32" },
{ name: "storageID", type: "uint32" },
],
},
primaryType: "Transfer",
domain: {
name: "Loopring Protocol",
version: "3.6.0",
chainId: chainId,
verifyingContract: data.exchange,
},
message: message,
};
const inputs = [
new BN(ethUtil.toBuffer(request.exchange)).toString(),
request.payerId,
request.payeeId,
request.token.tokenId,
request.token.volume,
request.maxFee.tokenId,
request.maxFee.volume,
new BN(ethUtil.toBuffer(request.payeeAddr)).toString(),
0,
0,
request.validUntil,
request.storageId,
];
const hasher = Poseidon.createHash(inputs.length + 1, 6, 53);
const hash = hasher(inputs).toString(10);