2

The ZkSync documentation states that a deposit has to be made from an existing Ethereum account to a non-existing ZkSync account counterfactually in order to create a new account.

However, the method that is used to make the deposit already takes a ZkSync account address as a parameter to specify the recipient:

/// @notice Deposit ETH to Layer 2 - transfer ether from user into contract, validate it, register deposit
/// @param _zkSyncAddress The receiver Layer 2 address
function depositETH(address _zkSyncAddress) external payable {
    require(_zkSyncAddress != SPECIAL_ACCOUNT_ADDRESS, "P");
    require(msg.value > 0, "M"); // Zero-value deposits are forbidden by zkSync rollup logic
    requireActive();
    registerDeposit(0, SafeCast.toUint128(msg.value), _zkSyncAddress);
}

How do we pass a ZkSync account address if that's the very thing we're trying to achieve?

If you take a look at one of examples the ZkSync team provided for the Swift SDK:

let ethereumProvider = try self.wallet.createEthereumProvider(web3: Web3.InfuraRinkebyWeb3())

firstly {
    ethereumProvider.deposit(token: .ETH,
                             amount: amount,
                             userAddress: wallet.address) /// Ethereum wallet address is provided
}.done { (_) in
    self.present(UIAlertController.for(message: "Successfully deposited"), animated: true, completion: nil)
}.catch { (error) in
    self.present(UIAlertController.for(error: error), animated: true, completion: nil)
}

The parameter for the deposit is the address of the sender which is the account on the Ethereum network, not ZkSync.

Source

func depositETH(address: EthereumAddress, value: BigUInt) -> Promise<TransactionSendingResult> {
    guard let tx = self.contract.write("depositETH",
                                       parameters: [address] as [AnyObject], // here the parameter passed for the depositETH method of the smart contract is the address of the sender's account, which is the Ethereum account.
                                       transactionOptions: createOptions(value: value)) else {
        return Promise(error: ZkSyncContractError.invalidParameters)
    }

    return tx.sendPromise()
}

If you execute above code, you get the following error:

enter image description here

This mysterious error seems to indicate a connection error according to the web3swift source code, since it seems to say error 1.

public enum Web3Error: Error {
    case transactionSerializationError
    case connectionError
    case dataError
    case walletError
    case inputError(desc:String)
    case nodeError(desc:String)
    case processingError(desc:String)
    case keystoreError(err:AbstractKeystoreError)
    case generalError(err:Error)
    case unknownError

So what address do you have to pass to the deposit method in order to create a new ZkSync account? Is the Swift SDK example correct by passing a sender's address of an Ethereum account? If so, what is the source of the error?

Update

The sequence of the deposit process in the Swift SDK's example code goes something like following:

  1. A wallet is created
guard let wallet = try? DefaultWallet<ChangePubKeyECDSA, DefaultEthSigner>(ethSigner: ethSigner,
                                                                           zkSigner: zkSigner,
                                                                           provider: provider) else {
    fatalError()
}
  1. The wallet is passed to a depositing view controller and is used to send a deposit.
let ethereumProvider = try self.wallet.createEthereumProvider(web3: Web3.InfuraRinkebyWeb3())

firstly {
    ethereumProvider.deposit(token: .ETH,
                             amount: amount,
                             userAddress: wallet.address)
}.done { (_) in
    self.present(UIAlertController.for(message: "Successfully deposited"), animated: true, completion: nil)
}.catch { (error) in
    self.present(UIAlertController.for(error: error), animated: true, completion: nil)
}

But, if my understanding if correct, the userAddress parameter in the deposit method is supposed to be the recipient's address. wallet.address, however, is the address of the sender.

public var address: String {
    self.ethSigner.address
}

Prior to calling the deposit method, I generated a new Ethereum address to send the funds to in hopes that it could generate a new account in Zksync, but still got the same error.

KeysService().getWalletPrivateKey(password: password, completion: { [weak self] privateKey, error in
    if let error = error {
        print(error)
    }
    
    if let privateKey = privateKey {
        do {

            guard let newWallet = self?.createZKWallet(.rinkeby, privateKey: privateKey) else { return }
            let ethereumProvider = try newWallet.createEthereumProvider(web3: Web3.InfuraRinkebyWeb3())

            firstly {
                ethereumProvider.deposit(token: .ETH,
                                         amount: amount,
                                         userAddress: newWallet.address)
            }.done { (_) in
                self?.present(UIAlertController.for(message: "Successfully deposited"), animated: true, completion: nil)
            }.catch { (error) in
                self?.present(UIAlertController.for(error: error), animated: true, completion: nil)
            }
        } catch {
            self?.present(UIAlertController.for(error: error), animated: true, completion: nil)
        }
    }
})
Kevvv
  • 3,655
  • 10
  • 44
  • 90
  • Instead of just presenting the error, you can cast it to an Web3Error and investigate which enum case it is. I.e. in catch scope, – Sajjon Apr 25 '22 at 07:04
  • @Sajjon The problem is the error occurs some time after the deposit process seems to have finished from the client's end as if it's triggered by an `Event` being emitted in response to the deposit. So I'm having a hard time tracing the root of this `Web3Error` – Kevvv Apr 25 '22 at 11:51
  • I was merely suggesting that you investigate the exact error you get. Which you can do if you cast it or maybe debug print it. – Sajjon Apr 25 '22 at 12:12
  • Do you have funds from the sender to do the transaction + deposit? How do you initialize the ethereum client? A full snippet of the code you use will be helpful to resolve your problem – DarthMike Apr 26 '22 at 12:25
  • See response below, saw you were running the example in the sdk – DarthMike Apr 26 '22 at 12:40
  • @Kevvv Deposit can be to same address as in Ethereum, or a different one. It doesn't matter from the smart contract point of view. It's just bridging funds from L1 to L2. The SDK example hardcodes to deposit to self (that means deposit to my address in zksync, from my address in ethereum) but could be to other address. – DarthMike Apr 27 '22 at 17:03

2 Answers2

2

You need to pass a new address (recipient address). Can't send from a 'non-existing' address as you state.

You can 'create' the address by generating it randomly from a private key, or by copying it if you know the address already.

Related to your problem, the example app uses an account that currently doesn't have any funds on Ethereum (0x46a23e25df9a0f6c18729dda9ad1af3b6a131160) (see screenshot). I've sent a small amount and it will work now.

enter image description here

DarthMike
  • 3,471
  • 1
  • 22
  • 18
  • Thanks for the reply. Can I ask you if the deposit worked when you tried for this example? I actually did have enough balance in the Ethereum side of the account when I tried it, but wasn't working. Upon your recommendation, I generated a new *Ethereum* address using a private key and used the `deposit` method in question to deposit the fund to this newly generated Ethereum address, but still got the same error. Please see my updated question. – Kevvv Apr 26 '22 at 19:29
  • Also, I think my wording wasn't clear, but I wasn't implying that the funds had to be deposited FROM a non-existing account, but rather TO a non-existing account.It's my understanding when you're depositing funds from an Ethereum account to a ZkSync account, the ZkSync account doesn't exist yet and this is the way to create a new ZkSync account, which is what I gathered from the [doc](https://docs.zksync.io/dev/payments/basic.html#creating-an-account): "Accounts in zkSync can be created by either doing a deposit of funds from Ethereum or by transferring funds in zkSync to the desired address." – Kevvv Apr 26 '22 at 19:31
  • It did work correctly for me after I added the balance to the account. – DarthMike Apr 27 '22 at 11:28
  • @Kevvv Deposit can be to same address as in Ethereum, or a different one. It doesn't matter from the smart contract point of view. It's just bridging funds from L1 to L2. The SDK example hardcodes to deposit to self (that means deposit to my address in zksync, from my address in ethereum) – DarthMike Apr 27 '22 at 16:49
  • Thank you for that explanation! That makes a lot of sense. Do you think maybe I could share my code with you to see what's wrong with it because it's odd that I'm getting the "connection error" even though I haven't strayed away from the sample code much, except for the generation of private keys. – Kevvv Apr 27 '22 at 20:10
0

to create a zkSync account we need to interact with our wallet somehow: f.e.: We can make a deposit from any decentralized wallet L1→L2 and it will mean that account was created or make a transfer to the existing address l2→l2 and it will be also workable. But to work with this funds we will need activate our L2 - make CPK, pay some fee. Otherwise we will need to do alternative withdraw.

bxpana
  • 1