Создание транзакции
В данной статье мы будем использоваться этот кошелек для примера:
Address: 0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF
Private Key: 0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf
Единственная транзакция, которая совершается на Уровне-1 – это депозит. Она имеет два подтипа
DepositETH и DepositERC20
.[
{
"constant": false,
"inputs": [
{
"internalType": "contract IERC20",
"name": "_token",
"type": "address"
},
{
"internalType": "uint104",
"name": "_amount",
"type": "uint104"
},
{
"internalType": "address",
"name": "_franklinAddr",
"type": "address"
}
],
"name": "depositERC20",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "_franklinAddr",
"type": "address"
}
],
"name": "depositETH",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
}
]
Пример кода:
import { Wallet, Contract, utils } from 'ethers'
const contract = new Contract('0x8ECa806Aecc86CE90Da803b080Ca4E3A9b8097ad', ABI, wallet)
const wallet = new Wallet('0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf')
async function depositETH(amount) {
const tx = await contract.depositETH(wallet.address, {
value: utils.parse(amount)
})
return tx
}
// deposit 1 ETH
depositETH('1').then(console.log)
Как и в других проектах вы должны подтвердить основной адрес контракта ZKSwap, чтобы внести свои токенты ERC20 на депозит. Будьте осторожны с токенами, у которых есть ограничения (Подробнее см. здесь).
Пример кода:
import { Wallet, Contract, utils } from 'ethers'
const contract = new Contract('0x8ECa806Aecc86CE90Da803b080Ca4E3A9b8097ad', ABI, wallet)
const wallet = new Wallet('0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf')
async function depositERC20(amount, tokenAddress) {
const tokenContract = new Contract(tokenAddress, ERC20_ABI, wallet)
// check allowance
const allowance = await tokenContract.allowance(wallet.address, MAIN_CONTRACT_ADDRESS)
let nonce
if (allowance.lt(utils.parse(amount)) {
// approve
const MAX_AMOUNT = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
const approveTx = await tokenContract.allow(MAIN_CONTRACT_ADDRESS, MAX_AMOUNT)
nonce = approveTx.nonce + 1
}
const tx = await contract.depositERC20(tokenAddress, utils.parse(amount), wallet.address, {
nonce
})
return tx
}
// deposit 100 ZKS
depositERC20('100', '0xe4815ae53b124e7263f08dcdbbb757d41ed658c6').then(console.log)
При отправке транзакции на ZKSwap через API необходимо заполнить три поля:
tx
, signature
и fastProcessing
. Далее по тексту Signed Transaction
относиться к полю tx
, а ETH Signature относится к полю signature
.Подпишите следующее сообщение приватным ключом Уровня 1, чтобы получить сид фразу Уровня 2. И используйте криптографические библиотеки zkSync, чтобы получить приватный ключ.
Plain Text
JavaScript
Access ZKSwap account.
Only sign this message for a trusted client!
const msg = 'Access ZKSwap account.\n\nOnly sign this message for a trusted client!'
import { Wallet, Contract, utils } from 'ethers'
import { privateKeyFromSeed, private_key_to_pubkey_hash } from 'zksync-crypto'
const wallet = new Wallet('0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf')
async function getPrivateKey() {
const msg = 'Access ZKSwap account.\n\nOnly sign this message for a trusted client!'
const signature = await wallet.signMessage(msg)
const seed = utils.arrayify(signature)
// Get private key
const privateKey = privateKeyFromSeed(seed)
return privateKey
}
getPrivateKey().then(console.log)
После получения приватного ключа вам необходимо зарегистрировать хэш открытого ключа в ZKSwap, чтобы он мог верифицировать отправленные вами транзакции.
import { utils } from 'ethers'
import { private_key_to_pubkey_hash } from 'zksync-crypto'
const pubKeyHash = `sync:${utils.hexlify(private_key_to_pubkey_hash(privateKey)).substr(2)}`
Перед отправкой транзакции в ZKSwap вам необходимо подписать данные транзакции.
import { utils } from 'ethers'
import { sign_musig } from 'zksync-crypto'
function signMessage(privateKey, msgBytes) {
const signaturePacked = sign_musig(privateKey, msgBytes)
const pubKey = utils.hexlify(signaturePacked.slice(0, 32)).substr(2)
const signature = utils.hexlify(signaturePacked.slice(32)).substr(2)
return {
pubKey,
signature
}
}
const msgBytes = utils.concat([type, accountId, ...etc])
const signature = signMessage(privateKey, msgBytes)
После того, как учетная запись была «зарегистрирована» в ZKSwap (посредством перевода или депозита), вы можете изменить pubKeyHash учетной записи, чтобы совершать любую транзакцию на Уровне 2. Это особая транзакция, которую не нужно подписывать приватным ключом Уровня 2.
Поля транзакции
Field | Type | Comment |
type | string | ChangePubKey |
accountId | number | Your account ID. |
account | address | Your address. |
newPkHash | number | The public key hash. |
nonce | number | Your current nonce. |
ethSignature | string | Layer-1 signature |
Пример подписанной транзакции
{
"type": "ChangePubKey",
"accountId": 83670,
"account": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"newPkHash": "sync:83f62ba777515089eb905a375f77f59ddfada116",
"nonce": 0,
"ethSignature": "0x66c1ef3611a634e400301375b291a0835b0e31237273e1bdab45acc3ef27c761674fd5e5a706566e5175e8e18306f5b8d1d36016f3894e84d527c3c97e92bcf71c"
}
ETH подпись
Шаблон сообщения
Сообщение для подписи
Подпись
Register ZKSwap pubkey:
{pubKeyHash}
nonce: {hexlifiedNonce}
account id: {hexlifiedAccountId}
Only sign this message for a trusted client!
Register ZKSwap pubkey:
83f62ba777515089eb905a375f77f59ddfada116
nonce: 0x00000000
account id: 0x000146d6
Only sign this message for a trusted client!
0x66c1ef3611a634e400301375b291a0835b0e31237273e1bdab45acc3ef27c761674fd5e5a706566e5175e8e18306f5b8d1d36016f3894e84d527c3c97e92bcf71c
Поля транзакции
Bytes Order | Field | Type | Bytes Length | Comment | Bytes Example |
0 | type | string | 1 | Transfer | 0x05 |
1 | accountId | number | 4 | Your account ID. | 0x0000053a |
2 | from | address | 20 | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | 20 | The target address you want to transfer. | 0x961b513dfd3e363c238e0f98219ee02552a847bd |
4 | token | number | 2 | The ID of the token. | 0x000a |
5 | amount | string | 5 | The amount you want to transfer. | 0x4a817c8008 |
6 | feeToken | number | 1 | The ID of fee token. | 0x0a |
7 | fee | string | 2 | | 0x0000 |
8 | chainId | number | 1 | 11 for mainnet, 128 for ropsten. | 0x0b |
9 | nonce | number | 4 | Your current nonce. | 0x00000001 |
- | signature | object | | Contains your pubKey and signature. | |
Пример Full Bytes
0x050000053a026a25efbcefb2e481d005e4f00ccced0af511ff961b513dfd3e363c238e0f98219ee02552a847bd000a4a817c80080a00000b00000001
Пример подписанной транзакции
{
"type": "Transfer",
"accountId": 1338,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0x961b513dfd3e363c238e0f98219ee02552a847bd",
"token": 10,
"amount": "1000000000000000000",
"feeToken": 10,
"fee": "0",
"chainId": 11,
"nonce": 1,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "7db4f4ce33abf89cbccaff96ae0651c79043dcf965893de71e7388163ec57883b2d4ef9bf264346ceff69f9ba8dfe8624d1fad9a452acf10a5d15f956a0a7b03"
}
}
ETH подпись
Шаблон сообщения
Пример сообщения
Подпись
Transfer {readableAmount} {tokenSymbol}
To: {to}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Transfer 1.0 ZKS
To: 0x961b513dfd3e363c238e0f98219ee02552a847bd
Chain Id: 11
Nonce: 1
Fee: 0.0 ZKS
Account Id: 1338
{
"type": "EthereumSignature",
"signature": "0xbf8fa93e7da866aa3acb07a6a826e5e61195eba04e3c72a4f02b8fc8221da1f764363817968576013ca515ffe5e1104b5890937150883f3304d0738777af915b1c"
}
Поля транзакции
Bytes Order | Field | Type | Bytes Length | Comment | Bytes Example |
0 | type | string | 1 | Withdraw | 0x03 |
1 | accountId | number | 4 | Your account ID. | 0x0000053a |
2 | from | address | 20 | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | 20 | The target address you want to withdraw to. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
4 | token | number | 2 | The ID of the token you want to withdraw. | 0x000a |
5 | amount | string | 16 | The amount you want to withdraw. | 0x00000000000000000de0b6b3a7640000 |
6 | feeToken | number | 1 | The ID of fee token. | 0x0a |
7 | fee | string | 2 | | 0x4bf0 |
8 | chainId | number | 1 | 11 for mainnet, 128 for ropsten. | 0x0b |
9 | nonce | number | 4 | Your current nonce. | 0x00000002 |
- | signature | object | | Contains your pubKey and signature. | |
Пример Full Bytes
0x030000053a026a25efbcefb2e481d005e4f00ccced0af511ff026a25efbcefb2e481d005e4f00ccced0af511ff000a00000000000000000de0b6b3a76400000a4bf00b00000002
Пример подписанной транзакции
{
"type": "Withdraw",
"accountId": 1338,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0x026a25efbcefb2e481d005e4f00ccced0af511ff",
"token": 10,
"amount": "1000000000000000000",
"feeToken": 10,
"fee": "6070000000000000000",
"chainId": 11,
"nonce": 2,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "68bb8413edc0182812aa90481ff46f0514df9d5d6b5703338f1a292682caad9b04cac623f95b9d26fa31d4a9330ba35b5746fd697853a0512f92b00692fe6d00"
}
}
ETH подпись
Шаблон сообщения
Пример сообщения
Подпись
Withdraw {readableAmount} {tokenSymbol}
To: {to}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Withdraw 3.4226556417 ZKS
To: 0x026a25efbcefb2e481d005e4f00ccced0af511ff
ChainId 10
Nonce: 2
Fee: 1.577 ZKS
Account Id: 83670
{
"type": "EthereumSignature",
"signature": "0x0440667d6a694b76e5f3a51fa3981a3db95bfc7d3feeb301f403ea6f3bef01d32c9e06920f7b13edd92a6cb22f49d6709fb4f9d41efc09b0a094173b6bbb4f121b"
}
Для примера обменяем токен А на токен В. Есть два способа:
- 1.Если А – это токен комиссии, то ее размер рассчитывается как
amountIn * 5 / 9995
- 2.Если А не выступает в роли токена комиссии, а для комиссии применяется токен В, то ее размер
amountOut * 5 /10000
. Это неamountOutMin
.amountOut
равенamountOutMin
и тогда проскальзывание равно 0.
Bytes Order | Field | Type | Bytes Length | Comment | Bytes Example |
0 | type | string | 1 | Swap | 0x0b |
1 | accountId | number | 4 | Your account ID. | 0x0000053a |
2 | from | address | 20 | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | 20 | The pair's address. | 0xaa45c964e21eafb38574e9d000adbaf85acfbb80 |
4 | tokenIn | number | 2 | The ID of the token you want to swap in. | 0x000a |
5 | amountIn | string | 5 | The amount you want to swap in. | 0x94efe63009 |
6 | tokenOut | number | 2 | The ID of the token you want to swap out. | 0x0000 |
7 | amountOutMin | string | 5 | The minimum amount you want to swap out. | 0x25004d47c6 |
8 | feeToken | number | 1 | The ID of fee token. | 0x0a |
9 | fee | string | 2 | | 0x7d0d |
10 | chainId | number | 1 | 11 for mainnet, 128 for ropsten. | 0x0b |
11 | nonce | number | 4 | Your current nonce. | 0x00000003 |
- | signature | object | | Contains your pubKey and signature. | |
Пример Full Bytes
0x0b0000053a026a25efbcefb2e481d005e4f00ccced0af511ffaa45c964e21eafb38574e9d000adbaf85acfbb80000a94efe63009000025004d47c60a7d0d0b00000003
Пример подписанной транзакции
{
"type": "Swap",
"accountId": 1338,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0xaa45c964e21eafb38574e9d000adbaf85acfbb80",
"tokenIn": 10,
"tokenOut": 0,
"amountIn": "19990000000000000000",
"amountOutMin": "4966214206000000",
"feeToken": 10,
"fee": "10000000000000000",
"chainId": 11,
"nonce": 3,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "3c6c2059ab0e929ed18d6ad4fbbf1cddce0e84b0cb9537069456b16cd01f33a2bc5391f8f7e1b9ae8fdff4c5d05856709e6bfd0e9200f5293386cf1aa6b39c00"
}
}
ETH подпись
Шаблон сообщения
Пример сообщения
Подпись
Swap {readableAmontIn} {tokenInSymbol}
Minimum: {readableAmontOutMin} {tokenOutSymbol}
To: {pairAddress}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Swap 19.99 ZKS
Minimum: 0.004966214206 ETH
To: 0xaa45c964e21eafb38574e9d000adbaf85acfbb80
Chain Id: 11
Nonce: 3
Fee: 0.01 ZKS
Account Id: 1338
{
"type": "EthereumSignature",
"signature": "0x66ca505f09e2dbd2aaaa809cac3ec7085ea7831ec58c695566190588a2ced45c0d7e1c235840dd3f547d54ad87e6740bb3d299a89d36460b9eb1e56b25456ef41b"
}
Добавление ликвидности
Поля транзакции
Bytes Order | Field | Type | Bytes Length | Comment | Bytes Example |
0 | type | string | 1 | AddLiquidity | 0x09 |
1 | accountId | number | 4 | Your account ID. | 0x0000053a |
2 | from | address | 20 | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | 20 | The pair's address. | 0xaa45c964e21eafb38574e9d000adbaf85acfbb80 |
4 | tokenA | number | 2 | The ID of token A. | 0x0000 |
5 | amountADesired | number | 5 | The amount of token A you want to add to the pair. | 0xc2cf6f3245 |
6 | amountAMin | string | 5 | The minimum amount of Token A you want to add to the pair. | 0xb911dcd625 |
7 | tokenB | number | 2 | The ID of the token B. | 0x000a |
8 | amountBDesired | string | 5 | The amount of token B you want to add to the pair. | 0x4a817c8009 |
9 | amountBMin | string | 5 | The minimum amount of Token B you want to add to the pair. | 0x46c7cfe009 |
10 | tokenLiquidity | number | 2 | The pair ID. | 0x4002 |
11 | feeToken | number | 1 | The ID of fee token. | 0x0a |
12 | fee | string | 2 | | 0x0000 |
13 | chainId | number | 1 | 11 for mainnet, 128 for ropsten. | 0x0b |
14 | nonce | number | 4 | Your current nonce. | 0x00000004 |
- | signature | object | | Contains your pubKey and signature. | |
Пример Full Bytes
0x090000053a026a25efbcefb2e481d005e4f00ccced0af511ffaa45c964e21eafb38574e9d000adbaf85acfbb800000c2cf6f3245b911dcd625000a4a817c800946c7cfe00940020a00000b00000004
Пример подписанной транзакции
{
"type": "AddLiquidity",
"accountId": 1338,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0xaa45c964e21eafb38574e9d000adbaf85acfbb80",
"tokenA": 0,
"tokenB": 10,
"tokenLiquidity": 16386,
"amountADesired": "2614699457800000",
"amountBDesired": "10000000000000000000",
"amountAMin": "2483964484900000",
"amountBMin": "9500000000000000000",
"feeToken": 10,
"fee": "0",
"chainId": 11,
"nonce": 4,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "3506a865b8a0871b706a620abbf7978760f76670c2d563f059d217890349988dd7a37d1cea3f67d5ca691453dd45d282141acac3f4dafb9f7a44b1dda3e0ca00"
}
}
ETH подпись
Шаблон сообщения
Пример сообщения
Подпись
AddLiquidity {pairSymbol}
Desired: {readableAmontA} {tokenASymbol} {readableAmontB} {tokenBSymbol}
Minimum: {readableAmontAMin} {tokenASymbol} {readableAmontBMin} {tokenBSymbol}
To: {pairAddress}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
AddLiquidity liquidity_0_10