fix: calculating next nonce for optimism chain improved to align with calculation on mainnet and arbitrum

This commit is contained in:
Sale Djenic 2024-03-12 10:15:30 +01:00 committed by saledjenic
parent b987e8d6f5
commit f69ee07593
21 changed files with 390 additions and 290 deletions

View File

@ -1 +1 @@
0.176.9 0.176.10

View File

@ -18,7 +18,6 @@ import (
"github.com/imdario/mergo" "github.com/imdario/mergo"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
ethcrypto "github.com/ethereum/go-ethereum/crypto" ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -49,7 +48,6 @@ import (
"github.com/status-im/status-go/services/ext" "github.com/status-im/status-go/services/ext"
"github.com/status-im/status-go/services/personal" "github.com/status-im/status-go/services/personal"
"github.com/status-im/status-go/services/typeddata" "github.com/status-im/status-go/services/typeddata"
wcommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/signal" "github.com/status-im/status-go/signal"
"github.com/status-im/status-go/transactions" "github.com/status-im/status-go/transactions"
"github.com/status-im/status-go/walletdatabase" "github.com/status-im/status-go/walletdatabase"
@ -1911,24 +1909,7 @@ func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, pa
return hash, err return hash, err
} }
hash, err = b.transactor.SendTransaction(sendArgs, verifiedAccount) return b.transactor.SendTransaction(sendArgs, verifiedAccount)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
} }
func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) { func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) {
@ -1937,45 +1918,11 @@ func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs
return hash, err return hash, err
} }
hash, err = b.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount) return b.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
} }
func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) { func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) {
hash, err = b.transactor.BuildTransactionAndSendWithSignature(b.transactor.NetworkID(), sendArgs, sig) return b.transactor.BuildTransactionAndSendWithSignature(b.transactor.NetworkID(), sendArgs, sig)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
} }
// HashTransaction validate the transaction and returns new sendArgs and the transaction hash. // HashTransaction validate the transaction and returns new sendArgs and the transaction hash.

View File

@ -452,6 +452,9 @@ func (b *StatusNode) ensService(timesource func() time.Time) *ens.Service {
func (b *StatusNode) pendingTrackerService(walletFeed *event.Feed) *transactions.PendingTxTracker { func (b *StatusNode) pendingTrackerService(walletFeed *event.Feed) *transactions.PendingTxTracker {
if b.pendingTracker == nil { if b.pendingTracker == nil {
b.pendingTracker = transactions.NewPendingTxTracker(b.walletDB, b.rpcClient, b.rpcFiltersSrvc, walletFeed, transactions.PendingCheckInterval) b.pendingTracker = transactions.NewPendingTxTracker(b.walletDB, b.rpcClient, b.rpcFiltersSrvc, walletFeed, transactions.PendingCheckInterval)
if b.transactor != nil {
b.transactor.SetPendingTracker(b.pendingTracker)
}
} }
return b.pendingTracker return b.pendingTracker
} }

View File

@ -52,7 +52,7 @@ const (
type Entry struct { type Entry struct {
payloadType PayloadType payloadType PayloadType
transaction *transfer.TransactionIdentity transaction *transfer.TransactionIdentity
id transfer.MultiTransactionIDType id common.MultiTransactionIDType
timestamp int64 timestamp int64
activityType Type activityType Type
activityStatus Status activityStatus Status
@ -77,7 +77,7 @@ type Entry struct {
type EntryData struct { type EntryData struct {
PayloadType PayloadType `json:"payloadType"` PayloadType PayloadType `json:"payloadType"`
Transaction *transfer.TransactionIdentity `json:"transaction,omitempty"` Transaction *transfer.TransactionIdentity `json:"transaction,omitempty"`
ID *transfer.MultiTransactionIDType `json:"id,omitempty"` ID *common.MultiTransactionIDType `json:"id,omitempty"`
Timestamp *int64 `json:"timestamp,omitempty"` Timestamp *int64 `json:"timestamp,omitempty"`
ActivityType *Type `json:"activityType,omitempty"` ActivityType *Type `json:"activityType,omitempty"`
ActivityStatus *Status `json:"activityStatus,omitempty"` ActivityStatus *Status `json:"activityStatus,omitempty"`
@ -196,7 +196,7 @@ func newActivityEntryWithTransaction(pending bool, transaction *transfer.Transac
} }
} }
func NewActivityEntryWithMultiTransaction(id transfer.MultiTransactionIDType, timestamp int64, activityType Type, activityStatus Status) Entry { func NewActivityEntryWithMultiTransaction(id common.MultiTransactionIDType, timestamp int64, activityType Type, activityStatus Status) Entry {
return Entry{ return Entry{
payloadType: MultiTransactionPT, payloadType: MultiTransactionPT,
id: id, id: id,
@ -660,7 +660,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
*inChainID = common.ChainID(inChainIDDB.Int64) *inChainID = common.ChainID(inChainIDDB.Int64)
} }
entry = NewActivityEntryWithMultiTransaction(transfer.MultiTransactionIDType(multiTxID.Int64), entry = NewActivityEntryWithMultiTransaction(common.MultiTransactionIDType(multiTxID.Int64),
timestamp, activityType, activityStatus) timestamp, activityType, activityStatus)
// Extract tokens // Extract tokens

View File

@ -109,10 +109,10 @@ type testData struct {
multiTx2PendingTr transfer.TestTransfer // index 7, DAI/Mainnet multiTx2PendingTr transfer.TestTransfer // index 7, DAI/Mainnet
multiTx1 transfer.TestMultiTransaction multiTx1 transfer.TestMultiTransaction
multiTx1ID transfer.MultiTransactionIDType multiTx1ID common.MultiTransactionIDType
multiTx2 transfer.TestMultiTransaction multiTx2 transfer.TestMultiTransaction
multiTx2ID transfer.MultiTransactionIDType multiTx2ID common.MultiTransactionIDType
nextIndex int nextIndex int
} }
@ -640,7 +640,7 @@ func TestGetActivityEntriesFilterByType(t *testing.T) {
multiTxs[3] = transfer.GenerateTestBridgeMultiTransaction(trs[6], trs[7]) multiTxs[3] = transfer.GenerateTestBridgeMultiTransaction(trs[6], trs[7])
multiTxs[4] = transfer.GenerateTestSendMultiTransaction(trs[8]) // trs[9] multiTxs[4] = transfer.GenerateTestSendMultiTransaction(trs[8]) // trs[9]
var lastMT transfer.MultiTransactionIDType var lastMT common.MultiTransactionIDType
for i := range trs { for i := range trs {
if i%2 == 0 { if i%2 == 0 {
lastMT = transfer.InsertTestMultiTransaction(t, deps.db, &multiTxs[i/2]) lastMT = transfer.InsertTestMultiTransaction(t, deps.db, &multiTxs[i/2])

View File

@ -21,7 +21,7 @@ const nilStr = "nil"
type EntryIdentity struct { type EntryIdentity struct {
payloadType PayloadType payloadType PayloadType
transaction *transfer.TransactionIdentity transaction *transfer.TransactionIdentity
id transfer.MultiTransactionIDType id common.MultiTransactionIDType
} }
func (e EntryIdentity) same(a EntryIdentity) bool { func (e EntryIdentity) same(a EntryIdentity) bool {

View File

@ -571,7 +571,7 @@ func (api *API) ProceedWithTransactionsSignatures(ctx context.Context, signature
return api.s.transactionManager.ProceedWithTransactionsSignatures(ctx, signatures) return api.s.transactionManager.ProceedWithTransactionsSignatures(ctx, signatures)
} }
func (api *API) GetMultiTransactions(ctx context.Context, transactionIDs []transfer.MultiTransactionIDType) ([]*transfer.MultiTransaction, error) { func (api *API) GetMultiTransactions(ctx context.Context, transactionIDs []wcommon.MultiTransactionIDType) ([]*transfer.MultiTransaction, error) {
log.Debug("wallet.api.GetMultiTransactions", "IDs.len", len(transactionIDs)) log.Debug("wallet.api.GetMultiTransactions", "IDs.len", len(transactionIDs))
return api.s.transactionManager.GetMultiTransactions(ctx, transactionIDs) return api.s.transactionManager.GetMultiTransactions(ctx, transactionIDs)
} }

View File

@ -5,6 +5,12 @@ import (
"time" "time"
) )
type MultiTransactionIDType int64
const (
NoMultiTransactionID = MultiTransactionIDType(0)
)
type ChainID uint64 type ChainID uint64
const ( const (

View File

@ -352,7 +352,7 @@ func (c *transfersCommand) confirmPendingTransactions(tx *sql.Tx, allTransfers [
} }
if mTID != nil { if mTID != nil {
allTransfers[i].MultiTransactionID = MultiTransactionIDType(*mTID) allTransfers[i].MultiTransactionID = w_common.MultiTransactionIDType(*mTID)
} }
if txType != nil && *txType == transactions.WalletTransfer { if txType != nil && *txType == transactions.WalletTransfer {
notify, err := c.pendingTxManager.DeleteBySQLTx(tx, chainID, txHash) notify, err := c.pendingTxManager.DeleteBySQLTx(tx, chainID, txHash)
@ -366,7 +366,7 @@ func (c *transfersCommand) confirmPendingTransactions(tx *sql.Tx, allTransfers [
} }
// Mark all subTxs of a given Tx with the same multiTxID // Mark all subTxs of a given Tx with the same multiTxID
func setMultiTxID(tx Transaction, multiTxID MultiTransactionIDType) { func setMultiTxID(tx Transaction, multiTxID w_common.MultiTransactionIDType) {
for _, subTx := range tx { for _, subTx := range tx {
subTx.MultiTransactionID = multiTxID subTx.MultiTransactionID = multiTxID
} }
@ -422,7 +422,7 @@ func (c *transfersCommand) checkAndProcessBridgeMultiTx(ctx context.Context, tx
} }
if multiTransaction != nil { if multiTransaction != nil {
setMultiTxID(tx, MultiTransactionIDType(multiTransaction.ID)) setMultiTxID(tx, multiTransaction.ID)
c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address) c.markMultiTxTokensAsPreviouslyOwned(ctx, multiTransaction, subTx.Address)
return true, nil return true, nil
} }

View File

@ -444,7 +444,7 @@ type transferDBFields struct {
log *types.Log log *types.Log
transferType w_common.Type transferType w_common.Type
baseGasFees string baseGasFees string
multiTransactionID MultiTransactionIDType multiTransactionID w_common.MultiTransactionIDType
receiptStatus *uint64 receiptStatus *uint64
receiptType *uint8 receiptType *uint8
txHash *common.Hash txHash *common.Hash

View File

@ -147,8 +147,8 @@ func TestGetTransfersForIdentities(t *testing.T) {
require.Equal(t, uint64(trs[3].Timestamp), entries[1].Timestamp) require.Equal(t, uint64(trs[3].Timestamp), entries[1].Timestamp)
require.Equal(t, uint64(trs[1].ChainID), entries[0].NetworkID) require.Equal(t, uint64(trs[1].ChainID), entries[0].NetworkID)
require.Equal(t, uint64(trs[3].ChainID), entries[1].NetworkID) require.Equal(t, uint64(trs[3].ChainID), entries[1].NetworkID)
require.Equal(t, MultiTransactionIDType(0), entries[0].MultiTransactionID) require.Equal(t, w_common.MultiTransactionIDType(0), entries[0].MultiTransactionID)
require.Equal(t, MultiTransactionIDType(0), entries[1].MultiTransactionID) require.Equal(t, w_common.MultiTransactionIDType(0), entries[1].MultiTransactionID)
} }
func TestGetLatestCollectibleTransfer(t *testing.T) { func TestGetLatestCollectibleTransfer(t *testing.T) {

View File

@ -63,7 +63,7 @@ type Transfer struct {
TokenValue *big.Int `json:"tokenValue"` TokenValue *big.Int `json:"tokenValue"`
BaseGasFees string BaseGasFees string
// Internal field that is used to track multi-transaction transfers. // Internal field that is used to track multi-transaction transfers.
MultiTransactionID MultiTransactionIDType `json:"multi_transaction_id"` MultiTransactionID w_common.MultiTransactionIDType `json:"multi_transaction_id"`
} }
// ETHDownloader downloads regular eth transfers and tokens transfers. // ETHDownloader downloads regular eth transfers and tokens transfers.
@ -288,7 +288,7 @@ func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Bloc
Receipt: receipt, Receipt: receipt,
Log: nil, Log: nil,
BaseGasFees: blk.BaseFee().String(), BaseGasFees: blk.BaseFee().String(),
MultiTransactionID: NoMultiTransactionID}) MultiTransactionID: w_common.NoMultiTransactionID})
} }
} }
} }
@ -416,7 +416,7 @@ func (d *ETHDownloader) subTransactionsFromPreloaded(preloadedTx *PreloadedTrans
Transaction: tx, Transaction: tx,
Receipt: receipt, Receipt: receipt,
Timestamp: blk.Time(), Timestamp: blk.Time(),
MultiTransactionID: NoMultiTransactionID, MultiTransactionID: w_common.NoMultiTransactionID,
} }
rst = append(rst, transfer) rst = append(rst, transfer)
@ -451,7 +451,7 @@ func (d *ETHDownloader) subTransactionsFromTransactionData(address, from common.
Transaction: tx, Transaction: tx,
Receipt: receipt, Receipt: receipt,
Timestamp: blk.Time(), Timestamp: blk.Time(),
MultiTransactionID: NoMultiTransactionID, MultiTransactionID: w_common.NoMultiTransactionID,
} }
rst = append(rst, transfer) rst = append(rst, transfer)

View File

@ -27,7 +27,7 @@ type TestTransaction struct {
Success bool Success bool
Nonce uint64 Nonce uint64
Contract eth_common.Address Contract eth_common.Address
MultiTransactionID MultiTransactionIDType MultiTransactionID common.MultiTransactionIDType
} }
type TestTransfer struct { type TestTransfer struct {
@ -38,7 +38,7 @@ type TestTransfer struct {
} }
type TestMultiTransaction struct { type TestMultiTransaction struct {
MultiTransactionID MultiTransactionIDType MultiTransactionID common.MultiTransactionIDType
MultiTransactionType MultiTransactionType MultiTransactionType MultiTransactionType
FromAddress eth_common.Address FromAddress eth_common.Address
ToAddress eth_common.Address ToAddress eth_common.Address
@ -78,7 +78,7 @@ func generateTestTransaction(seed int) TestTransaction {
Nonce: uint64(seed), Nonce: uint64(seed),
// In practice this is last20Bytes(Keccak256(RLP(From, nonce))) // In practice this is last20Bytes(Keccak256(RLP(From, nonce)))
Contract: eth_common.HexToAddress(fmt.Sprintf("0x4%d", seed)), Contract: eth_common.HexToAddress(fmt.Sprintf("0x4%d", seed)),
MultiTransactionID: NoMultiTransactionID, MultiTransactionID: common.NoMultiTransactionID,
} }
} }
@ -367,7 +367,7 @@ func InsertTestPendingTransaction(tb testing.TB, db *sql.DB, tr *TestTransfer) {
require.NoError(tb, err) require.NoError(tb, err)
} }
func InsertTestMultiTransaction(tb testing.TB, db *sql.DB, tr *TestMultiTransaction) MultiTransactionIDType { func InsertTestMultiTransaction(tb testing.TB, db *sql.DB, tr *TestMultiTransaction) common.MultiTransactionIDType {
fromTokenType := tr.FromToken fromTokenType := tr.FromToken
if tr.FromToken == "" { if tr.FromToken == "" {
fromTokenType = testutils.EthSymbol fromTokenType = testutils.EthSymbol
@ -386,7 +386,7 @@ func InsertTestMultiTransaction(tb testing.TB, db *sql.DB, tr *TestMultiTransact
require.NoError(tb, err) require.NoError(tb, err)
rowID, err := result.LastInsertId() rowID, err := result.LastInsertId()
require.NoError(tb, err) require.NoError(tb, err)
tr.MultiTransactionID = MultiTransactionIDType(rowID) tr.MultiTransactionID = common.MultiTransactionIDType(rowID)
return tr.MultiTransactionID return tr.MultiTransactionID
} }

View File

@ -21,11 +21,7 @@ import (
"github.com/status-im/status-go/transactions" "github.com/status-im/status-go/transactions"
) )
type MultiTransactionIDType int64
const ( const (
NoMultiTransactionID = MultiTransactionIDType(0)
// EventMTTransactionUpdate is emitted when a multi-transaction is updated (added or deleted) // EventMTTransactionUpdate is emitted when a multi-transaction is updated (added or deleted)
EventMTTransactionUpdate walletevent.EventType = "multi-transaction-update" EventMTTransactionUpdate walletevent.EventType = "multi-transaction-update"
) )
@ -38,6 +34,7 @@ type SignatureDetails struct {
type TransactionDescription struct { type TransactionDescription struct {
chainID uint64 chainID uint64
from common.Address
builtTx *ethTypes.Transaction builtTx *ethTypes.Transaction
signature []byte signature []byte
} }
@ -89,7 +86,7 @@ const (
) )
type MultiTransaction struct { type MultiTransaction struct {
ID uint `json:"id"` ID wallet_common.MultiTransactionIDType `json:"id"`
Timestamp uint64 `json:"timestamp"` Timestamp uint64 `json:"timestamp"`
FromNetworkID uint64 `json:"fromNetworkID"` FromNetworkID uint64 `json:"fromNetworkID"`
ToNetworkID uint64 `json:"toNetworkID"` ToNetworkID uint64 `json:"toNetworkID"`
@ -226,21 +223,5 @@ func (tm *TransactionManager) BuildRawTransaction(chainID uint64, sendArgs trans
} }
func (tm *TransactionManager) SendTransactionWithSignature(chainID uint64, txType transactions.PendingTrxType, sendArgs transactions.SendTxArgs, signature []byte) (hash types.Hash, err error) { func (tm *TransactionManager) SendTransactionWithSignature(chainID uint64, txType transactions.PendingTrxType, sendArgs transactions.SendTxArgs, signature []byte) (hash types.Hash, err error) {
hash, err = tm.transactor.BuildTransactionAndSendWithSignature(chainID, sendArgs, signature) return tm.transactor.BuildTransactionAndSendWithSignature(chainID, sendArgs, signature)
if err != nil {
return hash, err
}
err = tm.pendingTracker.TrackPendingTransaction(
wallet_common.ChainID(chainID),
common.Hash(hash),
common.Address(sendArgs.From),
txType,
transactions.AutoDelete,
)
if err != nil {
return hash, err
}
return hash, nil
} }

View File

@ -19,7 +19,6 @@ import (
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/bridge" "github.com/status-im/status-go/services/wallet/bridge"
wallet_common "github.com/status-im/status-go/services/wallet/common" wallet_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/walletevent" "github.com/status-im/status-go/services/wallet/walletevent"
@ -90,11 +89,11 @@ func getMultiTransactionTimestamp(multiTransaction *MultiTransaction) uint64 {
} }
// insertMultiTransaction inserts a multi transaction into the database and updates multi-transaction ID and timestamp // insertMultiTransaction inserts a multi transaction into the database and updates multi-transaction ID and timestamp
func insertMultiTransaction(db *sql.DB, multiTransaction *MultiTransaction) (MultiTransactionIDType, error) { func insertMultiTransaction(db *sql.DB, multiTransaction *MultiTransaction) (wallet_common.MultiTransactionIDType, error) {
insert, err := db.Prepare(fmt.Sprintf(`INSERT INTO multi_transactions (%s) insert, err := db.Prepare(fmt.Sprintf(`INSERT INTO multi_transactions (%s)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, multiTransactionColumns)) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, multiTransactionColumns))
if err != nil { if err != nil {
return NoMultiTransactionID, err return wallet_common.NoMultiTransactionID, err
} }
timestamp := getMultiTransactionTimestamp(multiTransaction) timestamp := getMultiTransactionTimestamp(multiTransaction)
result, err := insert.Exec( result, err := insert.Exec(
@ -113,22 +112,22 @@ func insertMultiTransaction(db *sql.DB, multiTransaction *MultiTransaction) (Mul
timestamp, timestamp,
) )
if err != nil { if err != nil {
return NoMultiTransactionID, err return wallet_common.NoMultiTransactionID, err
} }
defer insert.Close() defer insert.Close()
multiTransactionID, err := result.LastInsertId() multiTransactionID, err := result.LastInsertId()
multiTransaction.Timestamp = timestamp multiTransaction.Timestamp = timestamp
multiTransaction.ID = uint(multiTransactionID) multiTransaction.ID = wallet_common.MultiTransactionIDType(multiTransactionID)
return MultiTransactionIDType(multiTransactionID), err return wallet_common.MultiTransactionIDType(multiTransactionID), err
} }
func (tm *TransactionManager) InsertMultiTransaction(multiTransaction *MultiTransaction) (MultiTransactionIDType, error) { func (tm *TransactionManager) InsertMultiTransaction(multiTransaction *MultiTransaction) (wallet_common.MultiTransactionIDType, error) {
return tm.insertMultiTransactionAndNotify(tm.db, multiTransaction, nil) return tm.insertMultiTransactionAndNotify(tm.db, multiTransaction, nil)
} }
func (tm *TransactionManager) insertMultiTransactionAndNotify(db *sql.DB, multiTransaction *MultiTransaction, chainIDs []uint64) (MultiTransactionIDType, error) { func (tm *TransactionManager) insertMultiTransactionAndNotify(db *sql.DB, multiTransaction *MultiTransaction, chainIDs []uint64) (wallet_common.MultiTransactionIDType, error) {
id, err := insertMultiTransaction(db, multiTransaction) id, err := insertMultiTransaction(db, multiTransaction)
if err != nil { if err != nil {
publishMultiTransactionUpdatedEvent(db, multiTransaction, tm.eventFeed, chainIDs) publishMultiTransactionUpdatedEvent(db, multiTransaction, tm.eventFeed, chainIDs)
@ -156,7 +155,7 @@ func publishMultiTransactionUpdatedEvent(db *sql.DB, multiTransaction *MultiTran
} }
func updateMultiTransaction(db *sql.DB, multiTransaction *MultiTransaction) error { func updateMultiTransaction(db *sql.DB, multiTransaction *MultiTransaction) error {
if MultiTransactionIDType(multiTransaction.ID) == NoMultiTransactionID { if multiTransaction.ID == wallet_common.NoMultiTransactionID {
return fmt.Errorf("no multitransaction ID") return fmt.Errorf("no multitransaction ID")
} }
@ -211,7 +210,7 @@ func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Cont
return nil, err return nil, err
} }
multiTransaction.ID = uint(multiTransactionID) multiTransaction.ID = multiTransactionID
if password == "" { if password == "" {
acc, err := tm.accountsDB.GetAccountByAddress(types.Address(multiTransaction.FromAddress)) acc, err := tm.accountsDB.GetAccountByAddress(types.Address(multiTransaction.FromAddress))
if err != nil { if err != nil {
@ -244,11 +243,6 @@ func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Cont
return nil, err return nil, err
} }
err = tm.storePendingTransactions(multiTransaction, hashes, data)
if err != nil {
return nil, err
}
return &MultiTransactionCommandResult{ return &MultiTransactionCommandResult{
ID: int64(multiTransactionID), ID: int64(multiTransactionID),
Hashes: hashes, Hashes: hashes,
@ -292,64 +286,26 @@ func (tm *TransactionManager) ProceedWithTransactionsSignatures(ctx context.Cont
// send transactions // send transactions
hashes := make(map[uint64][]types.Hash) hashes := make(map[uint64][]types.Hash)
for _, desc := range tm.transactionsForKeycardSingning { for _, desc := range tm.transactionsForKeycardSingning {
hash, err := tm.transactor.AddSignatureToTransactionAndSend(desc.chainID, desc.builtTx, desc.signature) hash, err := tm.transactor.AddSignatureToTransactionAndSend(
desc.chainID,
desc.from,
tm.multiTransactionForKeycardSigning.FromAsset,
tm.multiTransactionForKeycardSigning.ID,
desc.builtTx,
desc.signature,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hashes[desc.chainID] = append(hashes[desc.chainID], hash) hashes[desc.chainID] = append(hashes[desc.chainID], hash)
} }
err := tm.storePendingTransactions(tm.multiTransactionForKeycardSigning, hashes, tm.transactionsBridgeData)
if err != nil {
return nil, err
}
return &MultiTransactionCommandResult{ return &MultiTransactionCommandResult{
ID: int64(tm.multiTransactionForKeycardSigning.ID), ID: int64(tm.multiTransactionForKeycardSigning.ID),
Hashes: hashes, Hashes: hashes,
}, nil }, nil
} }
func (tm *TransactionManager) storePendingTransactions(multiTransaction *MultiTransaction,
hashes map[uint64][]types.Hash, data []*bridge.TransactionBridge) error {
txs := createPendingTransactions(hashes, data, multiTransaction)
for _, tx := range txs {
err := tm.pendingTracker.StoreAndTrackPendingTx(tx)
if err != nil {
return err
}
}
return nil
}
func createPendingTransactions(hashes map[uint64][]types.Hash, data []*bridge.TransactionBridge,
multiTransaction *MultiTransaction) []*transactions.PendingTransaction {
txs := make([]*transactions.PendingTransaction, 0)
for _, tx := range data {
for _, hash := range hashes[tx.ChainID] {
pendingTransaction := &transactions.PendingTransaction{
Hash: common.Hash(hash),
Timestamp: uint64(time.Now().Unix()),
Value: bigint.BigInt{Int: multiTransaction.FromAmount.ToInt()},
From: common.Address(tx.From()),
To: common.Address(tx.To()),
Data: tx.Data().String(),
Type: transactions.WalletTransfer,
ChainID: wallet_common.ChainID(tx.ChainID),
MultiTransactionID: int64(multiTransaction.ID),
Symbol: multiTransaction.FromAsset,
AutoDelete: new(bool),
}
// Transaction downloader will delete pending transaction as soon as it is confirmed
*pendingTransaction.AutoDelete = false
txs = append(txs, pendingTransaction)
}
}
return txs
}
func multiTransactionFromCommand(command *MultiTransactionCommand) *MultiTransaction { func multiTransactionFromCommand(command *MultiTransactionCommand) *MultiTransaction {
log.Info("Creating multi transaction", "command", command) log.Info("Creating multi transaction", "command", command)
@ -380,6 +336,7 @@ func (tm *TransactionManager) buildTransactions(bridges map[string]bridge.Bridge
txHash := signer.Hash(builtTx) txHash := signer.Hash(builtTx)
tm.transactionsForKeycardSingning[txHash] = &TransactionDescription{ tm.transactionsForKeycardSingning[txHash] = &TransactionDescription{
from: common.Address(bridgeTx.From()),
chainID: bridgeTx.ChainID, chainID: bridgeTx.ChainID,
builtTx: builtTx, builtTx: builtTx,
} }
@ -403,6 +360,27 @@ func (tm *TransactionManager) sendTransactions(multiTransaction *MultiTransactio
hashes := make(map[uint64][]types.Hash) hashes := make(map[uint64][]types.Hash)
for _, tx := range data { for _, tx := range data {
if tx.TransferTx != nil {
tx.TransferTx.MultiTransactionID = multiTransaction.ID
tx.TransferTx.Symbol = multiTransaction.FromAsset
}
if tx.HopTx != nil {
tx.HopTx.MultiTransactionID = multiTransaction.ID
tx.HopTx.Symbol = multiTransaction.FromAsset
}
if tx.CbridgeTx != nil {
tx.CbridgeTx.MultiTransactionID = multiTransaction.ID
tx.CbridgeTx.Symbol = multiTransaction.FromAsset
}
if tx.ERC721TransferTx != nil {
tx.ERC721TransferTx.MultiTransactionID = multiTransaction.ID
tx.ERC721TransferTx.Symbol = multiTransaction.FromAsset
}
if tx.ERC1155TransferTx != nil {
tx.ERC1155TransferTx.MultiTransactionID = multiTransaction.ID
tx.ERC1155TransferTx.Symbol = multiTransaction.FromAsset
}
hash, err := bridges[tx.BridgeName].Send(tx, selectedAccount) hash, err := bridges[tx.BridgeName].Send(tx, selectedAccount)
if err != nil { if err != nil {
return nil, err return nil, err
@ -412,7 +390,7 @@ func (tm *TransactionManager) sendTransactions(multiTransaction *MultiTransactio
return hashes, nil return hashes, nil
} }
func (tm *TransactionManager) GetMultiTransactions(ctx context.Context, ids []MultiTransactionIDType) ([]*MultiTransaction, error) { func (tm *TransactionManager) GetMultiTransactions(ctx context.Context, ids []wallet_common.MultiTransactionIDType) ([]*MultiTransaction, error) {
placeholders := make([]string, len(ids)) placeholders := make([]string, len(ids))
args := make([]interface{}, len(ids)) args := make([]interface{}, len(ids))
for i, v := range ids { for i, v := range ids {

View File

@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
wallet_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/t/helpers" "github.com/status-im/status-go/t/helpers"
"github.com/status-im/status-go/walletdatabase" "github.com/status-im/status-go/walletdatabase"
@ -77,11 +78,11 @@ func TestBridgeMultiTransactions(t *testing.T) {
trxs := []*MultiTransaction{&trx1, &trx2} trxs := []*MultiTransaction{&trx1, &trx2}
var err error var err error
ids := make([]MultiTransactionIDType, len(trxs)) ids := make([]wallet_common.MultiTransactionIDType, len(trxs))
for i, trx := range trxs { for i, trx := range trxs {
ids[i], err = insertMultiTransaction(manager.db, trx) ids[i], err = insertMultiTransaction(manager.db, trx)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, MultiTransactionIDType(i+1), ids[i]) require.Equal(t, wallet_common.MultiTransactionIDType(i+1), ids[i])
} }
rst, err := manager.GetBridgeOriginMultiTransaction(context.Background(), trx1.ToNetworkID, trx1.CrossTxID) rst, err := manager.GetBridgeOriginMultiTransaction(context.Background(), trx1.ToNetworkID, trx1.CrossTxID)
@ -129,14 +130,14 @@ func TestMultiTransactions(t *testing.T) {
trxs := []*MultiTransaction{&trx1, &trx2} trxs := []*MultiTransaction{&trx1, &trx2}
var err error var err error
ids := make([]MultiTransactionIDType, len(trxs)) ids := make([]wallet_common.MultiTransactionIDType, len(trxs))
for i, trx := range trxs { for i, trx := range trxs {
ids[i], err = insertMultiTransaction(manager.db, trx) ids[i], err = insertMultiTransaction(manager.db, trx)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, MultiTransactionIDType(i+1), ids[i]) require.Equal(t, wallet_common.MultiTransactionIDType(i+1), ids[i])
} }
rst, err := manager.GetMultiTransactions(context.Background(), []MultiTransactionIDType{ids[0], 555}) rst, err := manager.GetMultiTransactions(context.Background(), []wallet_common.MultiTransactionIDType{ids[0], 555})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(rst)) require.Equal(t, 1, len(rst))
require.True(t, areMultiTransactionsEqual(trxs[0], rst[0])) require.True(t, areMultiTransactionsEqual(trxs[0], rst[0]))
@ -153,7 +154,7 @@ func TestMultiTransactions(t *testing.T) {
for i, id := range ids { for i, id := range ids {
found := false found := false
for _, trx := range rst { for _, trx := range rst {
if id == MultiTransactionIDType(trx.ID) { if id == trx.ID {
found = true found = true
require.True(t, areMultiTransactionsEqual(trxs[i], trx)) require.True(t, areMultiTransactionsEqual(trxs[i], trx))
break break

View File

@ -21,6 +21,7 @@ import (
"github.com/status-im/status-go/services/rpcfilters" "github.com/status-im/status-go/services/rpcfilters"
"github.com/status-im/status-go/services/wallet/bigint" "github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/services/wallet/common"
wallet_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/walletevent" "github.com/status-im/status-go/services/wallet/walletevent"
) )
@ -417,7 +418,8 @@ type PendingTransaction struct {
Type PendingTrxType `json:"type"` Type PendingTrxType `json:"type"`
AdditionalData string `json:"additionalData"` AdditionalData string `json:"additionalData"`
ChainID common.ChainID `json:"network_id"` ChainID common.ChainID `json:"network_id"`
MultiTransactionID int64 `json:"multi_transaction_id"` MultiTransactionID wallet_common.MultiTransactionIDType `json:"multi_transaction_id"`
Nonce uint64 `json:"nonce"`
// nil will insert the default value (Pending) in DB // nil will insert the default value (Pending) in DB
Status *TxStatus `json:"status,omitempty"` Status *TxStatus `json:"status,omitempty"`
@ -427,7 +429,7 @@ type PendingTransaction struct {
const selectFromPending = `SELECT hash, timestamp, value, from_address, to_address, data, const selectFromPending = `SELECT hash, timestamp, value, from_address, to_address, data,
symbol, gas_price, gas_limit, type, additional_data, symbol, gas_price, gas_limit, type, additional_data,
network_id, COALESCE(multi_transaction_id, 0), status, auto_delete network_id, COALESCE(multi_transaction_id, 0), status, auto_delete, nonce
FROM pending_transactions FROM pending_transactions
` `
@ -456,6 +458,7 @@ func rowsToTransactions(rows *sql.Rows) (transactions []*PendingTransaction, err
&transaction.MultiTransactionID, &transaction.MultiTransactionID,
transaction.Status, transaction.Status,
transaction.AutoDelete, transaction.AutoDelete,
&transaction.Nonce,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -517,6 +520,23 @@ func (tm *PendingTxTracker) GetPendingEntry(chainID common.ChainID, hash eth.Has
return trs[0], nil return trs[0], nil
} }
func (tm *PendingTxTracker) GetPendingTxForSuggestedNonce(chainID common.ChainID, address eth.Address, nonce uint64) (pendingTx uint64, err error) {
err = tm.db.QueryRow(`
SELECT
COUNT(nonce)
FROM
pending_transactions
WHERE
network_id = ?
AND
from_address = ?
AND
nonce >= ?`,
chainID, address, nonce).
Scan(&pendingTx)
return
}
// StoreAndTrackPendingTx store the details of a pending transaction and track it until it is mined // StoreAndTrackPendingTx store the details of a pending transaction and track it until it is mined
func (tm *PendingTxTracker) StoreAndTrackPendingTx(transaction *PendingTransaction) error { func (tm *PendingTxTracker) StoreAndTrackPendingTx(transaction *PendingTransaction) error {
err := tm.addPending(transaction) err := tm.addPending(transaction)
@ -530,14 +550,67 @@ func (tm *PendingTxTracker) StoreAndTrackPendingTx(transaction *PendingTransacti
} }
func (tm *PendingTxTracker) addPending(transaction *PendingTransaction) error { func (tm *PendingTxTracker) addPending(transaction *PendingTransaction) error {
insert, err := tm.db.Prepare(`INSERT OR REPLACE INTO pending_transactions var notifyFn func()
(network_id, hash, timestamp, value, from_address, to_address, tx, err := tm.db.Begin()
data, symbol, gas_price, gas_limit, type, additional_data, multi_transaction_id, status, auto_delete)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ?)`)
if err != nil { if err != nil {
return err return err
} }
defer func() {
if err == nil {
err = tx.Commit()
if notifyFn != nil {
notifyFn()
}
return
}
_ = tx.Rollback()
}()
exists := true
var hash eth.Hash
err = tx.QueryRow(`
SELECT hash
FROM
pending_transactions
WHERE
network_id = ?
AND
from_address = ?
AND
nonce = ?
`,
transaction.ChainID,
transaction.From,
transaction.Nonce).
Scan(&hash)
if err != nil {
if err == sql.ErrNoRows {
exists = false
} else {
return err
}
}
if exists {
notifyFn, err = tm.DeleteBySQLTx(tx, transaction.ChainID, hash)
if err != nil && err != ErrStillPending {
return err
}
}
// TODO: maybe we should think of making (network_id, from_address, nonce) as primary key instead (network_id, hash) ????
insert, err := tx.Prepare(`INSERT OR REPLACE INTO pending_transactions
(network_id, hash, timestamp, value, from_address, to_address,
data, symbol, gas_price, gas_limit, type, additional_data, multi_transaction_id, status,
auto_delete, nonce)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ?, ?)`)
if err != nil {
return err
}
defer insert.Close()
_, err = insert.Exec( _, err = insert.Exec(
transaction.ChainID, transaction.ChainID,
transaction.Hash, transaction.Hash,
@ -554,6 +627,7 @@ func (tm *PendingTxTracker) addPending(transaction *PendingTransaction) error {
transaction.MultiTransactionID, transaction.MultiTransactionID,
transaction.Status, transaction.Status,
transaction.AutoDelete, transaction.AutoDelete,
transaction.Nonce,
) )
// Notify listeners of new pending transaction (used in activity history) // Notify listeners of new pending transaction (used in activity history)
if err == nil { if err == nil {

View File

@ -19,6 +19,8 @@ import (
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/status-im/status-go/rpc" "github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/wallet/bigint"
wallet_common "github.com/status-im/status-go/services/wallet/common"
) )
const ( const (
@ -46,6 +48,7 @@ func (e *ErrBadNonce) Error() string {
// It uses upstream to propagate transactions to the Ethereum network. // It uses upstream to propagate transactions to the Ethereum network.
type Transactor struct { type Transactor struct {
rpcWrapper *rpcWrapper rpcWrapper *rpcWrapper
pendingTracker *PendingTxTracker
sendTxTimeout time.Duration sendTxTimeout time.Duration
rpcCallTimeout time.Duration rpcCallTimeout time.Duration
networkID uint64 networkID uint64
@ -60,6 +63,11 @@ func NewTransactor() *Transactor {
} }
} }
// SetPendingTracker sets a pending tracker.
func (t *Transactor) SetPendingTracker(tracker *PendingTxTracker) {
t.pendingTracker = tracker
}
// SetNetworkID selects a correct network. // SetNetworkID selects a correct network.
func (t *Transactor) SetNetworkID(networkID uint64) { func (t *Transactor) SetNetworkID(networkID uint64) {
t.networkID = networkID t.networkID = networkID
@ -78,7 +86,26 @@ func (t *Transactor) SetRPC(rpcClient *rpc.Client, timeout time.Duration) {
func (t *Transactor) NextNonce(rpcClient *rpc.Client, chainID uint64, from types.Address) (uint64, error) { func (t *Transactor) NextNonce(rpcClient *rpc.Client, chainID uint64, from types.Address) (uint64, error) {
wrapper := newRPCWrapper(rpcClient, chainID) wrapper := newRPCWrapper(rpcClient, chainID)
ctx := context.Background() ctx := context.Background()
return wrapper.PendingNonceAt(ctx, common.Address(from)) nonce, err := wrapper.PendingNonceAt(ctx, common.Address(from))
if err != nil {
return 0, err
}
// We need to take into consideration all pending transactions in case of Optimism, cause the network returns always
// the nonce of last executed tx + 1 for the next nonce value.
if chainID == wallet_common.OptimismMainnet ||
chainID == wallet_common.OptimismSepolia ||
chainID == wallet_common.OptimismGoerli {
if t.pendingTracker != nil {
countOfPendingTXs, err := t.pendingTracker.GetPendingTxForSuggestedNonce(wallet_common.ChainID(chainID), common.Address(from), nonce)
if err != nil {
return 0, err
}
return nonce + countOfPendingTXs, nil
}
}
return nonce, err
} }
func (t *Transactor) EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error) { func (t *Transactor) EstimateGas(network *params.Network, from common.Address, to common.Address, value *big.Int, input []byte) (uint64, error) {
@ -141,25 +168,64 @@ func (t *Transactor) SendRawTransaction(chainID uint64, rawTx string) error {
return rpcWrapper.SendRawTransaction(ctx, rawTx) return rpcWrapper.SendRawTransaction(ctx, rawTx)
} }
func (t *Transactor) SendTransactionWithSignature(tx *gethtypes.Transaction) (hash types.Hash, err error) { func createPendingTransactions(from common.Address, symbol string, chainID uint64, multiTransactionID wallet_common.MultiTransactionIDType, tx *gethtypes.Transaction) (pTx *PendingTransaction) {
rpcWrapper := newRPCWrapper(t.rpcWrapper.RPCClient, tx.ChainId().Uint64())
pTx = &PendingTransaction{
Hash: tx.Hash(),
Timestamp: uint64(time.Now().Unix()),
Value: bigint.BigInt{Int: tx.Value()},
From: from,
To: *tx.To(),
Nonce: tx.Nonce(),
Data: string(tx.Data()),
Type: WalletTransfer,
ChainID: wallet_common.ChainID(chainID),
MultiTransactionID: multiTransactionID,
Symbol: symbol,
AutoDelete: new(bool),
}
// Transaction downloader will delete pending transaction as soon as it is confirmed
*pTx.AutoDelete = false
return
}
func (t *Transactor) sendTransaction(rpcWrapper *rpcWrapper, from common.Address, symbol string,
multiTransactionID wallet_common.MultiTransactionIDType, tx *gethtypes.Transaction) (hash types.Hash, err error) {
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout) ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
defer cancel() defer cancel()
if err := rpcWrapper.SendTransaction(ctx, tx); err != nil { if err := rpcWrapper.SendTransaction(ctx, tx); err != nil {
return hash, err return hash, err
} }
if t.pendingTracker != nil {
tx := createPendingTransactions(from, symbol, rpcWrapper.chainID, multiTransactionID, tx)
err := t.pendingTracker.StoreAndTrackPendingTx(tx)
if err != nil {
return hash, err
}
}
return types.Hash(tx.Hash()), nil return types.Hash(tx.Hash()), nil
} }
func (t *Transactor) AddSignatureToTransactionAndSend(chainID uint64, tx *gethtypes.Transaction, sig []byte) (hash types.Hash, err error) { func (t *Transactor) SendTransactionWithSignature(from common.Address, symbol string,
multiTransactionID wallet_common.MultiTransactionIDType, tx *gethtypes.Transaction) (hash types.Hash, err error) {
rpcWrapper := newRPCWrapper(t.rpcWrapper.RPCClient, tx.ChainId().Uint64())
return t.sendTransaction(rpcWrapper, from, symbol, multiTransactionID, tx)
}
func (t *Transactor) AddSignatureToTransactionAndSend(chainID uint64, from common.Address, symbol string,
multiTransactionID wallet_common.MultiTransactionIDType, tx *gethtypes.Transaction, sig []byte) (hash types.Hash, err error) {
txWithSignature, err := t.AddSignatureToTransaction(chainID, tx, sig) txWithSignature, err := t.AddSignatureToTransaction(chainID, tx, sig)
if err != nil { if err != nil {
return hash, err return hash, err
} }
return t.SendTransactionWithSignature(txWithSignature) return t.SendTransactionWithSignature(from, symbol, multiTransactionID, txWithSignature)
} }
// BuildTransactionAndSendWithSignature receive a transaction and a signature, serialize them together and propage it to the network. // BuildTransactionAndSendWithSignature receive a transaction and a signature, serialize them together and propage it to the network.
@ -171,7 +237,7 @@ func (t *Transactor) BuildTransactionAndSendWithSignature(chainID uint64, args S
return hash, err return hash, err
} }
hash, err = t.SendTransactionWithSignature(txWithSignature) hash, err = t.SendTransactionWithSignature(common.Address(args.From), args.Symbol, args.MultiTransactionID, txWithSignature)
return hash, err return hash, err
} }
@ -378,13 +444,8 @@ func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccoun
if err != nil { if err != nil {
return hash, err return hash, err
} }
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
defer cancel()
if err := rpcWrapper.SendTransaction(ctx, signedTx); err != nil { return t.sendTransaction(rpcWrapper, common.Address(args.From), args.Symbol, args.MultiTransactionID, signedTx)
return hash, err
}
return types.Hash(signedTx.Hash()), nil
} }
func (t *Transactor) buildTransaction(args SendTxArgs) *gethtypes.Transaction { func (t *Transactor) buildTransaction(args SendTxArgs) *gethtypes.Transaction {

View File

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
wallet_common "github.com/status-im/status-go/services/wallet/common"
) )
var ( var (
@ -53,6 +54,10 @@ type SendTxArgs struct {
// see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107` // see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107`
Input types.HexBytes `json:"input"` Input types.HexBytes `json:"input"`
Data types.HexBytes `json:"data"` Data types.HexBytes `json:"data"`
// additional data
MultiTransactionID wallet_common.MultiTransactionIDType
Symbol string
} }
// Valid checks whether this structure is filled in correctly. // Valid checks whether this structure is filled in correctly.

View File

@ -23,6 +23,7 @@
// 1706531789_remove_gasfee-only-eth-transfers.up.sql (627B) // 1706531789_remove_gasfee-only-eth-transfers.up.sql (627B)
// 1707160323_add_contract_type_table.up.sql (282B) // 1707160323_add_contract_type_table.up.sql (282B)
// 1708089811_add_nullable_fiesl_blocks_ranges.up.sql (450B) // 1708089811_add_nullable_fiesl_blocks_ranges.up.sql (450B)
// 1710189541_add_nonce_to_pending_transactions.up.sql (54B)
// doc.go (94B) // doc.go (94B)
package migrations package migrations
@ -33,6 +34,7 @@ import (
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -42,7 +44,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) { func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data)) gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil { if err != nil {
return nil, fmt.Errorf("read %q: %w", name, err) return nil, fmt.Errorf("read %q: %v", name, err)
} }
var buf bytes.Buffer var buf bytes.Buffer
@ -50,7 +52,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close() clErr := gz.Close()
if err != nil { if err != nil {
return nil, fmt.Errorf("read %q: %w", name, err) return nil, fmt.Errorf("read %q: %v", name, err)
} }
if clErr != nil { if clErr != nil {
return nil, err return nil, err
@ -551,6 +553,26 @@ func _1708089811_add_nullable_fiesl_blocks_rangesUpSql() (*asset, error) {
return a, nil return a, nil
} }
var __1710189541_add_nonce_to_pending_transactionsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x48\xcd\x4b\xc9\xcc\x4b\x8f\x2f\x29\x4a\xcc\x2b\x4e\x4c\x2e\xc9\xcc\xcf\x2b\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\xc8\xcb\xcf\x4b\x4e\x55\xf0\xf4\x0b\xb1\x06\x04\x00\x00\xff\xff\x87\x1f\x38\x0b\x36\x00\x00\x00")
func _1710189541_add_nonce_to_pending_transactionsUpSqlBytes() ([]byte, error) {
return bindataRead(
__1710189541_add_nonce_to_pending_transactionsUpSql,
"1710189541_add_nonce_to_pending_transactions.up.sql",
)
}
func _1710189541_add_nonce_to_pending_transactionsUpSql() (*asset, error) {
bytes, err := _1710189541_add_nonce_to_pending_transactionsUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1710189541_add_nonce_to_pending_transactions.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6, 0x2e, 0x35, 0x7c, 0xf, 0x9, 0x63, 0x64, 0x4d, 0xdf, 0x8f, 0x99, 0x96, 0x66, 0xda, 0x81, 0x56, 0x84, 0x3b, 0xbf, 0x88, 0xf9, 0xb0, 0x7d, 0x9f, 0x87, 0x74, 0xa9, 0xb, 0x9a, 0x70, 0xcb}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xcb\x41\x0e\x02\x31\x08\x05\xd0\x7d\x4f\xf1\x2f\x00\xe8\xca\xc4\xc4\xc3\xa0\x43\x08\x19\x5b\xc6\x96\xfb\xc7\x4d\xdf\xfe\x5d\xfa\x39\xd5\x0d\xeb\xf7\x6d\x4d\xc4\xf3\xe9\x36\x6c\x6a\x19\x3c\xe9\x1d\xe3\xd0\x52\x50\xcf\xa3\xa2\xdb\xeb\xfe\xb8\x6d\xa0\xeb\x74\xf4\xf0\xa9\x15\x39\x16\x28\xc1\x2c\x7b\xb0\x27\x58\xda\x3f\x00\x00\xff\xff\x57\xd4\xd5\x90\x5e\x00\x00\x00") var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xcb\x41\x0e\x02\x31\x08\x05\xd0\x7d\x4f\xf1\x2f\x00\xe8\xca\xc4\xc4\xc3\xa0\x43\x08\x19\x5b\xc6\x96\xfb\xc7\x4d\xdf\xfe\x5d\xfa\x39\xd5\x0d\xeb\xf7\x6d\x4d\xc4\xf3\xe9\x36\x6c\x6a\x19\x3c\xe9\x1d\xe3\xd0\x52\x50\xcf\xa3\xa2\xdb\xeb\xfe\xb8\x6d\xa0\xeb\x74\xf4\xf0\xa9\x15\x39\x16\x28\xc1\x2c\x7b\xb0\x27\x58\xda\x3f\x00\x00\xff\xff\x57\xd4\xd5\x90\x5e\x00\x00\x00")
func docGoBytes() ([]byte, error) { func docGoBytes() ([]byte, error) {
@ -663,45 +685,65 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name. // _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){ var _bindata = map[string]func() (*asset, error){
"1691753758_initial.up.sql": _1691753758_initialUpSql, "1691753758_initial.up.sql": _1691753758_initialUpSql,
"1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql, "1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql,
"1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql, "1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql,
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": _1694540071_add_collectibles_ownership_update_timestampUpSql, "1694540071_add_collectibles_ownership_update_timestamp.up.sql": _1694540071_add_collectibles_ownership_update_timestampUpSql,
"1694692748_add_raw_balance_to_token_balances.up.sql": _1694692748_add_raw_balance_to_token_balancesUpSql, "1694692748_add_raw_balance_to_token_balances.up.sql": _1694692748_add_raw_balance_to_token_balancesUpSql,
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql, "1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql,
"1695932536_balance_history_v2.up.sql": _1695932536_balance_history_v2UpSql, "1695932536_balance_history_v2.up.sql": _1695932536_balance_history_v2UpSql,
"1696853635_input_data.up.sql": _1696853635_input_dataUpSql, "1696853635_input_data.up.sql": _1696853635_input_dataUpSql,
"1698117918_add_community_id_to_tokens.up.sql": _1698117918_add_community_id_to_tokensUpSql, "1698117918_add_community_id_to_tokens.up.sql": _1698117918_add_community_id_to_tokensUpSql,
"1698257443_add_community_metadata_to_wallet_db.up.sql": _1698257443_add_community_metadata_to_wallet_dbUpSql, "1698257443_add_community_metadata_to_wallet_db.up.sql": _1698257443_add_community_metadata_to_wallet_dbUpSql,
"1699987075_add_timestamp_and_state_to_community_data_cache.up.sql": _1699987075_add_timestamp_and_state_to_community_data_cacheUpSql, "1699987075_add_timestamp_and_state_to_community_data_cache.up.sql": _1699987075_add_timestamp_and_state_to_community_data_cacheUpSql,
"1700414564_add_wallet_connect_pairings_table.up.sql": _1700414564_add_wallet_connect_pairings_tableUpSql, "1700414564_add_wallet_connect_pairings_table.up.sql": _1700414564_add_wallet_connect_pairings_tableUpSql,
"1701101493_add_token_blocks_range.up.sql": _1701101493_add_token_blocks_rangeUpSql, "1701101493_add_token_blocks_range.up.sql": _1701101493_add_token_blocks_rangeUpSql,
"1702467441_wallet_connect_sessions_instead_of_pairings.up.sql": _1702467441_wallet_connect_sessions_instead_of_pairingsUpSql, "1702467441_wallet_connect_sessions_instead_of_pairings.up.sql": _1702467441_wallet_connect_sessions_instead_of_pairingsUpSql,
"1702577524_add_community_collections_and_collectibles_images_cache.up.sql": _1702577524_add_community_collections_and_collectibles_images_cacheUpSql, "1702577524_add_community_collections_and_collectibles_images_cache.up.sql": _1702577524_add_community_collections_and_collectibles_images_cacheUpSql,
"1702867707_add_balance_to_collectibles_ownership_cache.up.sql": _1702867707_add_balance_to_collectibles_ownership_cacheUpSql, "1702867707_add_balance_to_collectibles_ownership_cache.up.sql": _1702867707_add_balance_to_collectibles_ownership_cacheUpSql,
"1703686612_add_color_to_saved_addresses.up.sql": _1703686612_add_color_to_saved_addressesUpSql, "1703686612_add_color_to_saved_addresses.up.sql": _1703686612_add_color_to_saved_addressesUpSql,
"1704701942_remove_favourite_and_change_primary_key_for_saved_addresses.up.sql": _1704701942_remove_favourite_and_change_primary_key_for_saved_addressesUpSql, "1704701942_remove_favourite_and_change_primary_key_for_saved_addresses.up.sql": _1704701942_remove_favourite_and_change_primary_key_for_saved_addressesUpSql,
"1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cache.up.sql": _1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cacheUpSql, "1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cache.up.sql": _1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cacheUpSql,
"1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": _1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql, "1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": _1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql,
"1706531789_remove_gasfee-only-eth-transfers.up.sql": _1706531789_remove_gasfeeOnlyEthTransfersUpSql, "1706531789_remove_gasfee-only-eth-transfers.up.sql": _1706531789_remove_gasfeeOnlyEthTransfersUpSql,
"1707160323_add_contract_type_table.up.sql": _1707160323_add_contract_type_tableUpSql, "1707160323_add_contract_type_table.up.sql": _1707160323_add_contract_type_tableUpSql,
"1708089811_add_nullable_fiesl_blocks_ranges.up.sql": _1708089811_add_nullable_fiesl_blocks_rangesUpSql, "1708089811_add_nullable_fiesl_blocks_ranges.up.sql": _1708089811_add_nullable_fiesl_blocks_rangesUpSql,
"1710189541_add_nonce_to_pending_transactions.up.sql": _1710189541_add_nonce_to_pending_transactionsUpSql,
"doc.go": docGo, "doc.go": docGo,
} }
// AssetDebug is true if the assets were built with the debug flag enabled.
const AssetDebug = false
// AssetDir returns the file names below a certain // AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata. // directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the // For example if you run go-bindata on data/... and data contains the
// following hierarchy: // following hierarchy:
//
// data/ // data/
// foo.txt // foo.txt
// img/ // img/
// a.png // a.png
// b.png // b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}, // then AssetDir("data") would return []string{"foo.txt", "img"},
// AssetDir("data/img") would return []string{"a.png", "b.png"}, // AssetDir("data/img") would return []string{"a.png", "b.png"},
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
@ -734,30 +776,31 @@ type bintree struct {
} }
var _bintree = &bintree{nil, map[string]*bintree{ var _bintree = &bintree{nil, map[string]*bintree{
"1691753758_initial.up.sql": {_1691753758_initialUpSql, map[string]*bintree{}}, "1691753758_initial.up.sql": &bintree{_1691753758_initialUpSql, map[string]*bintree{}},
"1692701329_add_collectibles_and_collections_data_cache.up.sql": {_1692701329_add_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}}, "1692701329_add_collectibles_and_collections_data_cache.up.sql": &bintree{_1692701329_add_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
"1692701339_add_scope_to_pending.up.sql": {_1692701339_add_scope_to_pendingUpSql, map[string]*bintree{}}, "1692701339_add_scope_to_pending.up.sql": &bintree{_1692701339_add_scope_to_pendingUpSql, map[string]*bintree{}},
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": {_1694540071_add_collectibles_ownership_update_timestampUpSql, map[string]*bintree{}}, "1694540071_add_collectibles_ownership_update_timestamp.up.sql": &bintree{_1694540071_add_collectibles_ownership_update_timestampUpSql, map[string]*bintree{}},
"1694692748_add_raw_balance_to_token_balances.up.sql": {_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}}, "1694692748_add_raw_balance_to_token_balances.up.sql": &bintree{_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}},
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": {_1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}}, "1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": &bintree{_1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
"1695932536_balance_history_v2.up.sql": {_1695932536_balance_history_v2UpSql, map[string]*bintree{}}, "1695932536_balance_history_v2.up.sql": &bintree{_1695932536_balance_history_v2UpSql, map[string]*bintree{}},
"1696853635_input_data.up.sql": {_1696853635_input_dataUpSql, map[string]*bintree{}}, "1696853635_input_data.up.sql": &bintree{_1696853635_input_dataUpSql, map[string]*bintree{}},
"1698117918_add_community_id_to_tokens.up.sql": {_1698117918_add_community_id_to_tokensUpSql, map[string]*bintree{}}, "1698117918_add_community_id_to_tokens.up.sql": &bintree{_1698117918_add_community_id_to_tokensUpSql, map[string]*bintree{}},
"1698257443_add_community_metadata_to_wallet_db.up.sql": {_1698257443_add_community_metadata_to_wallet_dbUpSql, map[string]*bintree{}}, "1698257443_add_community_metadata_to_wallet_db.up.sql": &bintree{_1698257443_add_community_metadata_to_wallet_dbUpSql, map[string]*bintree{}},
"1699987075_add_timestamp_and_state_to_community_data_cache.up.sql": {_1699987075_add_timestamp_and_state_to_community_data_cacheUpSql, map[string]*bintree{}}, "1699987075_add_timestamp_and_state_to_community_data_cache.up.sql": &bintree{_1699987075_add_timestamp_and_state_to_community_data_cacheUpSql, map[string]*bintree{}},
"1700414564_add_wallet_connect_pairings_table.up.sql": {_1700414564_add_wallet_connect_pairings_tableUpSql, map[string]*bintree{}}, "1700414564_add_wallet_connect_pairings_table.up.sql": &bintree{_1700414564_add_wallet_connect_pairings_tableUpSql, map[string]*bintree{}},
"1701101493_add_token_blocks_range.up.sql": {_1701101493_add_token_blocks_rangeUpSql, map[string]*bintree{}}, "1701101493_add_token_blocks_range.up.sql": &bintree{_1701101493_add_token_blocks_rangeUpSql, map[string]*bintree{}},
"1702467441_wallet_connect_sessions_instead_of_pairings.up.sql": {_1702467441_wallet_connect_sessions_instead_of_pairingsUpSql, map[string]*bintree{}}, "1702467441_wallet_connect_sessions_instead_of_pairings.up.sql": &bintree{_1702467441_wallet_connect_sessions_instead_of_pairingsUpSql, map[string]*bintree{}},
"1702577524_add_community_collections_and_collectibles_images_cache.up.sql": {_1702577524_add_community_collections_and_collectibles_images_cacheUpSql, map[string]*bintree{}}, "1702577524_add_community_collections_and_collectibles_images_cache.up.sql": &bintree{_1702577524_add_community_collections_and_collectibles_images_cacheUpSql, map[string]*bintree{}},
"1702867707_add_balance_to_collectibles_ownership_cache.up.sql": {_1702867707_add_balance_to_collectibles_ownership_cacheUpSql, map[string]*bintree{}}, "1702867707_add_balance_to_collectibles_ownership_cache.up.sql": &bintree{_1702867707_add_balance_to_collectibles_ownership_cacheUpSql, map[string]*bintree{}},
"1703686612_add_color_to_saved_addresses.up.sql": {_1703686612_add_color_to_saved_addressesUpSql, map[string]*bintree{}}, "1703686612_add_color_to_saved_addresses.up.sql": &bintree{_1703686612_add_color_to_saved_addressesUpSql, map[string]*bintree{}},
"1704701942_remove_favourite_and_change_primary_key_for_saved_addresses.up.sql": {_1704701942_remove_favourite_and_change_primary_key_for_saved_addressesUpSql, map[string]*bintree{}}, "1704701942_remove_favourite_and_change_primary_key_for_saved_addresses.up.sql": &bintree{_1704701942_remove_favourite_and_change_primary_key_for_saved_addressesUpSql, map[string]*bintree{}},
"1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cache.up.sql": {_1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cacheUpSql, map[string]*bintree{}}, "1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cache.up.sql": &bintree{_1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cacheUpSql, map[string]*bintree{}},
"1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": {_1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql, map[string]*bintree{}}, "1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": &bintree{_1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql, map[string]*bintree{}},
"1706531789_remove_gasfee-only-eth-transfers.up.sql": {_1706531789_remove_gasfeeOnlyEthTransfersUpSql, map[string]*bintree{}}, "1706531789_remove_gasfee-only-eth-transfers.up.sql": &bintree{_1706531789_remove_gasfeeOnlyEthTransfersUpSql, map[string]*bintree{}},
"1707160323_add_contract_type_table.up.sql": {_1707160323_add_contract_type_tableUpSql, map[string]*bintree{}}, "1707160323_add_contract_type_table.up.sql": &bintree{_1707160323_add_contract_type_tableUpSql, map[string]*bintree{}},
"1708089811_add_nullable_fiesl_blocks_ranges.up.sql": {_1708089811_add_nullable_fiesl_blocks_rangesUpSql, map[string]*bintree{}}, "1708089811_add_nullable_fiesl_blocks_ranges.up.sql": &bintree{_1708089811_add_nullable_fiesl_blocks_rangesUpSql, map[string]*bintree{}},
"doc.go": {docGo, map[string]*bintree{}}, "1710189541_add_nonce_to_pending_transactions.up.sql": &bintree{_1710189541_add_nonce_to_pending_transactionsUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}} }}
// RestoreAsset restores an asset under the given directory. // RestoreAsset restores an asset under the given directory.
@ -774,7 +817,7 @@ func RestoreAsset(dir, name string) error {
if err != nil { if err != nil {
return err return err
} }
err = os.WriteFile(_filePath(dir, name), data, info.Mode()) err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil { if err != nil {
return err return err
} }

View File

@ -0,0 +1 @@
ALTER TABLE pending_transactions ADD COLUMN nonce INT;