In the following article, we will use this wallet as example:
Copy Address : 0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF
Private Key : 0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf
Layer-1
The only transaction that made on Layer-1 is deposit. It has two sub-types which are DepositETH
and DepositERC20
.
ABIs
Copy [
{
"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"
}
]
Deposit ETH
Example Code:
Copy 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)
Deposit ERC20
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:
Copy 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)
Layer-2
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.
Private Key
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
Copy Access ZKSwap account.
Only sign this message for a trusted client!
Copy const msg = 'Access ZKSwap account.\n\nOnly sign this message for a trusted client!'
Here's a full example of getting private key using zksync-crypto in JavaScript.
Copy 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)
Public Key Hash
After getting private key, you will need to register you publick key hash to ZKSwap so that it can verify transations that you sent.
Copy 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 ) } `
Signature
Before submit transaction to ZKSwap, you need to sign the the transaction data.
Copy 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)
Change Public Key
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
Signed Transaction Example
Copy {
"type" : "ChangePubKey" ,
"accountId" : 83670 ,
"account" : "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF" ,
"newPkHash" : "sync:83f62ba777515089eb905a375f77f59ddfada116" ,
"nonce" : 0 ,
"ethSignature" : "0x66c1ef3611a634e400301375b291a0835b0e31237273e1bdab45acc3ef27c761674fd5e5a706566e5175e8e18306f5b8d1d36016f3894e84d527c3c97e92bcf71c"
}
ETH Signature
Message Template Message Example Signature
Copy Register ZKSwap pubkey:
{pubKeyHash}
nonce: {hexlifiedNonce}
account id: {hexlifiedAccountId}
Only sign this message for a trusted client!
Copy Register ZKSwap pubkey:
83f62ba777515089eb905a375f77f59ddfada116
nonce: 0x00000000
account id: 0x000146d6
Only sign this message for a trusted client!
Copy 0x66c1ef3611a634e400301375b291a0835b0e31237273e1bdab45acc3ef27c761674fd5e5a706566e5175e8e18306f5b8d1d36016f3894e84d527c3c97e92bcf71c
NOTE : The {pubKeyHash}
in the above message doesn't contain 0x as prefix. The {hexlifiedNonce}
and {hexlifiedAccountId}
has 4-bytes length with 0 padding in the start and 0x as prefx. See example for reference.
Transfer
Transaction Fields
0x026a25efbcefb2e481d005e4f00ccced0af511ff
The target address you want to transfer.
0x961b513dfd3e363c238e0f98219ee02552a847bd
The packed amount you want to transfer.
11 for mainnet, 128 for ropsten.
Contains your pubKey
and signature.
Full Bytes Example
Copy 0x050000053a026a25efbcefb2e481d005e4f00ccced0af511ff961b513dfd3e363c238e0f98219ee02552a847bd000a4a817c80080a00000b00000001
Signed Transaction Example
Copy {
"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 Signature
Message Template Message Example Signature
Copy Transfer {readableAmount} {tokenSymbol}
To: {to}
Chain Id: {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Copy Transfer 1.0 ZKS
To: 0x961b513dfd3e363c238e0f98219ee02552a847bd
Chain Id: 11
Nonce: 1
Fee: 0.0 ZKS
Account Id: 1338
Copy {
"type" : "EthereumSignature" ,
"signature" : "0xbf8fa93e7da866aa3acb07a6a826e5e61195eba04e3c72a4f02b8fc8221da1f764363817968576013ca515ffe5e1104b5890937150883f3304d0738777af915b1c"
}
Withdraw
Transaction Fields
0x026a25efbcefb2e481d005e4f00ccced0af511ff
The target address you want to withdraw to.
0x026a25efbcefb2e481d005e4f00ccced0af511ff
The ID of the token you want to withdraw.
The amount you want to withdraw.
0x00000000000000000de0b6b3a7640000
11 for mainnet, 128 for ropsten.
Contains your pubKey
and signature.
Full Bytes Example
Copy 0x030000053a026a25efbcefb2e481d005e4f00ccced0af511ff026a25efbcefb2e481d005e4f00ccced0af511ff000a00000000000000000de0b6b3a76400000a4bf00b00000002
Signed Transaction Example
Copy {
"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 Signature
Message Template Message Example Signature
Copy Withdraw {readableAmount} {tokenSymbol}
To: {to}
Chain Id: {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Copy Withdraw 3.4226556417 ZKS
To: 0x026a25efbcefb2e481d005e4f00ccced0af511ff
ChainId 10
Nonce: 2
Fee: 1.577 ZKS
Account Id: 83670
Copy {
"type" : "EthereumSignature" ,
"signature" : "0x0440667d6a694b76e5f3a51fa3981a3db95bfc7d3feeb301f403ea6f3bef01d32c9e06920f7b13edd92a6cb22f49d6709fb4f9d41efc09b0a094173b6bbb4f121b"
}
Swap
Fee
Let's take swap token A for token B as example. There are two cases:
If A is a fee token, the fee token of swap is A. The number of fee is calculated by amountIn * 5 / 9995
If A is not a fee token, the fee token of swap is B. The number of fee is amountOut * 5 /10000
. It's not amountOutMin
. amountOut
equals amountOutMin
then slipplage is 0.
Transaction Fields
0x026a25efbcefb2e481d005e4f00ccced0af511ff
0xaa45c964e21eafb38574e9d000adbaf85acfbb80
The ID of the token you want to swap in.
The amount you want to swap in.
The ID of the token you want to swap out.
The minimum amount you want to swap out.
11 for mainnet, 128 for ropsten.
Contains your pubKey
and signature.
Full Bytes Example
Copy 0x0b0000053a026a25efbcefb2e481d005e4f00ccced0af511ffaa45c964e21eafb38574e9d000adbaf85acfbb80000a94efe63009000025004d47c60a7d0d0b00000003
Signed Transaction Example
Copy {
"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 Signature
Message Template Message Example Signature
Copy Swap {readableAmontIn} {tokenInSymbol}
Minimum: {readableAmontOutMin} {tokenOutSymbol}
To: {pairAddress}
Chain Id: {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Copy Swap 19.99 ZKS
Minimum: 0.004966214206 ETH
To: 0xaa45c964e21eafb38574e9d000adbaf85acfbb80
Chain Id: 11
Nonce: 3
Fee: 0.01 ZKS
Account Id: 1338
Copy {
"type" : "EthereumSignature" ,
"signature" : "0x66ca505f09e2dbd2aaaa809cac3ec7085ea7831ec58c695566190588a2ced45c0d7e1c235840dd3f547d54ad87e6740bb3d299a89d36460b9eb1e56b25456ef41b"
}
Add Liquidity
Transaction Fields
0x026a25efbcefb2e481d005e4f00ccced0af511ff
0xaa45c964e21eafb38574e9d000adbaf85acfbb80
The amount of token A you want to add to the pair.
The minimum amount of Token A you want to add to the pair.
The amount of token B you want to add to the pair.
The minimum amount of Token B you want to add to the pair.
11 for mainnet, 128 for ropsten.
Contains your pubKey
and signature.
Full Bytes Example
Copy 0x090000053a026a25efbcefb2e481d005e4f00ccced0af511ffaa45c964e21eafb38574e9d000adbaf85acfbb800000c2cf6f3245b911dcd625000a4a817c800946c7cfe00940020a00000b00000004
Signed Transaction Example
Copy {
"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 Signature
Message Template Message Example Signature
Copy AddLiquidity {pairSymbol}
Desired: {readableAmontA} {tokenASymbol} {readableAmontB} {tokenBSymbol}
Minimum: {readableAmontAMin} {tokenASymbol} {readableAmontBMin} {tokenBSymbol}
To: {pairAddress}
Chain Id: {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Copy AddLiquidity liquidity_0_10
Desired: 0.0026146994578 ETH 10.0 ZKS
Minimum: 0.0024839644849 ETH 9.5 ZKS
To: 0xaa45c964e21eafb38574e9d000adbaf85acfbb80
Chain Id: 11
Nonce: 4
Fee: 0.0 ZKS
Account Id: 1338
Copy {
"type" : "EthereumSignature" ,
"signature" : "0x20c1c26e8f678220189f0a4a444e1686e969faa536a17abc1a30a113d6e4bfc12aa88a2075693857ea410f439d28467b01666bcb01d1b6bb7b8ce3641bd6daea1b"
}
Remove Liquidity
Transaction Fields
0x026a25efbcefb2e481d005e4f00ccced0af511ff
0xaa45c964e21eafb38574e9d000adbaf85acfbb80
The minimum amount of Token A you want to remove from the pair.
The minimum amount of Token B you want to remove from the pair.
The amount of LP token you want to remove.
11 for mainnet, 128 for ropsten.
Contains your pubKey
and signature.
Full Bytes Example
Copy 0x0a0000053a026a25efbcefb2e481d005e4f00ccced0af511ffaa45c964e21eafb38574e9d000adbaf85acfbb800000b96855c485000a46a6e210490a0000400277e80cdba70b00000005
Signed Transaction Example
Copy {
"type" : "RemoveLiquidity" ,
"accountId" : 1338 ,
"from" : "0x026A25EfbcEFb2e481d005E4F00Ccced0AF511FF" ,
"to" : "0xaa45c964e21eafb38574e9d000adbaf85acfbb80" ,
"tokenA" : 0 ,
"tokenB" : 10 ,
"amountAMin" : "2488498128400000" ,
"amountBMin" : "9482735746000000000" ,
"tokenLiquidity" : 16386 ,
"amountLiquidity" : "160935707810000000" ,
"feeToken" : 10 ,
"fee" : "0" ,
"chainId" : 11 ,
"nonce" : 5 ,
"signature" : {
"pubKey" : "110ffd569daaee30068fc3c85922d1237f63a41d4749d464b883131e92369204" ,
"signature" : "bf0e5c3639e9f9f837e2d141fa9481da8e11574001dbe8cd81cb3005c9cac69ae05655d416cd53bedd27142235ad5743e9f26b66ac8643d859d0c8caf149a700"
}
}
ETH Signature
Message Template Message Example Signature
Copy RemoveLiquidity {readableLiquidityAmount} {pairSymbol}
Minimum: {readableAmontAMin} {tokenASymbol} {readableAmontBMin} {tokenBSymbol}
To: {pairAddress}
Chain Id: {chainId}
Nonce: {nonce}
Fee: {readableFee} {feeTokenSymbol}
Account Id: {accountId}
Copy RemoveLiquidity 0.16093570781 liquidity_0_10
Minimum: 0.0024884981284 ETH 9.482735746 ZKS
To: 0xaa45c964e21eafb38574e9d000adbaf85acfbb80
Chain Id: 11
Nonce: 5
Fee: 0.0 ZKS
Account Id: 1338
Copy {
"type": "EthereumSignature",
"signature": "0x85ce1409808a56b4522b6787d397d4b5d04a926e701a72b1388fff74f447650b1789c6bb7487b638bb1f6100faaa318b37311d831f07252bd0971331e61b8ad51b"
}