SmartAccount Utilities
The SmartAccount Utilities
provide functions for signing payloads and populating transactions using ECDSA and
multiple ECDSA keys. These utilities offer flexibility and ease of use for developers working with smart accounts in
the ZKsync Era.
Functions
PopulateTransactionECDSA
Populates missing properties meant for signing using an ECDSA private key:
- Populates tx.From using the address derived from the ECDSA private key.
- Populates tx.Nonce via client.NonceAt().
- Populates tx.Gas via client.EstimateGasL2(). If tx.From is not EOA, the estimation is done with address derived from the ECDSA private key.
- Populates tx.GasFeeCap via client.SuggestGasPrice().
- Populates tx.GasTipCap with 0 if is not set.
- Populates tx.ChainID via client.ChainID().
- Populates tx.Data with "0x".
- Populates tx.Meta.GasPerPubdata with utils.DefaultGasPerPubdataLimit.
Expects the secret to be ECDSA private in hex format.
Inputs
Parameter | Type | Description |
---|---|---|
ctx | context.Context | Context. |
tx | *zkTypes.Transaction | The transaction that needs to be populated. |
secret | string | The ECDSA private key. |
client | *clients.Client | The client which fetches data from the network. |
var PopulateTransactionECDSA TransactionBuilder = func(ctx context.Context, tx *zkTypes.Transaction, secret interface{}, client *clients.Client) error
Examples
privateKey := os.Getenv("PRIVATE_KEY")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
tx := zkTypes.Transaction{
To: &Address2,
Value: big.NewInt(7_000_000_000),
From: &Address1,
}
err = accounts.PopulateTransactionECDSA(context.Background(), &tx, privateKey, client)
if err != nil {
log.Panic(err)
}
PopulateTransactionMultipleECDSA
Populates missing properties meant for signing using multiple ECDSA private keys.
It uses PopulateTransactionECDSA
, where the address of the first
ECDSA key is set as the secret argument.
Expects the secret to be a slice of ECDSA private in hex format.
Inputs
Parameter | Type | Description |
---|---|---|
ctx | context.Context | Context. |
tx | *zkTypes.Transaction | The transaction that needs to be populated. |
secret | []string | The list of the ECDSA private keys. |
client | *clients.Client | The client which fetches data from the network. |
var PopulateTransactionMultipleECDSA TransactionBuilder = func(ctx context.Context, tx *zkTypes.Transaction, secret interface{}, client *clients.Client) error
Examples
privateKey1 := os.Getenv("PRIVATE_KEY1")
privateKey2 := os.Getenv("PRIVATE_KEY2")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
tx := zkTypes.Transaction{
To: &Address2,
Value: big.NewInt(7_000_000_000),
From: &Address1,
}
err = accounts.PopulateTransactionECDSA(context.Background(), &tx, privateKey, client)
if err != nil {
log.Panic(err)
}
SignPayloadWithECDSA
Implementation of PayloadSigner
which signs the payload using
an ECDSA private key.
Inputs
Parameter | Type | Description |
---|---|---|
ctx | context.Context | Context. |
payload | []byte | The payload that needs to be signed. |
secret | string | The ECDSA private key. |
client | *clients.Client | Not used and should be nil . |
var SignPayloadWithECDSA PayloadSigner = func(ctx context.Context, payload []byte, secret interface{}, client *clients.Client) ([]byte, error)
Examples
Sign EIP712 transaction hash.
privateKey := os.Getenv("PRIVATE_KEY")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
chainId, err := client.ChainID(context.Background())
if err != nil {
log.Panic(err)
}
tx := zkTypes.Transaction{
Nonce: big.NewInt(0),
GasTipCap: big.NewInt(0),
GasFeeCap: big.NewInt(1_000_000_000),
Gas: big.NewInt(1_000_000_000),
To: &Address2,
Value: big.NewInt(7_000_000_000),
Data: hexutil.Bytes{},
ChainID: chainId,
From: &Address1,
Meta: &zkTypes.Eip712Meta{
GasPerPubdata: utils.NewBig(utils.DefaultGasPerPubdataLimit.Int64()),
},
}
domain := eip712.ZkSyncEraEIP712Domain(chainId.Int64())
eip712Msg, err := tx.EIP712Message()
if err != nil {
log.Panic(err)
}
hash, _, err := apitypes.TypedDataAndHash(apitypes.TypedData{
Types: apitypes.Types{
tx.EIP712Type(): tx.EIP712Types(),
domain.EIP712Type(): domain.EIP712Types(),
},
PrimaryType: tx.EIP712Type(),
Domain: domain.EIP712Domain(),
Message: eip712Msg,
})
if err != nil {
log.Panic(err)
}
signature, err := accounts.SignPayloadWithECDSA(context.Background(), hash, privateKey, nil)
if err != nil {
log.Panic(err)
}
Sign message hash.
privateKey := os.Getenv("PRIVATE_KEY")
signature, err := accounts.SignPayloadWithECDSA(context.Background(), ethAccounts.TextHash([]byte("Hello World!")), privateKey, nil)
if err != nil {
log.Panic(err)
}
Sign typed data hash.
privateKey := os.Getenv("PRIVATE_KEY")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
chainId, err := client.ChainID(context.Background())
if err != nil {
log.Panic(err)
}
hash, _, err := apitypes.TypedDataAndHash(apitypes.TypedData{
Domain: apitypes.TypedDataDomain{
Name: "Example",
Version: "1",
ChainId: math.NewHexOrDecimal256(chainId.Int64()),
},
Types: apitypes.Types{
"Person": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "age", Type: "uint8"},
},
"EIP712Domain": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
},
},
PrimaryType: "Person",
Message: apitypes.TypedDataMessage{
"name": "John",
"age": hexutil.EncodeUint64(30),
},
})
if err != nil {
log.Panic(err)
}
signature, err := accounts.SignPayloadWithECDSA(context.Background(), hash, privateKey, nil)
if err != nil {
log.Panic(err)
}
SignPayloadWithMultipleECDSA
Implementation of PayloadSigner
which signs the payload using
multiple ECDSA private keys.
The signature is generated by concatenating signatures created by signing with each key individually.
The length of the resulting signature is len(secret) * 65
.
Inputs
Parameter | Type | Description |
---|---|---|
ctx | context.Context | Context. |
payload | []byte | The payload that needs to be signed. |
secret | []string | The list of the ECDSA private keys. |
client | *clients.Client | Not used and should be nil . |
var SignPayloadWithMultipleECDSA PayloadSigner = func(ctx context.Context, payload []byte, secret interface{}, client *clients.Client) ([]byte, error)
Examples
Sign EIP712 transaction hash.
privateKey1 := os.Getenv("PRIVATE_KEY1")
privateKey2 := os.Getenv("PRIVATE_KEY2")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
chainId, err := client.ChainID(context.Background())
if err != nil {
log.Panic(err)
}
tx := zkTypes.Transaction{
Nonce: big.NewInt(0),
GasTipCap: big.NewInt(0),
GasFeeCap: big.NewInt(1_000_000_000),
Gas: big.NewInt(1_000_000_000),
To: &Address2,
Value: big.NewInt(7_000_000_000),
Data: hexutil.Bytes{},
ChainID: big.NewInt(270),
From: &Address1,
Meta: &zkTypes.Eip712Meta{
GasPerPubdata: utils.NewBig(utils.DefaultGasPerPubdataLimit.Int64()),
},
}
domain := eip712.ZkSyncEraEIP712Domain(chainId.Int64())
eip712Msg, err := tx.EIP712Message()
if err != nil {
log.Panic(err)
}
hash, _, err := apitypes.TypedDataAndHash(apitypes.TypedData{
Types: apitypes.Types{
tx.EIP712Type(): tx.EIP712Types(),
domain.EIP712Type(): domain.EIP712Types(),
},
PrimaryType: tx.EIP712Type(),
Domain: domain.EIP712Domain(),
Message: eip712Msg,
})
if err != nil {
log.Panic(err)
}
signature, err := accounts.SignPayloadWithMultipleECDSA(context.Background(), hash, []string{privateKey1, privateKey2}, nil)
if err != nil {
log.Panic(err)
}
Sign message hash.
privateKey1 := os.Getenv("PRIVATE_KEY1")
privateKey2 := os.Getenv("PRIVATE_KEY2")
signature, err := accounts.SignPayloadWithMultipleECDSA(context.Background(), hash, []string{privateKey1, privateKey2}, nil)
if err != nil {
log.Panic(err)
}
Sign typed data hash.
privateKey1 := os.Getenv("PRIVATE_KEY1")
privateKey2 := os.Getenv("PRIVATE_KEY2")
client, err := clients.DialBase(ZkSyncEraProvider)
if err != nil {
log.Panic(err)
}
defer client.Close()
chainId, err := client.ChainID(context.Background())
if err != nil {
log.Panic(err)
}
hash, _, err := apitypes.TypedDataAndHash(apitypes.TypedData{
Domain: apitypes.TypedDataDomain{
Name: "Example",
Version: "1",
ChainId: math.NewHexOrDecimal256(chainId.Int64()),
},
Types: apitypes.Types{
"Person": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "age", Type: "uint8"},
},
"EIP712Domain": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
},
},
PrimaryType: "Person",
Message: apitypes.TypedDataMessage{
"name": "John",
"age": hexutil.EncodeUint64(30),
},
})
if err != nil {
log.Panic(err)
}
signature, err := accounts.SignPayloadWithMultipleECDSA(context.Background(), hash, []string{privateKey1, privateKey2}, nil)
if err != nil {
log.Panic(err)
}