Skip to content

Commit

Permalink
feat: starknet support cairo 0 address.
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhangguiguang committed Jan 4, 2024
1 parent 8a34f3b commit 35c12ac
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 27 deletions.
8 changes: 8 additions & 0 deletions core/base/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ func NewOptionalBool(b bool) *OptionalBool {
return &OptionalBool{Value: b}
}

type OptionalInt struct {
Value int
}

func NewOptionalInt(i int) *OptionalInt {
return &OptionalInt{Value: i}
}

type safeMap struct {
sync.RWMutex
Map map[interface{}]interface{}
Expand Down
15 changes: 14 additions & 1 deletion core/starknet/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import (

type Account struct {
privateKey *big.Int

// default false
Cairo0 bool
}

func grindKey(keySeed []byte) (*big.Int, error) {
Expand Down Expand Up @@ -133,7 +136,17 @@ func (a *Account) PublicKeyHex() string {

// The ethereum address is same as public key in coming
func (a *Account) Address() string {
addr, _ := EncodePublicKeyToAddress(a.PublicKeyHex())
addr, _ := encodePublicKeyToAddressArgentX(a.PublicKeyHex(), a.Cairo0)
return addr
}

func (a *Account) AddressCairo1() string {
addr, _ := encodePublicKeyToAddressArgentX(a.PublicKeyHex(), false)
return addr
}

func (a *Account) AddressCairo0() string {
addr, _ := encodePublicKeyToAddressArgentX(a.PublicKeyHex(), true)
return addr
}

Expand Down
16 changes: 14 additions & 2 deletions core/starknet/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ func TestEncodeAddress(t *testing.T) {
param := deployParamForArgentX(*mustFelt(pub))
addr, err := param.ComputeContractAddress()
require.Nil(t, err)
require.Equal(t, addr.String(), "0x7384b9770dce88ee83a62a8a0ab0fac476e513a9e4b611b80fa08e844ce1f2")
require.Equal(t, addr.String(),
"0x7384b9770dce88ee83a62a8a0ab0fac476e513a9e4b611b80fa08e844ce1f2")
}
{
// Braavos
Expand All @@ -33,7 +34,18 @@ func TestEncodeAddress(t *testing.T) {
param := deployParamForBraavos(*mustFelt(pub))
addr, err := param.ComputeContractAddress()
require.Nil(t, err)
require.Equal(t, addr.String(), "0x8debaf4740ac184b2e879d4d3fd773f2c7f5d453b795212d4098899a73fc19")
require.Equal(t, addr.String(),
"0x8debaf4740ac184b2e879d4d3fd773f2c7f5d453b795212d4098899a73fc19")
}
{
// ArgentX cairo0
// see https://testnet.starkscan.co/tx/0x0153002e687910abe1d28acbb955e45a50b6b6c53a3813ae6c3539ec1ef3c1a6
pub := "0x28081ae2bc3668241b1303df98a61e229ee760eb554f9c7fb21cd968a1b74b1"
param := deployParamForArgentXCairo0(*mustFelt(pub))
addr, err := param.ComputeContractAddress()
require.Nil(t, err)
require.Equal(t, addr.String(),
"0x3d6b3da9cfaf00482fbecd18312e5a1918744bfe6f0dd2650c4221284efce09")
}
}

Expand Down
87 changes: 74 additions & 13 deletions core/starknet/address_util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package starknet

import (
"errors"
"regexp"

"github.com/NethermindEth/juno/core/felt"
Expand Down Expand Up @@ -34,12 +35,23 @@ func (u *Util) IsValidAddress(address string) bool {

// MARK - like wallet.Util

// EncodePublicKeyToAddress
// - return: encode cairo version 1.0 address
func EncodePublicKeyToAddress(publicKey string) (string, error) {
return encodePublicKeyToAddressArgentX(publicKey)
return encodePublicKeyToAddressArgentX(publicKey, false)
}

func encodePublicKeyToAddressArgentX(publicKey string) (string, error) {
addr, err := defaultEncodeContractAddress(publicKey)
func EncodePublicKeyToAddressCairo0(publicKey string) (string, error) {
return encodePublicKeyToAddressArgentX(publicKey, true)
}

func encodePublicKeyToAddressArgentX(publicKey string, isCairo0 bool) (string, error) {
pubFelt, err := utils.HexToFelt(publicKey)
if err != nil {
return "", err
}
p := deployParamForArgentXWithVersion(*pubFelt, isCairo0)
addr, err := p.ComputeContractAddress()
if err != nil {
return "", err
}
Expand All @@ -56,6 +68,42 @@ func IsValidAddress(address string) bool {
return reg.MatchString(address)
}

// CheckCairoVersion
// - return address version, 0 for cairo0, 1 for cairo1.0
func CheckCairoVersion(address, pubkey string) (*base.OptionalInt, error) {
addrFelt, err := utils.HexToFelt(address)
if err != nil {
return nil, base.ErrInvalidAddress
}
pubFelt, err := utils.HexToFelt(pubkey)
if err != nil {
return nil, base.ErrInvalidPublicKey
}
version, err := CheckCairoVersionFelt(addrFelt, pubFelt)
if err != nil {
return nil, err
}
return base.NewOptionalInt(version), nil
}

func CheckCairoVersionFelt(address, pubkey *felt.Felt) (int, error) {
p1 := deployParamForArgentX(*pubkey)
addr, err := p1.ComputeContractAddress()
if err == nil {
if addr.Cmp(address) == 0 {
return 1, nil
}
}
p0 := deployParamForArgentXCairo0(*pubkey)
addr, err = p0.ComputeContractAddress()
if err == nil {
if addr.Cmp(address) == 0 {
return 0, nil
}
}
return -1, errors.New("the address and public key mismatch")
}

// MARK - Contract Address Generate

type deployParam struct {
Expand All @@ -70,19 +118,17 @@ func (p *deployParam) ComputeContractAddress() (*felt.Felt, error) {
return acc.PrecomputeAddress(p.Caller, &p.Pubkey, p.ClassHash, p.CallData)
}

func defaultEncodeContractAddress(pub string) (*felt.Felt, error) {
pubFelt, err := utils.HexToFelt(pub)
if err != nil {
return nil, err
}
p := defaultDeployParam(*pubFelt)
acc := account.Account{}
return acc.PrecomputeAddress(p.Caller, &p.Pubkey, p.ClassHash, p.CallData)
}

// var defaultDeployParam = deployParamForBraavos
var defaultDeployParam = deployParamForArgentX

func deployParamForArgentXWithVersion(pub felt.Felt, isCairo0 bool) deployParam {
if isCairo0 {
return deployParamForArgentXCairo0(pub)
} else {
return deployParamForArgentX(pub)
}
}

func deployParamForArgentX(pub felt.Felt) deployParam {
return deployParam{
Caller: &felt.Zero,
Expand All @@ -108,3 +154,18 @@ func deployParamForBraavos(pub felt.Felt) deployParam {
},
}
}

func deployParamForArgentXCairo0(pub felt.Felt) deployParam {
return deployParam{
Caller: &felt.Zero,
Pubkey: pub,
ClassHash: mustFelt("25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"),
CallData: []*felt.Felt{
mustFelt("33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2"),
mustFelt("79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463"),
mustFelt("2"),
&pub,
&felt.Zero,
},
}
}
29 changes: 26 additions & 3 deletions core/starknet/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (c *Chain) BalanceOfAddress(address string) (b *base.Balance, err error) {
return c.BalanceOf(address, ETHTokenAddress)
}
func (c *Chain) BalanceOfPublicKey(publicKey string) (*base.Balance, error) {
address, err := encodePublicKeyToAddressArgentX(publicKey)
address, err := EncodePublicKeyToAddress(publicKey)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -138,7 +138,16 @@ func (c *Chain) SendSignedTransaction(signedTxn base.SignedTransaction) (hash *b
}

// we need deploy the account firstly, and resend the original txn with fixed Nonce 1
deployTxn, err := c.BuildDeployAccountTransaction(txn.Account.PublicKeyHex(), "")
pubHex := txn.Account.PublicKeyHex()
pubFelt, err := utils.HexToFelt(pubHex)
if err != nil {
return nil, err
}
version, err := CheckCairoVersionFelt(txn.invokeTxn.SenderAddress, pubFelt)
if err != nil {
return nil, err
}
deployTxn, err := c.deployAccountTxnWithVersion(pubHex, "", version == 0)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -297,6 +306,16 @@ func (c *Chain) EstimateTransactionFeeUseAccount(transaction base.Transaction, a
// BuildDeployAccountTransaction
// @param maxFee default is 0.0002
func (c *Chain) BuildDeployAccountTransaction(publicKey string, maxFee string) (*DeployAccountTransaction, error) {
return c.deployAccountTxnWithVersion(publicKey, maxFee, false)
}

// BuildDeployAccountTransaction
// @param maxFee default is 0.0002
func (c *Chain) BuildDeployAccountTransactionCairo0(publicKey string, maxFee string) (*DeployAccountTransaction, error) {
return c.deployAccountTxnWithVersion(publicKey, maxFee, true)
}

func (c *Chain) deployAccountTxnWithVersion(publicKey string, maxFee string, isCairo0 bool) (*DeployAccountTransaction, error) {
var feeInt *big.Int
var ok bool
if maxFee == "" {
Expand All @@ -306,7 +325,7 @@ func (c *Chain) BuildDeployAccountTransaction(publicKey string, maxFee string) (
return nil, base.ErrInvalidAmount
}
}
return NewDeployAccountTransaction(publicKey, feeInt, c.rpc)
return NewDeployAccountTransaction(publicKey, feeInt, c.rpc, isCairo0)
}

func (c *Chain) IsContractAddressDeployed(contractAddress string) (b *base.OptionalBool, err error) {
Expand All @@ -326,3 +345,7 @@ func (c *Chain) IsContractAddressDeployed(contractAddress string) (b *base.Optio
deployed := nonce != nil
return base.NewOptionalBool(deployed), nil
}

func (c *Chain) IsContractAddressUpgraded(contractAddress string) (b *base.OptionalBool, err error) {
return
}
19 changes: 14 additions & 5 deletions core/starknet/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (t *Token) BalanceOfAddress(address string) (*base.Balance, error) {
}

func (t *Token) BalanceOfPublicKey(publicKey string) (*base.Balance, error) {
address, err := encodePublicKeyToAddressArgentX(publicKey)
address, err := EncodePublicKeyToAddress(publicKey)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -126,7 +126,7 @@ func (t *Token) BuildTransfer(sender, receiver, amount string) (txn base.Transac
}

cli := t.chain.rpc
cli.CairoVersion = cairoVersionOf(*senderFelt, cli)
cli.CairoVersion = t.chain.queryCairoVersionForFormatCalldata(*senderFelt)
callData, err := cli.FmtCalldata([]rpc.FunctionCall{transferCall})
if err != nil {
return
Expand Down Expand Up @@ -166,19 +166,28 @@ func (t *Token) BuildTransferAll(sender, receiver string) (txn base.Transaction,
return nil, base.ErrUnsupportedFunction
}

func cairoVersionOf(contractAddress felt.Felt, cli rpc.RpcProvider) int {
classInfo, err := cli.ClassAt(context.Background(), latestBlockId, &contractAddress)
func (c *Chain) queryCairoVersionForFormatCalldata(contractAddress felt.Felt) int {
classInfo, err := c.rpc.ClassAt(context.Background(), latestBlockId, &contractAddress)
if err != nil {
if err.Error() == rpc.ErrContractNotFound.Error() {
return 0
}
return 2 // default
}
switch info := classInfo.(type) {
case rpc.DeprecatedContractClass:
case rpc.DeprecatedContractClass,
*rpc.DeprecatedContractClass:
return 0
case rpc.ContractClass:
if info.ContractClassVersion == "0.0.0" {
return 0
}
return 2
case *rpc.ContractClass:
if info.ContractClassVersion == "0.0.0" {
return 0
}
return 2
default:
return 2
}
Expand Down
30 changes: 30 additions & 0 deletions core/starknet/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package starknet
import (
"testing"

"github.com/NethermindEth/juno/core/felt"
"github.com/coming-chat/wallet-SDK/core/base"
"github.com/coming-chat/wallet-SDK/core/testcase"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -90,3 +91,32 @@ func TestToken_Transfer(t *testing.T) {
require.Nil(t, err)
t.Log(hash.Value)
}

func TestChain_queryCairoVersionForFormatCalldata(t *testing.T) {
tests := []struct {
name string
address *felt.Felt
want int
}{
{
address: mustFelt("0x03d6b3da9cfaf00482fbecd18312e5a1918744bfe6f0dd2650c4221284efce09"),
want: 0},
{
address: mustFelt("0x7384b9770dce88ee83a62a8a0ab0fac476e513a9e4b611b80fa08e844ce1f2"),
want: 2},
{
address: mustFelt("0x3d6b3da9cfaf00482fbecd18312e5a1918744bfe6f0dd2650c4221284efce09"),
want: 0},
{
address: mustFelt("0x7384b9770dce88ee83a62a8a0ab0fac476e513a9e4b611b80fa08e844ce1f2"),
want: 2},
}
chain := GoerliChain()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := chain.queryCairoVersionForFormatCalldata(*tt.address); got != tt.want {
t.Errorf("Chain.queryCairoVersionForFormatCalldata() = %v, want %v", got, tt.want)
}
})
}
}
6 changes: 3 additions & 3 deletions core/starknet/transaction_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ func (txn *DeployAccountTransaction) SignedTransactionWithAccount(account base.A
}, nil
}

func NewDeployAccountTransaction(pubkey string, maxFee *big.Int, acc *account.Account) (*DeployAccountTransaction, error) {
func NewDeployAccountTransaction(pubkey string, maxFee *big.Int, cli *account.Account, isCairo0 bool) (*DeployAccountTransaction, error) {
pubFelt, err := utils.HexToFelt(pubkey)
if err != nil {
return nil, err
}
param := defaultDeployParam(*pubFelt)
param := deployParamForArgentXWithVersion(*pubFelt, isCairo0)
deployTxn := rpc.DeployAccountTxn{
ContractAddressSalt: &param.Pubkey,
ClassHash: param.ClassHash,
Expand All @@ -56,7 +56,7 @@ func NewDeployAccountTransaction(pubkey string, maxFee *big.Int, acc *account.Ac
if err != nil {
return nil, err
}
txnHash, err := acc.TransactionHashDeployAccount(deployTxn, contractAddress)
txnHash, err := cli.TransactionHashDeployAccount(deployTxn, contractAddress)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 35c12ac

Please sign in to comment.