Go SDK

ZKsync Era Features

An overview of ZKsync Era features

While ZKsync Era is mostly Web3-compatible, it has some differences compared to Ethereum. The major of those are:

  • Account abstraction support (accounts may have near-arbitrary validation logic, and also paymaster support is enabled).
  • Deployment transactions require the contracts' bytecode to be passed in a separate field.
  • The fee system is somewhat different.

These require us to extend standard Ethereum transactions with new custom fields. Such extended transactions are called EIP-712 transactions since EIP-712 is used to sign them. You can look at the internal structure of the EIP-712 transactions in the ZKsync documentation.

This document will focus solely on how to pass these arguments to the SDK.

EIP-712 support

The following objects provides support for utilizing ZKsync features:

Encoding paymaster params

While the paymaster feature by itself does not impose any limitations on values of the paymasterInput, the Matter Labs team endorses certain types of paymaster flows that are processable by EOAs.

ZKsync SDK provides a utility method that can be used to get the correctly formed PaymasterParams object: GetPaymasterParams.

See in action

If you want to call the method setGreeting of a contract called greeter, this would look the following way, while paying fees with the testnet paymaster:

PrivateKey     := os.Getenv("PRIVATE_KEY")
ZkSyncEraProvider := "https://testnet.era.zksync.dev"

TokenAddress   := common.HexToAddress("<Token address>")
GreeterAddress := common.HexToAddress("<Greeter contract address>")
ReceiptAddress := common.HexToAddress("<Receipt address>")


client, err := clients.Dial(ZkSyncEraProvider)
if err != nil {
    log.Panic(err)
}
defer client.Close()


ethClient, err := ethclient.Dial(EthereumProvider)
if err != nil {
  log.Panic(err)
}
defer ethClient.Close()

// Create wallet
wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), client, ethClient)
if err != nil {
    log.Panic(err)
}

abi, err := greeter.GreeterMetaData.GetAbi()
if err != nil {
    log.Panic(err)
}

// Encode transfer function from token contract
calldata, err := abi.Pack("setGreeting")
if err != nil {
    log.Panic(err)
}

gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
    log.Panic(err)
}

gas, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
    From: wallet.Address(),
    To:   ReceiptAddress,
    Data: calldata,
})
if err != nil {
  log.Panic(err)
}

testnetPaymaster, err := client.TestnetPaymaster(context.Background())
if err != nil {
    log.Panic(err)
}

// Create paymaster parameters with encoded paymaster input
paymasterParams, err := utils.GetPaymasterParams(
    PaymasterAddress,
    &zkTypes.ApprovalBasedPaymasterInput{
        Token:            testnetPaymaster,
        MinimalAllowance: new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas)),
        InnerInput:       []byte{},
    })
if err != nil {
    log.Panic(err)
}

hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{
    To:   &TokenAddress,
    Data: calldata,
    Meta: &types.Eip712Meta{
        PaymasterParams: paymasterParams,
    },
})
if err != nil {
    log.Panic(err)
}

_, err = client.WaitMined(context.Background(), hash)
if err != nil {
    log.Panic(err)
}

fmt.Println("Tx: ", hash)

Made with ❤️ by the ZKsync Community