Make Transaction
In the following article, we will use this wallet as example:
Address: 0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF
Private Key: 0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf
The only transaction that made on Layer-1 is deposit. It has two sub-types which are
DepositETH
and 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"
}
]
​
Example Code:
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)
Like other projects, you must approve ZKSwap's main contract address to spend your ERC20 tokens in order to deposit. Be careful for those tokens that has limit on changing allowance (See https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729).
Example code:
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)
When submitting transaction to ZKSwap, the API requires 3 fields:
tx
, signature
and fastProcessing
.In the following docs, Signed Transaction
refers to the tx
field and ETH Signature
refers to the signature
field.Sign the following message with Layer-1's private key to get Layer-2's seed. And use zkSync's crypto libraries to get private key.
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)
After getting private key, you will need to register you publick key hash to ZKSwap so that it can verify transations that you sent.
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)}`
Before submit transaction to ZKSwap, you need to sign the the transaction data.
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)
​
After the account has been "registered" on ZKSwap (via transfer or deposit), you can change the account's
pubKeyHash
in order to make any transaction on Layer-2. This is a special transaction that you don't need to sign it with Layer-2's private key.Transaction Fields
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 |
Signed Transaction Example
{
"type": "ChangePubKey",
"accountId": 83670,
"account": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"newPkHash": "sync:83f62ba777515089eb905a375f77f59ddfada116",
"nonce": 0,
"ethSignature": "0x66c1ef3611a634e400301375b291a0835b0e31237273e1bdab45acc3ef27c761674fd5e5a706566e5175e8e18306f5b8d1d36016f3894e84d527c3c97e92bcf71c"
}
ETH Signature
Message Template
Message to sign
Signature
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
Transaction Fields
Bytes Order | Field | Type | Comment | Bytes Examplle |
0 | type | string | Transfer | 0x05 |
1 | accountId | number | Your account ID. | 0x000146d6 |
2 | from | address | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | The target address you want to transfer. | 0x961b513dfd3e363c238e0f98219ee02552a847bd |
4 | token | number | The ID of the token. | 0x0001 |
5 | amount | string | The amount you want to transfer. | 0x4a817c8008 |
6 | fee | string | The transfer fee | 0x0000 |
7 | chainId | number | 10 for mainnet, 3 for ropsten. | 0x0a |
8 | nonce | number | Your current nonce. | 0x00000001 |
- | signature | object | Contains your pubKey and signature. | ​ |
Full Bytes Example
0x05000146d6026a25efbcefb2e481d005e4f00ccced0af511ff961b513dfd3e363c238e0f98219ee02552a847bd00014a817c800800000a00000001
Signed Transaction Example
{
"type": "Transfer",
"accountId": 83670,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0x961b513dfd3e363c238e0f98219ee02552a847bd",
"token": 1,
"amount": "1000000000000000000",
"fee": "0",
"chainId": 10,
"nonce": 1,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "4aaf03004e24973dbf418e1eb389aa540e41a119ec9908d270682ee32a260caef082b63dd5ec1a466b0011040fb3d7704c0fe0550108c0ffd5866021f1fbb004"
}
}
ETH Signature
Message Template
Message Example
Signature
Transfer {readableAmount} {tokenSymbol}
To: {to}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {tokenSymbol}
Account Id: {accountId}
Transfer 1.0 ZKS
To: 0x961b513dfd3e363c238e0f98219ee02552a847bd
ChainId 10
Nonce: 1
Fee: 0.0 ZKS
Account Id: 83670
{
"type": "EthereumSignature",
"signature": "0xd5d40b48c7f4f8448b2bacdfe5e828bcfd0b0a68e5c895318139a2428a19f3417f65b305b0fbb8c6b5416a101d6b68c7160fe5174caf9d181039fd77d853430f1c"
}
Transaction Fields
Bytes Order | Field | Type | Comment | Bytes Examplle |
0 | type | string | Withdraw | 0x03 |
1 | accountId | number | Your account ID. | 0x000146d6 |
2 | from | address | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | The target address you want to withdraw to. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
4 | token | number | The ID of the token you want to withdraw. | 0x0001 |
5 | amount | string | The amount you want to withdraw. | 0x00000000000000002f7fb72c1003e100 |
6 | fee | string | The withdraw fee. | 0xc52f |
7 | chainId | number | 10 for mainnet, 3 for ropsten. | 0x0a |
8 | nonce | number | Your current nonce. | 0x00000002 |
- | signature | object | Contains your pubKey and signature. | ​ |
Full Bytes Example
0x03000146d6026a25efbcefb2e481d005e4f00ccced0af511ff026a25efbcefb2e481d005e4f00ccced0af511ff000100000000000000002f7fb72c1003e100c52f0a00000002
Signed Transaction Example
{
"type": "Withdraw",
"accountId": 83670,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0x026a25efbcefb2e481d005e4f00ccced0af511ff",
"token": 1,
"amount": "3422655641700000000",
"fee": "1577000000000000000",
"chainId": 10,
"nonce": 2,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "b983234033e17cb3552a7253bec8c7fab7af7c63d06d1d328dac2d377a2440a0af18238b560c73e7274583b65887b59315fc3f87d9505146df7030dd45ee6801"
}
}
ETH Signature
Message Template
Message Example
Signature
Withdraw {readableAmount} {tokenSymbol}
To: {to}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFee} {tokenSymbol}
Account Id: {accountId}
Withdraw 3.4226556417 ZKS
To: 0x026a25efbcefb2e481d005e4f00ccced0af511ff
ChainId 10
Nonce: 2
Fee: 1.577 ZKS
Account Id: 83670
{
"type": "EthereumSignature",
"signature": "0x2c1d029ef846ef1643db63660834537d1b6c255050125c663df55ad51925786d070c450af9719d17ae14c86b9987871cbf7e8cca6177ded0a9d42aa5e6190bbc1b"
}
Transaction Fields
Bytes Order | Field | Type | Comment | Bytes Examplle |
0 | type | string | Swap | 0x0b |
1 | accountId | number | Your account ID. | 0x000146d6 |
2 | from | address | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | The pair's address. | 0xf005ab93a5ede376de898f0980cc63b460273e3d |
4 | tokenIn | number | The ID of the token you want to swap in. | 0x0001 |
5 | amountIn | string | The amount you want to swap in. | 0x4a817c8009 |
6 | tokenOut | number | The ID of the token you want to swap out. | 0x001d |
7 | amountOutMin | string | The minimum amount you want to swap out. | 0x003bfab660 |
8 | feeIn | string | Always "0". | 0x0000 |
9 | chainId | number | 10 for mainnet, 3 for ropsten. | 0x0a |
10 | nonce | number | Your current nonce. | 0x00000003 |
- | signature | object | Contains your pubKey and signature. | ​ |
Full Bytes Example
0x0b000146d6026a25efbcefb2e481d005e4f00ccced0af511fff005ab93a5ede376de898f0980cc63b460273e3d00014a817c8009001d003bfab66000000a00000003
Signed Transaction Example
{
"type": "Swap",
"accountId": 83670,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0xf005ab93a5ede376de898f0980cc63b460273e3d",
"tokenIn": 1,
"tokenOut": 29,
"amountIn": "10000000000000000000",
"amountOutMin": "31446451",
"feeIn": "0",
"chainId": 10,
"nonce": 3,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "8883428c7787ca9e92dda23c6161293acc4cd9b07b480b11021a54a229bd942ae2e3e95f8963ed6403395020487a1c176cddfa69abe8c48c00e0a52b25971f02"
}
}
ETH Signature
Message Template
Message Example
Signature
Swap {readableAmontIn} {tokenInSymbol}
Minimum: {readableAmontOutMin} {tokenOutSymbol}
To: {pairAddress}
ChainId {chainId}
Nonce: {nonce}
Fee: 0.0 {tokenInSymbol}
Account Id: {accountId}
Swap 10.0 ZKS
Minimum: 31.446451 USDT
To: 0xf005ab93a5ede376de898f0980cc63b460273e3d
ChainId 10
Nonce: 3
Fee: 0.0 ZKS
Account Id: 83670
{
"type": "EthereumSignature",
"signature": "0x18eefc084207b628945b98d30d051965a616c9d7af65e6475444b50870a98fec3277d82259e24d832f50a512475e795b284ccbac8c128ba82aa269849c4262bf1c"
}
Transaction Fields
Bytes Order | Field | Type | Comment | Bytes Examplle |
0 | type | string | AddLiquidity | 0x09 |
1 | accountId | number | Your account ID. | 0x000146d6 |
2 | from | address | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | The pair's address. | 0xf005ab93a5ede376de898f0980cc63b460273e3d |
4 | tokenA | number | The ID of the token A. | 0x0001 |
5 | amountADesired | number | The amount of token A you want to add to the pair. | 0x4a817c8009 |
6 | amountAMin | string | The minimum amount of Token A you want to add to the pair. | 0x4a221e7009 |
7 | tokenB | number | The ID of the token B. | 0x001d |
8 | amountBDesired | string | The amount of token B you want to add to the pair. | 0x003b9049e0 |
9 | amountBMin | string | The minimum amount of Token B you want to add to the pair. | 0x003b440c00 |
10 | tokenLiquidity | number | The pair ID. | 0x0080 |
11 | feeA | string | Charged fee for token A | 0x0000 |
12 | feeB | string | Charged fee for token B | 0x0000 |
13 | chainId | number | 10 for mainnet, 3 for ropsten. | 0x0a |
14 | nonce | number | Your current nonce. | 0x00000003 |
- | signature | object | Contains your pubKey and signature. | ​ |
Full Bytes Example
0x09000146d6026a25efbcefb2e481d005e4f00ccced0af511fff005ab93a5ede376de898f0980cc63b460273e3d00014a817c80094a221e7009001d003b9049e0003b440c000080000000000a00000004
Signed Transaction Example
{
"type": "AddLiquidity",
"accountId": 83670,
"from": "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF",
"to": "0xf005ab93a5ede376de898f0980cc63b460273e3d",
"tokenA": 1,
"tokenB": 29,
"tokenLiquidity": 128,
"amountADesired": "10000000000000000000",
"amountBDesired": "31228495",
"amountAMin": "9950000000000000000",
"amountBMin": "31072352",
"feeA": "0",
"feeB": "0",
"chainId": 10,
"nonce": 4,
"signature": {
"pubKey": "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204",
"signature": "40474f11c8c5826473969ffb6f8a4c5c15df8875c24faf07ee1f749d97f66e06dc1672a70ab79469affa953e3a37199725cf423929489ef99ae1b9293a771b01"
}
}
ETH Signature
Message Template
Message Example
Signature
AddLiquidity {pairSymbol}
Desired: {readableAmontA} {tokenASymbol} {readableAmontB} {tokenBSymbol}
Minimum: {readableAmontAMin} {tokenASymbol} {readableAmontBMin} {tokenBSymbol}
To: {pairAddress}
ChainId {chainId}
Nonce: {nonce}
Fee: {readableFeeA} {tokenASymbol} {readableFeeB} {tokenBSymbol}
Account Id: {accountId}
AddLiquidity liquidity_1_29
Desired: 10.0 ZKS 31.228495 USDT
Minimum: 9.95 ZKS 31.072352 USDT
To: 0xf005ab93a5ede376de898f0980cc63b460273e3d
ChainId 10
Nonce: 4
Fee: 0.0 ZKS 0.0 USDT
Account Id: 83670
{
"type": "EthereumSignature",
"signature": "0x365b5c64738f425743728b5615f6e428d9a6c3ca333cf9630602e283e2efaadf26194be778fe7a15532b4768b385b4339c739ac22cffba4f94ef8d594f415d021b"
}
Transaction Fields
Bytes Order | Field | Type | Comment | Bytes Examplle |
0 | type | string | RemoveLiquidity | 0x0a |
1 | accountId | number | Your account ID. | 0x000146d6 |
2 | from | address | Your address. | 0x026a25efbcefb2e481d005e4f00ccced0af511ff |
3 | to | address | The pair's address. | 0xf005ab93a5ede376de898f0980cc63b460273e3d |
4 | tokenA | number | The ID of token A. | 0x0001 |
5 | amountAMin | string | The minimum amount of Token A you want to remove from the pair. | 0x4a221e68e9 |
6 | feeA | string | Charged fee for token A | 0x0000 |
7 | tokenB | number | The ID of the token B. | 0x001d |
8 | amountBMin | string | The minimum amount of Token B you want to remove from the pair. | 0x003b440c00 |
9 | feeB | string | Charged fee for token B | 0x0000 |
10 | tokenLiquidity | number | The pair ID. | 0x0080 |
11 | amountLiquidity | string | The amount of LP token you want to remove. | 0x1da59cc1a3 |
12 | chainId | number | 10 for mainnet, 3 for ropsten. | 0x0a |
13 | nonce | number | Your current nonce. | 0x00000005 |
- | signature | object | Contains your pubKey and signature. |