Layer2 Transaction
There are two categories of zkLink transactions: L1Transaction and L2Transaction.
Modifies the public key hash of the Layer2 account.
Field | Description |
---|---|
type | ChangePubKey |
chainId | ID defined by zkLink, for example, when the user performs ChangePubKey on ETH, the front-end needs to set this value to the Ethereum ID defined by zkLink on Layer2 |
accountId | Target account ID of ChangePubKey |
subAccountId | Target subaccount ID of ChangePubKey, the fee will be deducted from this subaccount |
newPkHash | New public key hash |
nonce | Current nonce of the target account |
feeToken | The token used as the fee token |
fee | Fee obtained via estimateTransactionFee API, the value should be packable |
ts | Timestamp of the API call, used as front-end request id to generate transaction hash |
ethAuthData | ChangePubKeyAuthData to set the public key |
signature | TxSignature , the public key hash corresponding to the signature must be aligned with the newPkHash |
- EthECDSA{"type":"EthECDSA","ethSignature": "0x36a83c6358c55870f2da3a9a7abcbace3016debd6e6982e7fc9aace159592d2b6f42eb5a20b166e1b73193019c63c57cf90b7c2b531f6c5ec572f622e66b4a9e1c"}
- EthCREATE2{"type":"EthCREATE2","creatorAddress":"0x388c818ca8b9251b393131c08a736a67ccb19297","saltArg":"0x66b8e2fa879542a0c32c77e137ab830c3345788a2696999afbd07acabab8ad81","codeHash":"0xfb57f5a066444ff426f4433344fd2e179843fd9069c06eb3b4ecc74e8b599410"}
- Onchain{"type":"Onchain"}
The
EthECDSA
signature is assembled according to EIP712 standard, where the value of the domain is:{
"name":"ZkLink", // Constant
"version":"1", // Constant
"chainId":13, // This is the Layer1 blockchain Id, not the ID defined by zkLink
"verifyingContract": "0x388c818ca8b9251b393131c08a736a67ccb19297" // This is the address of the zkLink contract on Layer1 blockchain
}
Note:
chainId
and verifyingContract
are different for each chain, all related information can be obtained through the getSupportChains
API.EIP712 message includes:
{
"pubKeyHash":"0x79a239efe5cedff14e3e0c9bf9cd4c6c4cdec507", // tx.newPkHash
"nonce":0, // tx.nonce
"accountId":8
// tx.accountId
}
This message is the content of the signature displayed on Metamask.
{
"type": "ChangePubKey",
"chainId": 1,
"accountId": 39,
"subAccountId": 1,
"newPkHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
"feeToken": 1,
"fee": "1285000000000000",
"nonce": 0,
"signature": {
"pubKey": "ed53a138751ed1e456f46e74eff3463d2420e488a4f608bde0f28d13c7104d29",
"signature": "3b91c0421df4295281596746722ae20ccf270c5fc0561f93a0219db1faea6518f033e778dd552f90a9a6afd06427428b2ac4ea6f6893a3f162b32683d1108a02"
},
"ethAuthData": {
"type": "EthECDSA",
"ethSignature": "0x8e548e3727a94533b3963877b87966e308e6eef7762f78de567ff14b4e0e87780d37a845501ffd2cdbc7d6f0d620c14589212761f1637ea8214b0b6bac10aa9b1b"
},
"ts": 1675650037
}
Name | Rule |
---|---|
type | 1 byte with value "6" |
chainId | 1 byte |
accountId | 4 bytes |
subAccountId | 1 byte |
newPkHash | 20 bytes |
feeToken | 2 bytes |
fee | Refer to SDK serializeFeePacked, 2 bytes |
nonce | 4 bytes |
ts | 4 bytes |
39 bytes in total.
Layer-2 transfer
Field | Description |
---|---|
type | Transfer |
accountId | Account ID of the from_account |
fromSubAccountId | Subaccount ID of the from_account |
toSubAccountId | Sub-account ID of the to_account |
to | Account address of the to_account, if the account does not exist, a new account will be automatically created on zkLink Layer2 for this address |
token | Token ID |
amount | Token amount, the value must be packable |
fee | Fee returned by estimateTransactionFee API, the value should be packable |
ts | Timestamp of the API call, used as front-end request id to generate transaction hash |
nonce | Current nonce of the account |
signature | TxSignature , the public key hash corresponding to the signature must be aligned with the from_account |
{
"type": "Transfer",
"accountId": 8,
"fromSubAccountId": 3,
"toSubAccountId": 3,
"to": "0xbfDa941Bd2a0eddB57b10f8E8d3486A738B92cCC",
"token": 3,
"amount": "998000000000000000",
"fee": "3000000000000000",
"ts": 1646101085,
"nonce": 1,
"signature": {
"pubKey": "0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
"signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
}
}
Name | Rule |
---|---|
type | 1 byte with value "4" |
accountId | 4 bytes |
fromSubAccountId | 1 byte |
to | 20 bytes |
toSubAccountId | 1 byte |
token | 2 bytes |
amount | Refer to SDK serializeAmountPacked, 5 bytes |
feeAmount | Refer to SDK serializeFeePacked, 2 bytes |
nonce | 4 bytes |
ts | 4 bytes |
44 bytes in total.
Transfer {amount} {token} to: {to}
Fee: {feeAmount} {token}
Nonce: {nonce}
- The unit of
amount
is ether, for example, if the user transfers2.3
ZKL, then the amount would be2.3
. token
: the symbol of the token.to
: the encoded address, such as0xbfda941bbd2a0eddb57b10f8e8d3486a738b92ccc
(all in lowercase).fee
: the amount of transaction fee being paid, the unit is the same asamount
(ether). IffeeAmount
is 0, the message does not need to includeFee: {fee} {token}
.
Withdraw from zkLink L2 to connected networks.
Field | Description |
---|---|
type | Withdraw |
toChainId | The target chain of the withdrawal |
accountId | ID of the withdraw account |
subAccountId | ID of the withdraw subaccount |
to | The target address of the withdrawal |
l2SourceToken | The source token to be deducted from the Layer2 account and used as the fee token |
l1TargetToken | The target token to be sent to the to_address on Layer1 |
amount | Withdrawal amount, the value does not have to be packable |
fee | Fee requested via estimateTransactionFee API, the value should be packable |
withdrawFeeRatio | Transaction fee for fast withdraw, 100 as 1%, 10000 as 100% |
fastWithdraw | 0 for normal withdraw, 1 for fast withdraw |
ts | Timestamp of the API call, used as front-end request id to generate transaction hash |
nonce | Current nonce of the account |
signature | TxSignature , the public key hash corresponding to the signature must be aligned with the withdraw account |
Example
{
"type": "Withdraw",
"toChainId": 1,
"accountId": 7,
"subAccountId": 2,
"to": "0x3498f456645270ee003441df82c718b56c0e6666",
"l2SourceToken": 1,
"l1TargetToken": 17,
"amount": "995900000000000000",
"fee": "4100000000000000",
"withdrawFeeRatio": 50,
"fastWithdraw": 1,
"ts": 1646102148,
"nonce": 0,
"signature": {
"pubKey": "0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
"signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
}
}
Name | Rule |
---|---|
type | 1 byte with value "3" |
toChainId | 1 byte |
accountId | 4 bytes |
subAccountId | 1 byte |
to | 20 bytes |
l2SourceToken | 2 bytes |
l1TargetToken | 2 bytes |
amount | Refer to SDK serializeAmountFull, 16 bytes |
fee | Refer to SDK serializeFeePacked, 2 bytes |
nonce | 4 bytes |
fastWithdraw | 1 byte |
withdrawFeeRatio | 2 bytes |
ts | 4 bytes |
60 bytes in total.
Withdraw {amount} {l2SourceToken} to: {to}
Fee: {feeAmount} {l2SourceToken}
Nonce: {nonce}
- The unit of
amount
is ether, for example, if the user transfers2.3
ZKL, then the amount would be2.3
. token
: the symbol of the token.to
: the encoded address, such as0xbfda941bbd2a0eddb57b10f8e8d3486a738b92ccc
(all in lowercase).fee
: the amount of transaction fee being paid, the unit is the same asamount
(ether). IffeeAmount
is 0, the message does not need to includeFee: {fee} {token}
.
Forced withdraw from Layer2
Field | Description |
---|---|
type | ForcedExit |
toChainId | The target chain of the withdrawal |
initiatorAccountId | Account ID of the transaction initiator |
initiatorSubAccountId | Subaccount ID of the transaction initiator |
initiatorNonce | Nonce of the transaction initiator's subaccount |
target | The account address of the forced withdraw, the token on Layer 1 is also sent to this address |
targetSubAccountId | Subaccount ID of the account of the forced withdraw |
l2SourceToken | The token deducted from the account of the forced withdraw |
l1TargetToken | This token sent to the to_address on L1 |
exitAmount | Withdrawal amount |
ts | Timestamp of the API call, used as front-end request id to generate transaction hash |
signature | TxSignature , the public key hash corresponding to the signature must be aligned with the initiator account |
{
"type": "ForcedExit",
"toChainId": 1,
"initiatorAccountId": 7,
"initiatorSubAccountId": 3,
"initiatorNonce":4,
"target": "0x3498f456645270ee003441df82c718b56c0e6666",
"targetSubAccountId": 2,
"l2SourceToken": 1,
"l1TargetToken": 17,
"exitAmount": "4100000000000000",
"ts": 1646102148,
"nonce": 0,
"signature": {
"pubKey": "0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
"signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
}
}
Name | Rule |
---|---|
type | 1 byte with the value "7" |
toChainId | 1 byte |
initiatorAccountId | 4 bytes |
initiatorSubAccountId | 1 byte |
target | 20 bytes |
targetSubAccountId | 1 byte |
l2SourceToken | 2 bytes |
l1TargetToken | 2 bytes |
initiatorNonce | 4 bytes |
exitAmount | Refer to the SDK serializeAmountFull, 16 bytes |
ts | 4 bytes |
56 bytes in total.
Order Matching
Field | Description |
---|---|
type | OrderMatching |
accountId | Initiator's account id. Only specific accounts can initiate this type of transaction on Layer2 |
subAccountId | Initiator's subaccount id |
taker | Order , taker order |
maker | Order , maker order |
feeToken | Fee token, deducted from the initiator's subaccount |
fee | Fee returned via the estimateTransactionFee API. The value should be packable |
expectBaseAmount | The maximum amount of base token that the initiator expects to be traded in this order matching, which cannot exceed the maximum amount that the maker and taker can actually trade. The value does not need to be packable |
expectQuoteAmount | The maximum amount of quote token that the initiator expects to be traded in this order matching, which cannot exceed the maximum amount that the maker and taker can actually trade. The value does not need to be packable |
signature | TxSignature , the pub key hash corresponding to the signature must be aligned with the initiator account |
Field | Description |
---|---|
accountId | Account id |
subAccountId | Subaccount id |
slotId | Slot id |
nonce | Slot nonce |
baseTokenId | The base token, for example, BTC in BTC/USDT is the base token |
quoteTokenId | The quote token, for example, USDT in BTC/USDT is the quote token |
amount | Order amount. The value must be packablee |
price | Order price. The value does not need to be packable |
isSell | 1 for seller, that is, selling the base token. 0 for buyer, that is, buying the base token |
feeRatio1 | Fee rate for takers. 100 for 1%, for is 2.56% |
feeRatio2 | Fee rate for makers |
signature | TxSignature , the pub key hash corresponding to the signature must be aligned with the accountId |
The
subAccountId
, baseTokenId
, and quoteTokenId
of the maker and taker must be the same, and isSell
must be the opposite. If the taker is a sell order, the price of the taker must not be higher than the price of the maker. If the taker is a buy order, the price of the taker must not be lower than the price of the maker.{
"type": "OrderMatching",
"accountId": 4,
"subAccountId": 1,
"taker": {
"accountId": 11,
"subAccountId": 1,
"slotId": 5844,
"nonce": 24,
"baseTokenId": 42,
"quoteTokenId": 1,
"amount": "373400000000000000000",
"price": "1210900000000000000",
"isSell": 1,
"feeRatio1": 5,
"feeRatio2": 10,
"signature": {
"pubKey": "1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
"signature": "3a5c5c23a74cc04d256f03eb1671acd3959d707252ed52b16cb7b2ffe332a804986e09e0d62bcf49fc9231b38f07b71199769a7343eddc8b43ed9dd2ef8a4405"
}
},
"maker": {
"accountId": 11,
"subAccountId": 1,
"slotId": 5915,
"nonce": 14,
"baseTokenId": 42,
"quoteTokenId": 1,
"amount": "5165400000000000000000",
"price": "1210900000000000000",
"isSell": 0,
"feeRatio1": 5,
"feeRatio2": 10,
"signature": {
"pubKey": "1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
"signature": "9579e54f53aa709e72c7e4de9815d258cf92bb3e9c4b9d03c2f79a7a49b5bda062d7e81b278eb62f2452294d178728b460efdb80017c83748dd190e41e05b802"
}
},
"fee": "405000000000000",
"feeToken": 1,
"expectBaseAmount": "373400000000000000000",
"expectQuoteAmount": "452150060000000000000",
"signature": {
"pubKey": "84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
"signature": "1242830780b17dd362e8d31952deab6d8b5d81cadd62779b2caab0821baa030a770afa9a2c249d8f45000c4b9c6f01ef6b002682760e5bc4e5d39ef7f511ce03"
}
}
Name | Rule |
---|---|
type | 1 byte with the value "8==" |
accountId | 4 bytes |
subAccountId | 1 byte |
orderBytesHash | 32 bytes, refer to SDK rescueHashOrders |
feeToken | 2 bytes |
fee | Refer to SDK serializeFeePacked, 2 bytes |
expectBaseAmount | 16 bytes |
expectQuoteAmount | 16 bytes |
74 bytes in total.
Name | Rule |
---|---|
type | 0xff, 1 byte |
accountId | 4 bytes |
subAccountId | 1 byte |
slotId | 2 bytes |
nonce | 4 bytes |
baseTokenId | 2 bytes |
quoteTokenId | 2 bytes |
price | 15 bytes |
isSell | 1 byte |
feeRatio1 | 1 byte |
feeRatio2 | 1 byte |
amount | Refer to SDK serializeAmountPacked, 5 bytes |
39 bytes in total.
var ordersBytes = [makerOrderBytes, takerOrderBytes, paddingBytes];
// Where makerOrderBytes and takerOrderBytes are the encoded values of taker and maker respectively
// paddingBytes is padding with zeros to make the length of orderBytes 178 bytes
var orderBytesHash = rescueHashOrders(ordersBytes);
version: 4457a91
Last modified 2mo ago