fix: calculating next nonce for optimism chain improved to align with calculation on mainnet and arbitrum
This commit is contained in:
parent
b987e8d6f5
commit
f69ee07593
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -75,25 +75,25 @@ type Entry struct {
|
||||||
|
|
||||||
// Only used for JSON marshalling
|
// Only used for JSON marshalling
|
||||||
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"`
|
||||||
AmountOut *hexutil.Big `json:"amountOut,omitempty"`
|
AmountOut *hexutil.Big `json:"amountOut,omitempty"`
|
||||||
AmountIn *hexutil.Big `json:"amountIn,omitempty"`
|
AmountIn *hexutil.Big `json:"amountIn,omitempty"`
|
||||||
TokenOut *Token `json:"tokenOut,omitempty"`
|
TokenOut *Token `json:"tokenOut,omitempty"`
|
||||||
TokenIn *Token `json:"tokenIn,omitempty"`
|
TokenIn *Token `json:"tokenIn,omitempty"`
|
||||||
SymbolOut *string `json:"symbolOut,omitempty"`
|
SymbolOut *string `json:"symbolOut,omitempty"`
|
||||||
SymbolIn *string `json:"symbolIn,omitempty"`
|
SymbolIn *string `json:"symbolIn,omitempty"`
|
||||||
Sender *eth.Address `json:"sender,omitempty"`
|
Sender *eth.Address `json:"sender,omitempty"`
|
||||||
Recipient *eth.Address `json:"recipient,omitempty"`
|
Recipient *eth.Address `json:"recipient,omitempty"`
|
||||||
ChainIDOut *common.ChainID `json:"chainIdOut,omitempty"`
|
ChainIDOut *common.ChainID `json:"chainIdOut,omitempty"`
|
||||||
ChainIDIn *common.ChainID `json:"chainIdIn,omitempty"`
|
ChainIDIn *common.ChainID `json:"chainIdIn,omitempty"`
|
||||||
TransferType *TransferType `json:"transferType,omitempty"`
|
TransferType *TransferType `json:"transferType,omitempty"`
|
||||||
ContractAddress *eth.Address `json:"contractAddress,omitempty"`
|
ContractAddress *eth.Address `json:"contractAddress,omitempty"`
|
||||||
CommunityID *string `json:"communityId,omitempty"`
|
CommunityID *string `json:"communityId,omitempty"`
|
||||||
|
|
||||||
IsNew *bool `json:"isNew,omitempty"`
|
IsNew *bool `json:"isNew,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
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MultiTransactionIDType int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoMultiTransactionID = MultiTransactionIDType(0)
|
||||||
|
)
|
||||||
|
|
||||||
type ChainID uint64
|
type ChainID uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,19 +86,19 @@ 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"`
|
||||||
FromTxHash common.Hash `json:"fromTxHash"`
|
FromTxHash common.Hash `json:"fromTxHash"`
|
||||||
ToTxHash common.Hash `json:"toTxHash"`
|
ToTxHash common.Hash `json:"toTxHash"`
|
||||||
FromAddress common.Address `json:"fromAddress"`
|
FromAddress common.Address `json:"fromAddress"`
|
||||||
ToAddress common.Address `json:"toAddress"`
|
ToAddress common.Address `json:"toAddress"`
|
||||||
FromAsset string `json:"fromAsset"`
|
FromAsset string `json:"fromAsset"`
|
||||||
ToAsset string `json:"toAsset"`
|
ToAsset string `json:"toAsset"`
|
||||||
FromAmount *hexutil.Big `json:"fromAmount"`
|
FromAmount *hexutil.Big `json:"fromAmount"`
|
||||||
ToAmount *hexutil.Big `json:"toAmount"`
|
ToAmount *hexutil.Big `json:"toAmount"`
|
||||||
Type MultiTransactionType `json:"type"`
|
Type MultiTransactionType `json:"type"`
|
||||||
CrossTxID string
|
CrossTxID string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -405,19 +406,20 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type PendingTransaction struct {
|
type PendingTransaction struct {
|
||||||
Hash eth.Hash `json:"hash"`
|
Hash eth.Hash `json:"hash"`
|
||||||
Timestamp uint64 `json:"timestamp"`
|
Timestamp uint64 `json:"timestamp"`
|
||||||
Value bigint.BigInt `json:"value"`
|
Value bigint.BigInt `json:"value"`
|
||||||
From eth.Address `json:"from"`
|
From eth.Address `json:"from"`
|
||||||
To eth.Address `json:"to"`
|
To eth.Address `json:"to"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
GasPrice bigint.BigInt `json:"gasPrice"`
|
GasPrice bigint.BigInt `json:"gasPrice"`
|
||||||
GasLimit bigint.BigInt `json:"gasLimit"`
|
GasLimit bigint.BigInt `json:"gasLimit"`
|
||||||
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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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) {
|
||||||
|
@ -662,46 +684,66 @@ 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,
|
|
||||||
"1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql,
|
"1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql,
|
||||||
"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,
|
"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,
|
||||||
|
|
||||||
|
"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,
|
|
||||||
"1696853635_input_data.up.sql": _1696853635_input_dataUpSql,
|
"1695932536_balance_history_v2.up.sql": _1695932536_balance_history_v2UpSql,
|
||||||
"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,
|
"1696853635_input_data.up.sql": _1696853635_input_dataUpSql,
|
||||||
"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,
|
"1698117918_add_community_id_to_tokens.up.sql": _1698117918_add_community_id_to_tokensUpSql,
|
||||||
"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,
|
"1698257443_add_community_metadata_to_wallet_db.up.sql": _1698257443_add_community_metadata_to_wallet_dbUpSql,
|
||||||
"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,
|
"1699987075_add_timestamp_and_state_to_community_data_cache.up.sql": _1699987075_add_timestamp_and_state_to_community_data_cacheUpSql,
|
||||||
"1703686612_add_color_to_saved_addresses.up.sql": _1703686612_add_color_to_saved_addressesUpSql,
|
|
||||||
|
"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,
|
||||||
|
|
||||||
|
"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,
|
||||||
|
|
||||||
|
"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,
|
||||||
|
|
||||||
"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,
|
|
||||||
"1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": _1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql,
|
"1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cache.up.sql": _1704913491_add_type_and_tx_timestamp_to_collectibles_ownership_cacheUpSql,
|
||||||
"1706531789_remove_gasfee-only-eth-transfers.up.sql": _1706531789_remove_gasfeeOnlyEthTransfersUpSql,
|
|
||||||
"1707160323_add_contract_type_table.up.sql": _1707160323_add_contract_type_tableUpSql,
|
"1705664490_add_balance_check_fields_blocks_ranges_sequential.up.sql": _1705664490_add_balance_check_fields_blocks_ranges_sequentialUpSql,
|
||||||
"1708089811_add_nullable_fiesl_blocks_ranges.up.sql": _1708089811_add_nullable_fiesl_blocks_rangesUpSql,
|
|
||||||
|
"1706531789_remove_gasfee-only-eth-transfers.up.sql": _1706531789_remove_gasfeeOnlyEthTransfersUpSql,
|
||||||
|
|
||||||
|
"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,
|
||||||
|
|
||||||
|
"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
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE pending_transactions ADD COLUMN nonce INT;
|
Loading…
Reference in New Issue