Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API-3583] Track tx costs #57

Merged
merged 23 commits into from
Dec 6, 2024
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a836022
change tx price oracle to be slightly more chain agnostic, pull confi…
mattac21 Nov 19, 2024
526f1ca
add tx cost to submitted txs table and update queries
mattac21 Nov 19, 2024
d000b5f
move evmrpc tx price oracle to chain agnostic oracle package and allo…
mattac21 Nov 19, 2024
c7cabfe
parse fee out of tx result to use as gas cost
mattac21 Nov 19, 2024
fb3d9e5
rename evm tx price oracle -> price oracle
mattac21 Nov 19, 2024
61c4a6c
update interface for calling tx price oracle from hyperlane client
mattac21 Nov 19, 2024
94bb59e
get gas cost in uusdc when verifying a submitted tx
mattac21 Nov 19, 2024
8133aaa
add rebalance_transfer_id column to submitted txs table
mattac21 Nov 20, 2024
1920828
insert fund rebalancer txs into submitted txs table
mattac21 Nov 20, 2024
51c66f4
erc20 approval before gas cost estimation
mattac21 Nov 20, 2024
84b3d8e
Merge branch 'main' into ma/track-profit-in-db
mattac21 Nov 28, 2024
6cd7b23
move evm tx price oracle to generic oracle package to not be evm spec…
mattac21 Dec 2, 2024
44a9465
add db queries to support fund rebalancer to add txns to submitted tx…
mattac21 Dec 2, 2024
8b0cb8c
fund rebalancer adds txs to submitted txs table
mattac21 Dec 2, 2024
4d4f52f
add test for fund rebalancer adding txns to submitted txns table
mattac21 Dec 2, 2024
bee959e
Merge branch 'main' into ma/track-profit-in-db
mattac21 Dec 2, 2024
c666e81
fix imports
mattac21 Dec 2, 2024
10825ff
dont link erc20 approval txs to rebalance txs in fund rebalancer
mattac21 Dec 5, 2024
aa84081
change fee parsing to decode tx auth info bytes and return gas denom fee
mattac21 Dec 5, 2024
a77316f
return an error if fee for gas denom is not found in cosmos tx result
mattac21 Dec 5, 2024
14099d3
Merge branch 'main' into ma/track-profit-in-db
mattac21 Dec 5, 2024
b4f08e5
fix db migration naming and make rebalance_transfer_id a foreign key
mattac21 Dec 6, 2024
5408834
pass chainid to tx price oracle
mattac21 Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 65 additions & 60 deletions fundrebalancer/fundrebalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,23 @@ func (r *FundRebalancer) MoveFundsToChain(
}
txn := txns[0]

approvalHash, err := r.ERC20Approval(ctx, txn)
mattac21 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, nil, fmt.Errorf("approving usdc erc20 spend on chain %s for %suusdc: %w", rebalanceFromChainID, usdcToRebalance.String(), err)
}

txnWithMetadata, err := r.TxnWithMetadata(ctx, rebalanceFromChainID, rebalanceFromChainID, usdcToRebalance, txn)
if err != nil {
return nil, nil, fmt.Errorf("getting transaction metadata: %w", err)
}

chainConfig, err := config.GetConfigReader(ctx).GetChainConfig(rebalanceFromChainID)
if err != nil {
return nil, nil, fmt.Errorf("getting chain config for gas threshold check: %w", err)
}

if chainConfig.MaxRebalancingGasThreshold != 0 {
mattac21 marked this conversation as resolved.
Show resolved Hide resolved
gasAcceptable, totalRebalancingGas, err := r.isGasAcceptable(txns, chainConfig.MaxRebalancingGasThreshold)
gasAcceptable, totalRebalancingGas, err := r.isGasAcceptable(txn, chainConfig.MaxRebalancingGasThreshold)
if err != nil {
return nil, nil, fmt.Errorf("checking if gas amount is acceptable: %w", err)
}
Expand All @@ -285,11 +295,6 @@ func (r *FundRebalancer) MoveFundsToChain(
}
}

approvalHash, err := r.ERC20Approval(ctx, txn)
if err != nil {
return nil, nil, fmt.Errorf("approving usdc erc20 spend on chain %s for %suusdc: %w", rebalanceFromChainID, usdcToRebalance.String(), err)
}

rebalanceHash, err := r.SignAndSubmitTxn(ctx, txn)
if err != nil {
return nil, nil, fmt.Errorf("signing and submitting transaction: %w", err)
Expand Down Expand Up @@ -444,7 +449,7 @@ func (r *FundRebalancer) GetRebalanceTxns(
amount *big.Int,
sourceChainID string,
destChainID string,
) ([]SkipGoTxnWithMetadata, error) {
) ([]skipgo.Tx, error) {
rebalanceFromDenom, err := config.GetConfigReader(ctx).GetUSDCDenom(sourceChainID)
if err != nil {
return nil, fmt.Errorf("getting usdc denom for chain %s: %w", sourceChainID, err)
Expand Down Expand Up @@ -513,43 +518,55 @@ func (r *FundRebalancer) GetRebalanceTxns(
return nil, fmt.Errorf("getting rebalancing txn operations from Skip Go: %w", err)
}

txnsWithMetadata := make([]SkipGoTxnWithMetadata, 0, len(txns))
for _, txn := range txns {
var gasEstimate uint64
if txn.EVMTx != nil {
client, err := r.evmClientManager.GetClient(ctx, txn.EVMTx.ChainID)
if err != nil {
return nil, fmt.Errorf("getting evm client for chain %s: %w", txn.EVMTx.ChainID, err)
}
return txns, nil
}

decodedData, err := hex.DecodeString(txn.EVMTx.Data)
if err != nil {
return nil, fmt.Errorf("hex decoding evm call data: %w", err)
}
func (r *FundRebalancer) TxnWithMetadata(
ctx context.Context,
sourceChainID string,
destinationChainID string,
amount *big.Int,
txn skipgo.Tx,
) (SkipGoTxnWithMetadata, error) {
sourceChainConfig, err := config.GetConfigReader(ctx).GetChainConfig(sourceChainID)
if err != nil {
return SkipGoTxnWithMetadata{}, fmt.Errorf("getting source chain config for chain %s: %w", sourceChainID, err)
}

txBuilder := evm.NewTxBuilder(client)
estimate, err := txBuilder.EstimateGasForTx(
ctx,
sourceChainConfig.SolverAddress,
txn.EVMTx.To,
txn.EVMTx.Value,
decodedData,
)
if err != nil {
return nil, fmt.Errorf("estimating gas: %w", err)
}
gasEstimate = estimate
}
txnsWithMetadata = append(txnsWithMetadata, SkipGoTxnWithMetadata{
tx: txn,
sourceChainID: sourceChainID,
destinationChainID: destChainID,
amount: amount,
gasEstimate: gasEstimate,
})
var gasEstimate uint64
if txn.EVMTx == nil {
return SkipGoTxnWithMetadata{}, fmt.Errorf("evm tx cannot be nil")
}
client, err := r.evmClientManager.GetClient(ctx, txn.EVMTx.ChainID)
if err != nil {
return SkipGoTxnWithMetadata{}, fmt.Errorf("getting evm client for chain %s: %w", txn.EVMTx.ChainID, err)
}

decodedData, err := hex.DecodeString(txn.EVMTx.Data)
if err != nil {
return SkipGoTxnWithMetadata{}, fmt.Errorf("hex decoding evm call data: %w", err)
}

return txnsWithMetadata, nil
txBuilder := evm.NewTxBuilder(client)
estimate, err := txBuilder.EstimateGasForTx(
ctx,
sourceChainConfig.SolverAddress,
txn.EVMTx.To,
txn.EVMTx.Value,
decodedData,
)
if err != nil {
return SkipGoTxnWithMetadata{}, fmt.Errorf("estimating gas: %w", err)
}
gasEstimate = estimate

return SkipGoTxnWithMetadata{
tx: txn,
sourceChainID: sourceChainID,
destinationChainID: destinationChainID,
amount: amount,
gasEstimate: gasEstimate,
}, nil
}

// SignAndSubmitTxn signs and submits txs to chain
Expand Down Expand Up @@ -599,12 +616,13 @@ func (r *FundRebalancer) SignAndSubmitTxn(
}
}

func (r *FundRebalancer) ERC20Approval(ctx context.Context, txn SkipGoTxnWithMetadata) (string, error) {
if txn.tx.EVMTx == nil {
func (r *FundRebalancer) ERC20Approval(ctx context.Context, tx skipgo.Tx) (string, error) {
if tx.EVMTx == nil {
// if this isnt an evm tx, no erc20 approvals are required
return "", nil
}
evmTx := txn.tx.EVMTx

evmTx := tx.EVMTx
if len(evmTx.RequiredERC20Approvals) == 0 {
// if no approvals are required, return with no error
return "", nil
Expand Down Expand Up @@ -667,24 +685,11 @@ func (r *FundRebalancer) ERC20Approval(ctx context.Context, txn SkipGoTxnWithMet
return hash, nil
}

func (r *FundRebalancer) estimateTotalGas(txns []SkipGoTxnWithMetadata) (uint64, error) {
var totalGas uint64
for _, txn := range txns {
totalGas += txn.gasEstimate
}
return totalGas, nil
}

func (r *FundRebalancer) isGasAcceptable(txns []SkipGoTxnWithMetadata, maxRebalancingGasThreshold uint64) (bool, uint64, error) {
func (r *FundRebalancer) isGasAcceptable(txn SkipGoTxnWithMetadata, maxRebalancingGasThreshold uint64) (bool, uint64, error) {
// Check if total gas needed exceeds threshold to rebalance funds from this chain
totalRebalancingGas, err := r.estimateTotalGas(txns)
if err != nil {
return false, 0, fmt.Errorf("estimating total gas for transactions: %w", err)
}

if totalRebalancingGas > maxRebalancingGasThreshold {
return false, totalRebalancingGas, nil
if txn.gasEstimate > maxRebalancingGasThreshold {
return false, txn.gasEstimate, nil
}

return true, totalRebalancingGas, nil
return true, txn.gasEstimate, nil
}