Skip to content

Commit db4ce9f

Browse files
committed
ethereum nonce check will refund on failure
1 parent 4b0838b commit db4ce9f

File tree

9 files changed

+58
-35
lines changed

9 files changed

+58
-35
lines changed

apps/ethereum/account.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func GetSortedSafeOwners(holder, signer, observer string) ([]string, []string) {
112112
func GetOrDeploySafeAccount(ctx context.Context, rpc, key string, chainId int64, owners []string, threshold int64, timelock, observerIndex int64, tx *SafeTransaction) (*common.Address, error) {
113113
addr := GetSafeAccountAddress(owners, threshold)
114114

115-
isGuarded, isDeployed, err := CheckSafeAccountDeployed(rpc, addr.String())
115+
isGuarded, isDeployed, err := CheckSafeAccountDeployed(ctx, chainId, rpc, addr.String())
116116
if err != nil {
117117
return nil, err
118118
}
@@ -135,8 +135,8 @@ func GetOrDeploySafeAccount(ctx context.Context, rpc, key string, chainId int64,
135135
return &addr, nil
136136
}
137137

138-
func GetSafeAccountGuard(rpc, address string) (string, error) {
139-
conn, abi, err := safeInit(rpc, address)
138+
func GetSafeAccountGuard(ctx context.Context, chainId int64, rpc, address string) (string, error) {
139+
conn, abi, err := safeInit(ctx, chainId, rpc, address)
140140
if err != nil {
141141
return "", err
142142
}
@@ -157,8 +157,8 @@ func GetSafeAccountGuard(rpc, address string) (string, error) {
157157
return guardAddress.Hex(), nil
158158
}
159159

160-
func CheckSafeAccountDeployed(rpc, address string) (bool, bool, error) {
161-
guardAddress, err := GetSafeAccountGuard(rpc, address)
160+
func CheckSafeAccountDeployed(ctx context.Context, chainId int64, rpc, address string) (bool, bool, error) {
161+
guardAddress, err := GetSafeAccountGuard(ctx, chainId, rpc, address)
162162
if err != nil {
163163
return false, false, err
164164
}
@@ -222,8 +222,8 @@ func DeploySafeAccount(ctx context.Context, rpc, key string, chainId int64, owne
222222
return err
223223
}
224224

225-
func GetSafeLastTxTime(rpc, address string) (time.Time, error) {
226-
guardAddress, err := GetSafeAccountGuard(rpc, address)
225+
func GetSafeLastTxTime(ctx context.Context, chainId int64, rpc, address string) (time.Time, error) {
226+
guardAddress, err := GetSafeAccountGuard(ctx, chainId, rpc, address)
227227
if err != nil {
228228
return time.Time{}, err
229229
}
@@ -284,13 +284,21 @@ func ParseEthereumCompressedPublicKey(public string) (*common.Address, error) {
284284
return &addr, nil
285285
}
286286

287-
func FetchSafeNonce(ctx context.Context, rpc, address string, height int64) (int64, error) {
288-
conn, abi, err := safeInit(rpc, address)
287+
func FetchSafeNonce(ctx context.Context, chainId int64, rpc, address string, height int64) (int64, error) {
288+
conn, abi, err := safeInit(ctx, chainId, rpc, address)
289289
if err != nil {
290290
return 0, err
291291
}
292292
defer conn.Close()
293293

294+
now, err := conn.BlockNumber(ctx)
295+
if err != nil {
296+
return 0, err
297+
}
298+
if now < uint64(height) {
299+
panic(now)
300+
}
301+
294302
opt := &bind.CallOpts{}
295303
if height > 0 {
296304
opt.BlockNumber = big.NewInt(height)

apps/ethereum/common.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,11 +559,18 @@ func suggestMaxPriorityFeePerGas(ctx context.Context, conn *ethclient.Client) *b
559559
return gasPrice
560560
}
561561

562-
func safeInit(rpc, address string) (*ethclient.Client, *abi.GnosisSafe, error) {
562+
func safeInit(ctx context.Context, chainId int64, rpc, address string) (*ethclient.Client, *abi.GnosisSafe, error) {
563563
conn, err := ethclient.Dial(rpc)
564564
if err != nil {
565565
return nil, nil, err
566566
}
567+
id, err := conn.ChainID(ctx)
568+
if err != nil {
569+
return nil, nil, err
570+
}
571+
if id.Int64() != chainId {
572+
return nil, nil, fmt.Errorf("safeInit(%d, %s) => %d", chainId, rpc, id.Int64())
573+
}
567574

568575
abi, err := abi.NewGnosisSafe(common.HexToAddress(address), conn)
569576
if err != nil {

apps/ethereum/transaction.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ func UnmarshalSafeTransaction(b []byte) (*SafeTransaction, error) {
258258
}, nil
259259
}
260260

261-
func (tx *SafeTransaction) ValidTransaction(rpc string) error {
262-
conn, abi, err := safeInit(rpc, tx.SafeAddress)
261+
func (tx *SafeTransaction) ValidTransaction(ctx context.Context, rpc string) error {
262+
conn, abi, err := safeInit(ctx, tx.ChainID, rpc, tx.SafeAddress)
263263
if err != nil {
264264
return err
265265
}
@@ -297,7 +297,7 @@ func (tx *SafeTransaction) ValidTransaction(rpc string) error {
297297
}
298298

299299
func (tx *SafeTransaction) BuildTransaction(ctx context.Context, rpc, key string) (*types.Transaction, error) {
300-
conn, safeAbi, err := safeInit(rpc, tx.SafeAddress)
300+
conn, safeAbi, err := safeInit(ctx, tx.ChainID, rpc, tx.SafeAddress)
301301
if err != nil {
302302
return nil, err
303303
}

keeper/ethereum.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (node *Node) processEthereumSafeCloseAccountByInheritance(ctx context.Conte
7373
}
7474

7575
rpc, _ := node.ethereumParams(safe.Chain)
76-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
76+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, t.ChainID, rpc, safe.Address)
7777
logger.Printf("ethereum.GetSafeLastTxTime(%s) => %v %v", safe.Address, latestTxTime, err)
7878
if err != nil {
7979
panic(err)
@@ -206,7 +206,8 @@ func (node *Node) processEthereumSafeCloseAccount(ctx context.Context, req *comm
206206
}
207207

208208
rpc, _ := node.ethereumParams(safe.Chain)
209-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
209+
chainId := ethereum.GetEvmChainID(int64(safe.Chain))
210+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, chainId, rpc, safe.Address)
210211
logger.Printf("ethereum.GetSafeLastTxTime(%s) => %v %v", safe.Address, latestTxTime, err)
211212
if err != nil {
212213
panic(err)
@@ -701,6 +702,7 @@ func (node *Node) processEthereumSafeProposeTransaction(ctx context.Context, req
701702
if meta.Chain != common.SafeChainPolygon {
702703
return node.failRequest(ctx, req, "")
703704
}
705+
// FIXME no info height used yet
704706
deployed, err := abi.CheckFactoryAssetDeployed(node.conf.PolygonRPC, meta.AssetKey)
705707
logger.Printf("abi.CheckFactoryAssetDeployed(%s) => %v %v", meta.AssetKey, deployed, err)
706708
if err != nil || deployed.Sign() <= 0 {
@@ -862,17 +864,18 @@ func (node *Node) processEthereumSafeProposeTransaction(ctx context.Context, req
862864
return node.failRequest(ctx, req, "")
863865
}
864866

865-
nonceOnline, err := ethereum.FetchSafeNonce(ctx, rpc, safe.Address, int64(info.Height))
866-
logger.Printf("ethereum.FetchSafeNonce(%s %d) => %d %v", safe.Address, info.Height, nonceOnline, err)
867+
chainId := ethereum.GetEvmChainID(int64(safe.Chain))
868+
nonceOnline, err := ethereum.FetchSafeNonce(ctx, chainId, rpc, safe.Address, int64(info.Height))
869+
logger.Printf("ethereum.FetchSafeNonce(%s, %d) => %d %v", safe.Address, info.Height, nonceOnline, err)
867870
if err != nil {
868871
panic(err)
869872
}
870873
if nonce != nonceOnline && !common.CheckTestEnvironment(ctx) {
871-
panic(fmt.Errorf("invalid safe nonce: %s %d %d ", safe.Address, nonce, nonceOnline))
874+
logger.Printf("invalid safe nonce: %s %d %d %d", safe.Address, nonce, nonceOnline, info.Height)
875+
return node.refundAndFailRequest(ctx, req, safe.Receivers, int(safe.Threshold))
872876
}
873877

874878
var t *ethereum.SafeTransaction
875-
chainId := ethereum.GetEvmChainID(int64(safe.Chain))
876879
txType := ethereum.TypeETHTx
877880
switch flag {
878881
case common.FlagProposeNormalTransaction, common.FlagProposeSetInheritance, common.FlagProposeRemoveInheritance, common.FlagProposeCancelTransaction:
@@ -897,7 +900,8 @@ func (node *Node) processEthereumSafeProposeTransaction(ctx context.Context, req
897900
if err != nil {
898901
panic(fmt.Errorf("ethereum.RPCGetBlock(%s %s) => %v %v", rpc, info.Hash, latest, err))
899902
}
900-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
903+
// FIXME no info height used yet
904+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, chainId, rpc, safe.Address)
901905
if err != nil {
902906
panic(fmt.Errorf("ethereum.GetSafeLastTxTime(%s %s) => %v %v", rpc, safe.Address, latestTxTime, err))
903907
}

keeper/ethereum_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ func TestEthereumKeeper(t *testing.T) {
133133
require.Nil(err)
134134
_, pubs := ethereum.GetSortedSafeOwners(safe.Holder, safe.Signer, safe.Observer)
135135
rpc, _ := node.ethereumParams(safe.Chain)
136-
nonce, err := ethereum.FetchSafeNonce(ctx, rpc, safe.Address, 80093737)
136+
chainId := ethereum.GetEvmChainID(common.SafeChainPolygon)
137+
nonce, err := ethereum.FetchSafeNonce(ctx, chainId, rpc, safe.Address, 80093737)
137138
require.Nil(err)
138139
require.Equal(int64(1), nonce)
139140
require.Equal(int64(2), safe.Nonce)

keeper/network.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ func (node *Node) fetchMixinAsset(_ context.Context, id string) (*store.Asset, e
236236
if err != nil {
237237
return nil, err
238238
}
239-
defer resp.Body.Close()
239+
defer common.CloseOrPanic(resp.Body)
240240

241241
var body struct {
242242
Data *struct {

observer/accountant.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,14 +598,14 @@ func (node *Node) ethereumBroadcastTransactionAndWriteDeposit(ctx context.Contex
598598
rpc, _ := node.ethereumParams(tx.Chain)
599599
key := fmt.Sprintf("%s:SPENT_HASH", tx.TransactionHash)
600600

601-
err := st.ValidTransaction(rpc)
601+
err := st.ValidTransaction(ctx, rpc)
602602
logger.Printf("ValidTransaction(%s) => %v", st.TxHash, err)
603603
if err != nil {
604604
// retry when error not from Gnosis Safe Contract
605605
if !strings.Contains(err.Error(), "GS") {
606606
return "", err
607607
}
608-
nonce, err := ethereum.FetchSafeNonce(ctx, rpc, st.SafeAddress, 0)
608+
nonce, err := ethereum.FetchSafeNonce(ctx, st.ChainID, rpc, st.SafeAddress, 0)
609609
if err != nil {
610610
panic(err)
611611
}
@@ -666,7 +666,7 @@ func (node *Node) isTxStuck(ctx context.Context, tx *Transaction) bool {
666666
if err != nil {
667667
panic(err)
668668
}
669-
nonce, err := ethereum.FetchSafeNonce(ctx, rpc, st.SafeAddress, height)
669+
nonce, err := ethereum.FetchSafeNonce(ctx, st.ChainID, rpc, st.SafeAddress, height)
670670
if err != nil {
671671
panic(err)
672672
}

observer/ethereum.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ func (node *Node) httpCreateEthereumAccountRecoveryRequest(ctx context.Context,
816816
if err != nil {
817817
return err
818818
}
819-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
819+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, st.ChainID, rpc, safe.Address)
820820
logger.Printf("ethereum.GetSafeLastTxTime(%s %s) => %v %v", rpc, safe.Address, latestTxTime, err)
821821
if err != nil {
822822
return err
@@ -914,7 +914,7 @@ func (node *Node) httpSignEthereumAccountRecoveryRequest(ctx context.Context, sa
914914
if err != nil {
915915
return err
916916
}
917-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
917+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, st.ChainID, rpc, safe.Address)
918918
logger.Printf("ethereum.GetSafeLastTxTime(%s %s) => %v %v", rpc, safe.Address, latestTxTime, err)
919919
if err != nil {
920920
return err
@@ -1149,7 +1149,7 @@ func (node *Node) httpCreateEthereumInheritanceTransaction(ctx context.Context,
11491149
if err != nil {
11501150
return nil, err
11511151
}
1152-
latestTxTime, err := ethereum.GetSafeLastTxTime(rpc, safe.Address)
1152+
latestTxTime, err := ethereum.GetSafeLastTxTime(ctx, st.ChainID, rpc, safe.Address)
11531153
logger.Printf("ethereum.GetSafeLastTxTime(%s %s) => %v %v", rpc, safe.Address, latestTxTime, err)
11541154
if err != nil {
11551155
return nil, err

signer/ethereum_test.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,24 @@ func TestCMPEthereumERC20Transaction(t *testing.T) {
6161
rpc = polygonRpc
6262
}
6363

64-
nonce, err := ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 52874396)
64+
chainId := ethereum.GetEvmChainID(ethereum.ChainPolygon)
65+
nonce, err := ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 52874396)
6566
require.NotNil(err)
6667
require.True(strings.Contains(err.Error(), "no contract code at given address"))
67-
nonce, err = ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 52874399)
68+
require.Equal(int64(0), nonce)
69+
nonce, err = ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 52874399)
6870
require.Nil(err)
6971
require.Equal(int64(1), nonce)
70-
nonce, err = ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 53028021)
72+
nonce, err = ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 53028021)
7173
require.Nil(err)
7274
require.Equal(int64(2), nonce)
73-
nonce, err = ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 53030541)
75+
nonce, err = ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 53030541)
7476
require.Nil(err)
7577
require.Equal(int64(3), nonce)
76-
nonce, err = ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 58425175)
78+
nonce, err = ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 58425175)
7779
require.Nil(err)
7880
require.Equal(int64(4), nonce)
79-
nonce, err = ethereum.FetchSafeNonce(ctx, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 0)
81+
nonce, err = ethereum.FetchSafeNonce(ctx, chainId, rpc, "0x930A085bd78D2F1D225f2AA06dBfbF525CEe85cC", 0)
8082
require.Nil(err)
8183
require.Equal(int64(4), nonce)
8284

@@ -305,7 +307,8 @@ func TestCMPEthereumSign(t *testing.T) {
305307

306308
var tx types.Transaction
307309
b, _ := hex.DecodeString(raw[2:])
308-
tx.UnmarshalBinary(b)
310+
err = tx.UnmarshalBinary(b)
311+
require.Nil(err)
309312
signer := types.MakeSigner(mvmChainConfig, mvmChainConfig.ByzantiumBlock, 0)
310313
verify, _ := signer.Sender(&tx)
311314
require.Equal(testEthereumAddress, verify.String())

0 commit comments

Comments
 (0)