Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
saledjenic committed Sep 6, 2024
1 parent 557c4f7 commit 89425ce
Show file tree
Hide file tree
Showing 33 changed files with 878 additions and 99 deletions.
44 changes: 44 additions & 0 deletions services/wallet/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/status-im/status-go/services/wallet/router"
"github.com/status-im/status-go/services/wallet/router/fees"
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
"github.com/status-im/status-go/services/wallet/router/sendtype"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/transfer"
Expand Down Expand Up @@ -742,6 +743,49 @@ func (api *API) CreateMultiTransaction(ctx context.Context, multiTransactionComm
return nil, api.s.transactionManager.SendTransactionForSigningToKeycard(ctx, cmd, data, api.router.GetPathProcessors())
}

func (api *API) BuildTransactionsFromRoute(ctx context.Context, uuid string, slippagePercentage float32) error {
log.Debug("[WalletAPI::BuildTransactionsFromRoute] builds transactions from the generated best route", "uuid", uuid)

route, routeInputParams := api.router.GetBestRouteAndAssociatedInputParams()
if routeInputParams.Uuid != uuid {
return ErrCannotResolveRouteId
}

//////////////////////////////////////////////////////////////////////////////
// add multitx to db, in order to track it later
var mtType transfer.MultiTransactionType = transfer.MultiTransactionSend
if routeInputParams.SendType == sendtype.Bridge {
mtType = transfer.MultiTransactionBridge
} else if routeInputParams.SendType == sendtype.Swap {
mtType = transfer.MultiTransactionSwap
}

multiTx := transfer.NewMultiTransaction(
/* Timestamp: */ uint64(time.Now().Unix()),
/* FromNetworkID: */ 0,
/* ToNetworkID: */ 0,
/* FromTxHash: */ common.Hash{},
/* ToTxHash: */ common.Hash{},
/* FromAddress: */ routeInputParams.AddrFrom,
/* ToAddress: */ routeInputParams.AddrTo,
/* FromAsset: */ routeInputParams.TokenID,
/* ToAsset: */ routeInputParams.ToTokenID,
/* FromAmount: */ routeInputParams.AmountIn,
/* ToAmount: */ routeInputParams.AmountOut,
/* Type: */ mtType,
/* CrossTxID: */ "",
)
_, err := api.s.transactionManager.InsertMultiTransaction(multiTx)
if err != nil {
return err
}
//////////////////////////////////////////////////////////////////////////////

return api.s.transactionManager.BuildTransactionsFromRoute(route, routeInputParams.AddrFrom, routeInputParams.AddrTo,
api.router.GetPathProcessors(), routeInputParams.Username, routeInputParams.PublicKey, routeInputParams.PackID.ToInt(),
slippagePercentage, multiTx.ID)
}

func (api *API) ProceedWithTransactionsSignatures(ctx context.Context, signatures map[string]transfer.SignatureDetails) (*transfer.MultiTransactionCommandResult, error) {
log.Debug("[WalletAPI:: ProceedWithTransactionsSignatures] sign with signatures and send multi transaction")
return api.s.transactionManager.ProceedWithTransactionsSignatures(ctx, signatures)
Expand Down
4 changes: 3 additions & 1 deletion services/wallet/common/const.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"math/big"
"strconv"
"time"

Expand Down Expand Up @@ -32,7 +33,8 @@ const (
)

var (
ZeroAddress = ethCommon.HexToAddress("0x0000000000000000000000000000000000000000")
ZeroAddress = ethCommon.Address{}
ZeroBigIntValue = big.NewInt(0)

SupportedNetworks = map[uint64]bool{
EthereumMainnet: true,
Expand Down
32 changes: 32 additions & 0 deletions services/wallet/common/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package common

import (
"fmt"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/contracts/ierc20"
)

func PackApprovalInputData(amountIn *big.Int, approvalContractAddress *common.Address) ([]byte, error) {
if approvalContractAddress == nil || *approvalContractAddress == ZeroAddress {
return []byte{}, nil
}

erc20ABI, err := abi.JSON(strings.NewReader(ierc20.IERC20ABI))
if err != nil {
return []byte{}, err
}

return erc20ABI.Pack("approve", approvalContractAddress, amountIn)
}

func GetTokenIdFromSymbol(symbol string) (*big.Int, error) {
id, success := big.NewInt(0).SetString(symbol, 0)
if !success {
return nil, fmt.Errorf("failed to convert %s to big.Int", symbol)
}
return id, nil
}
10 changes: 10 additions & 0 deletions services/wallet/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package wallet

import (
"github.com/status-im/status-go/errors"
)

// Abbreviation `W` for the error code stands for Wallet
var (
ErrCannotResolveRouteId = &errors.ErrorResponse{Code: errors.ErrorCode("W-001"), Details: "cannot resolve route id"}
)
4 changes: 2 additions & 2 deletions services/wallet/requests/router_input_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ func (i *RouteInputParams) Validate() error {

if i.AmountIn != nil &&
i.AmountOut != nil &&
i.AmountIn.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 &&
i.AmountOut.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 {
i.AmountIn.ToInt().Cmp(walletCommon.ZeroBigIntValue) > 0 &&
i.AmountOut.ToInt().Cmp(walletCommon.ZeroBigIntValue) > 0 {
return ErrSwapAmountInAmountOutMustBeExclusive
}

Expand Down
4 changes: 2 additions & 2 deletions services/wallet/router/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/router/routes"

"go.uber.org/zap"
Expand Down Expand Up @@ -108,7 +108,7 @@ func setupRouteValidationMaps(fromLockedAmount map[uint64]*hexutil.Big) (map[uin
fromExcluded := make(map[uint64]bool)

for chainID, amount := range fromLockedAmount {
if amount.ToInt().Cmp(pathprocessor.ZeroBigIntValue) <= 0 {
if amount.ToInt().Cmp(walletCommon.ZeroBigIntValue) <= 0 {
fromExcluded[chainID] = false
} else {
fromIncluded[chainID] = false
Expand Down
12 changes: 6 additions & 6 deletions services/wallet/router/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"

"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/router/routes"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -94,9 +94,9 @@ func TestSetupRouteValidationMaps(t *testing.T) {
{
name: "Mixed zero and non-zero amounts",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(pathprocessor.ZeroBigIntValue),
1: (*hexutil.Big)(walletCommon.ZeroBigIntValue),
2: (*hexutil.Big)(big.NewInt(200)),
3: (*hexutil.Big)(pathprocessor.ZeroBigIntValue),
3: (*hexutil.Big)(walletCommon.ZeroBigIntValue),
4: (*hexutil.Big)(big.NewInt(400)),
},
expectedIncluded: map[uint64]bool{
Expand All @@ -123,8 +123,8 @@ func TestSetupRouteValidationMaps(t *testing.T) {
{
name: "All zero amounts",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(pathprocessor.ZeroBigIntValue),
2: (*hexutil.Big)(pathprocessor.ZeroBigIntValue),
1: (*hexutil.Big)(walletCommon.ZeroBigIntValue),
2: (*hexutil.Big)(walletCommon.ZeroBigIntValue),
},
expectedIncluded: map[uint64]bool{},
expectedExcluded: map[uint64]bool{
Expand All @@ -145,7 +145,7 @@ func TestSetupRouteValidationMaps(t *testing.T) {
{
name: "Single zero amount",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(pathprocessor.ZeroBigIntValue),
1: (*hexutil.Big)(walletCommon.ZeroBigIntValue),
},
expectedIncluded: map[uint64]bool{},
expectedExcluded: map[uint64]bool{
Expand Down
11 changes: 0 additions & 11 deletions services/wallet/router/pathprocessor/constants.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
package pathprocessor

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
)

var (
ZeroAddress = common.Address{}
ZeroBigIntValue = big.NewInt(0)
)

const (
IncreaseEstimatedGasFactor = 1.1
SevenDaysInSeconds = 60 * 60 * 24 * 7
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion services/wallet/router/pathprocessor/multipath_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/big"

"github.com/status-im/status-go/eth-node/types"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/transactions"
)

Expand Down Expand Up @@ -31,7 +32,7 @@ func (t *MultipathProcessorTxArgs) Value() *big.Int {
return t.ERC1155TransferTx.Amount.ToInt()
}

return ZeroBigIntValue
return walletCommon.ZeroBigIntValue
}

func (t *MultipathProcessorTxArgs) From() types.Address {
Expand Down
3 changes: 3 additions & 0 deletions services/wallet/router/pathprocessor/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/transactions"
)

type PathProcessor interface {
Expand All @@ -31,6 +32,8 @@ type PathProcessor interface {
GetContractAddress(params ProcessorInputParams) (common.Address, error)
// BuildTransaction builds the transaction based on MultipathProcessorTxArgs, returns the transaction and the used nonce (lastUsedNonce is -1 if it's the first tx)
BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error)
// BuildTransactionV2 builds the transaction based on SendTxArgs, returns the transaction and the used nonce (lastUsedNonce is -1 if it's the first tx)
BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error)
}

type PathProcessorClearable interface {
Expand Down
71 changes: 70 additions & 1 deletion services/wallet/router/pathprocessor/processor_bridge_celar.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/status-im/status-go/rpc"

"github.com/status-im/status-go/params"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/router/pathprocessor/cbridge"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/token"
Expand Down Expand Up @@ -203,7 +204,7 @@ func (s *CelerBridgeProcessor) CalculateFees(params ProcessorInputParams) (*big.
return nil, nil, ErrFailedToParsePercentageFee
}

return ZeroBigIntValue, new(big.Int).Add(baseFee, percFee), nil
return walletCommon.ZeroBigIntValue, new(big.Int).Add(baseFee, percFee), nil
}

func (c *CelerBridgeProcessor) PackTxInputData(params ProcessorInputParams) ([]byte, error) {
Expand Down Expand Up @@ -301,6 +302,7 @@ func (s *CelerBridgeProcessor) GetContractAddress(params ProcessorInputParams) (
return common.Address{}, ErrContractNotFound
}

// TODO: remove this struct once mobile switches to the new approach
func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (*ethTypes.Transaction, error) {
fromChain := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
if fromChain == nil {
Expand Down Expand Up @@ -363,6 +365,68 @@ func (s *CelerBridgeProcessor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, s
return tx, nil
}

func (s *CelerBridgeProcessor) sendOrBuildV2(sendArgs *transactions.SendTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (*ethTypes.Transaction, error) {
fromChain := s.rpcClient.NetworkManager.Find(sendArgs.FromChainID)
if fromChain == nil {
return nil, ErrNetworkNotFound
}
token := s.tokenManager.FindToken(fromChain, sendArgs.FromTokenID)
if token == nil {
return nil, ErrTokenNotFound
}
addrs, err := s.GetContractAddress(ProcessorInputParams{
FromChain: fromChain,
})
if err != nil {
return nil, createBridgeCellerErrorResponse(err)
}

backend, err := s.rpcClient.EthClient(sendArgs.FromChainID)
if err != nil {
return nil, createBridgeCellerErrorResponse(err)
}
contract, err := celer.NewCeler(addrs, backend)
if err != nil {
return nil, createBridgeCellerErrorResponse(err)
}

if lastUsedNonce >= 0 {
lastUsedNonceHexUtil := hexutil.Uint64(uint64(lastUsedNonce) + 1)
sendArgs.Nonce = &lastUsedNonceHexUtil
}

var tx *ethTypes.Transaction
txOpts := sendArgs.ToTransactOpts(signerFn)
if token.IsNative() {
tx, err = contract.SendNative(
txOpts,
common.Address(*sendArgs.To),
(*big.Int)(sendArgs.Value),
sendArgs.FromChainID,
uint64(time.Now().UnixMilli()),
maxSlippage,
)
} else {
tx, err = contract.Send(
txOpts,
common.Address(*sendArgs.To),
token.Address,
(*big.Int)(sendArgs.Value),
sendArgs.FromChainID,
uint64(time.Now().UnixMilli()),
maxSlippage,
)
}
if err != nil {
return tx, createBridgeCellerErrorResponse(err)
}
err = s.transactor.StoreAndTrackPendingTx(txOpts.From, sendArgs.FromTokenID, sendArgs.FromChainID, sendArgs.MultiTransactionID, tx)
if err != nil {
return tx, createBridgeCellerErrorResponse(err)
}
return tx, nil
}

func (s *CelerBridgeProcessor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (types.Hash, uint64, error) {
tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount), lastUsedNonce)
if err != nil {
Expand All @@ -377,6 +441,11 @@ func (s *CelerBridgeProcessor) BuildTransaction(sendArgs *MultipathProcessorTxAr
return tx, tx.Nonce(), err
}

func (s *CelerBridgeProcessor) BuildTransactionV2(sendArgs *transactions.SendTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) {
tx, err := s.sendOrBuildV2(sendArgs, nil, lastUsedNonce)
return tx, tx.Nonce(), err
}

func (s *CelerBridgeProcessor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) {
amt, err := s.estimateAmt(params.FromChain, params.ToChain, params.AmountIn, params.FromToken.Symbol)
if err != nil {
Expand Down
Loading

0 comments on commit 89425ce

Please sign in to comment.