Skip to content

Commit

Permalink
Merge branch 'main' into na/add-e2e-test
Browse files Browse the repository at this point in the history
  • Loading branch information
nadim-az authored Dec 18, 2024
2 parents 5fc418a + b604779 commit 1a73bec
Show file tree
Hide file tree
Showing 17 changed files with 225 additions and 120 deletions.
2 changes: 1 addition & 1 deletion cmd/solvercli/cmd/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ var relayCmd = &cobra.Command{
lmt.Logger(ctx).Error("Error creating hyperlane multi client from config", zap.Error(err))
}

destinationTxHash, destinationChainID, err := hyperlane.NewRelayer(hype, storageOverrideMap).Relay(ctx, originChainID, originTxHash, nil)
destinationTxHash, destinationChainID, _, err := hyperlane.NewRelayer(hype, storageOverrideMap).Relay(ctx, originChainID, originTxHash, nil)
if err != nil {
lmt.Logger(ctx).Error("Error relaying message", zap.Error(err))
return
Expand Down
62 changes: 32 additions & 30 deletions fundrebalancer/fundrebalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (r *FundRebalancer) MoveFundsToChain(
}
txn := txns[0]

approvalHash, err := r.ApproveTxn(ctx, rebalanceFromChainID, txn)
approvalHash, rawTx, err := r.ApproveTxn(ctx, rebalanceFromChainID, txn)
if err != nil {
return nil, nil, fmt.Errorf("approving rebalance txn from %s: %w", rebalanceFromChainID, err)
}
Expand All @@ -271,6 +271,7 @@ func (r *FundRebalancer) MoveFundsToChain(
approveTx := db.InsertSubmittedTxParams{
ChainID: rebalanceFromChainID,
TxHash: approvalHash,
RawTx: rawTx,
TxType: dbtypes.TxTypeERC20Approval,
TxStatus: dbtypes.TxStatusPending,
}
Expand Down Expand Up @@ -309,7 +310,7 @@ func (r *FundRebalancer) MoveFundsToChain(
}
}

rebalanceHash, err := r.SignAndSubmitTxn(ctx, txnWithMetadata)
rebalanceHash, rawTx, err := r.SignAndSubmitTxn(ctx, txnWithMetadata)
if err != nil {
return nil, nil, fmt.Errorf("signing and submitting transaction: %w", err)
}
Expand All @@ -332,6 +333,7 @@ func (r *FundRebalancer) MoveFundsToChain(
RebalanceTransferID: sql.NullInt64{Int64: rebalanceID, Valid: true},
ChainID: txnWithMetadata.sourceChainID,
TxHash: string(rebalanceHash),
RawTx: rawTx,
TxType: dbtypes.TxTypeFundRebalnance,
TxStatus: dbtypes.TxStatusPending,
}
Expand All @@ -357,21 +359,21 @@ func (r *FundRebalancer) ApproveTxn(
ctx context.Context,
chainID string,
txn skipgo.Tx,
) (string, error) {
) (txHash string, rawTx string, err error) {
needsApproal, err := r.NeedsERC20Approval(ctx, txn)
if err != nil {
return "", fmt.Errorf("checking if ERC20 approval is necessary for rebalance txn from %s: %w", chainID, err)
return "", "", fmt.Errorf("checking if ERC20 approval is necessary for rebalance txn from %s: %w", chainID, err)
}
if !needsApproal {
return "", nil
return "", "", nil
}

hash, err := r.ERC20Approval(ctx, txn)
hash, rawTx, err := r.ERC20Approval(ctx, txn)
if err != nil {
return "", fmt.Errorf("handling ERC20 approval for rebalance txn from %s: %w", chainID, err)
return "", "", fmt.Errorf("handling ERC20 approval for rebalance txn from %s: %w", chainID, err)
}

return hash, nil
return hash, rawTx, nil
}

// USDCToSpare returns a chains current balance - a chains target amount of
Expand Down Expand Up @@ -589,22 +591,22 @@ func (r *FundRebalancer) TxnWithMetadata(
func (r *FundRebalancer) SignAndSubmitTxn(
ctx context.Context,
txn SkipGoTxnWithMetadata,
) (skipgo.TxHash, error) {
) (txHash skipgo.TxHash, rawTx string, err error) {
// convert the Skip Go txHash into a signable data structure for
// each chain type
switch {
case txn.tx.EVMTx != nil:
signer, err := signing.NewSigner(ctx, txn.sourceChainID, r.chainIDToPrivateKey)
if err != nil {
return "", fmt.Errorf("creating signer for chain %s: %w", txn.sourceChainID, err)
return "", "", fmt.Errorf("creating signer for chain %s: %w", txn.sourceChainID, err)
}

txData, err := hex.DecodeString(txn.tx.EVMTx.Data)
if err != nil {
return "", fmt.Errorf("decoding hex data from Skip Go: %w", err)
return "", "", fmt.Errorf("decoding hex data from Skip Go: %w", err)
}

txHash, err := r.evmTxExecutor.ExecuteTx(
txHash, rawTxB64, err := r.evmTxExecutor.ExecuteTx(
ctx,
txn.sourceChainID,
txn.tx.EVMTx.SignerAddress,
Expand All @@ -614,7 +616,7 @@ func (r *FundRebalancer) SignAndSubmitTxn(
signer,
)
if err != nil {
return "", fmt.Errorf("submitting evm txn to chain %s: %w", txn.sourceChainID, err)
return "", "", fmt.Errorf("submitting evm txn to chain %s: %w", txn.sourceChainID, err)
}

lmt.Logger(ctx).Info(
Expand All @@ -624,11 +626,11 @@ func (r *FundRebalancer) SignAndSubmitTxn(
zap.String("txnHash", txHash),
)

return skipgo.TxHash(txHash), nil
return skipgo.TxHash(txHash), rawTxB64, nil
case txn.tx.CosmosTx != nil:
return "", fmt.Errorf("cosmos txns not supported yet")
return "", "", fmt.Errorf("cosmos txns not supported yet")
default:
return "", fmt.Errorf("no valid txHash types returned from Skip Go")
return "", "", fmt.Errorf("no valid txHash types returned from Skip Go")
}
}

Expand Down Expand Up @@ -688,60 +690,60 @@ func (r *FundRebalancer) NeedsERC20Approval(
return allowance.Cmp(necessaryApprovalAmount) < 0, nil
}

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

evmTx := txn.EVMTx
if len(evmTx.RequiredERC20Approvals) == 0 {
// if no approvals are required, return with no error
return "", nil
return "", "", nil
}
if len(evmTx.RequiredERC20Approvals) > 1 {
// only support single approval
return "", fmt.Errorf("expected 1 required erc20 approval but got %d", len(evmTx.RequiredERC20Approvals))
return "", "", fmt.Errorf("expected 1 required erc20 approval but got %d", len(evmTx.RequiredERC20Approvals))
}
approval := evmTx.RequiredERC20Approvals[0]

chainConfig, err := config.GetConfigReader(ctx).GetChainConfig(evmTx.ChainID)
if err != nil {
return "", fmt.Errorf("getting config for chain %s: %w", evmTx.ChainID, err)
return "", "", fmt.Errorf("getting config for chain %s: %w", evmTx.ChainID, err)
}
usdcDenom, err := config.GetConfigReader(ctx).GetUSDCDenom(evmTx.ChainID)
if err != nil {
return "", fmt.Errorf("fetching usdc denom on chain %s: %w", evmTx.ChainID, err)
return "", "", fmt.Errorf("fetching usdc denom on chain %s: %w", evmTx.ChainID, err)
}

// sanity check on the address being returned to be what the solver expects
if !strings.EqualFold(approval.TokenContract, usdcDenom) {
return "", fmt.Errorf("expected required approval for usdc token contract %s, but got %s", usdcDenom, approval.TokenContract)
return "", "", fmt.Errorf("expected required approval for usdc token contract %s, but got %s", usdcDenom, approval.TokenContract)
}

signer, err := signing.NewSigner(ctx, evmTx.ChainID, r.chainIDToPrivateKey)
if err != nil {
return "", fmt.Errorf("creating signer for chain %s: %w", evmTx.ChainID, err)
return "", "", fmt.Errorf("creating signer for chain %s: %w", evmTx.ChainID, err)
}

spender := common.HexToAddress(approval.Spender)

amount, ok := new(big.Int).SetString(approval.Amount, 10)
if !ok {
return "", fmt.Errorf("error converting erc20 approval amount %s on chain %s to *big.Int", approval.Amount, evmTx.ChainID)
return "", "", fmt.Errorf("error converting erc20 approval amount %s on chain %s to *big.Int", approval.Amount, evmTx.ChainID)
}

abi, err := usdc.UsdcMetaData.GetAbi()
if err != nil {
return "", fmt.Errorf("getting usdc contract abi: %w", err)
return "", "", fmt.Errorf("getting usdc contract abi: %w", err)
}

input, err := abi.Pack("approve", spender, amount)
if err != nil {
return "", fmt.Errorf("packing input to erc20 approval tx: %w", err)
return "", "", fmt.Errorf("packing input to erc20 approval tx: %w", err)
}

hash, err := r.evmTxExecutor.ExecuteTx(
hash, rawTxB64, err := r.evmTxExecutor.ExecuteTx(
ctx,
evmTx.ChainID,
chainConfig.SolverAddress,
Expand All @@ -751,10 +753,10 @@ func (r *FundRebalancer) ERC20Approval(ctx context.Context, txn skipgo.Tx) (stri
signer,
)
if err != nil {
return "", fmt.Errorf("executing erc20 approve for %s at contract %s for spender %s on %s: %w", amount.String(), approval.TokenContract, approval.Spender, evmTx.ChainID, err)
return "", "", fmt.Errorf("executing erc20 approve for %s at contract %s for spender %s on %s: %w", amount.String(), approval.TokenContract, approval.Spender, evmTx.ChainID, err)
}

return hash, nil
return hash, rawTxB64, nil
}

// isGasAcceptable checks if the gas cost for rebalancing transactions is
Expand Down
12 changes: 6 additions & 6 deletions fundrebalancer/fundrebalancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func TestFundRebalancer_Rebalance(t *testing.T) {
mockDatabse := mock_database.NewMockDatabase(t)

mockEVMTxExecutor := evm2.NewMockEVMTxExecutor(t)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", "", nil)

mockTxPriceOracle := mock_oracle.NewMockTxPriceOracle(t)
mockTxPriceOracle.On("TxFeeUUSDC", mockContext, mock.Anything, mock.Anything).Return(big.NewInt(75), nil)
Expand Down Expand Up @@ -358,8 +358,8 @@ func TestFundRebalancer_Rebalance(t *testing.T) {
mockEVMClientManager.EXPECT().GetClient(mockContext, arbitrumChainID).Return(mockEVMClient, nil)
mockEVMClientManager.EXPECT().GetClient(mockContext, ethChainID).Return(mockEVMClient, nil)
mockEVMTxExecutor := evm2.NewMockEVMTxExecutor(t)
mockEVMTxExecutor.On("ExecuteTx", mockContext, "42161", arbitrumAddress, []byte{}, "0", osmosisAddress, mock.Anything).Return("arbhash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, "1", ethAddress, []byte{}, "0", osmosisAddress, mock.Anything).Return("ethhash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, "42161", arbitrumAddress, []byte{}, "0", osmosisAddress, mock.Anything).Return("arbhash", "", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, "1", ethAddress, []byte{}, "0", osmosisAddress, mock.Anything).Return("ethhash", "", nil)
mockTxPriceOracle := mock_oracle.NewMockTxPriceOracle(t)

// using an in memory database for this test
Expand Down Expand Up @@ -668,10 +668,10 @@ func TestFundRebalancer_Rebalance(t *testing.T) {
mockDatabse := mock_database.NewMockDatabase(t)

mockEVMTxExecutor := evm2.NewMockEVMTxExecutor(t)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", "", nil)

// mock executing the approval tx
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, mock.Anything, "0", arbitrumUSDCDenom, mock.Anything).Return("arbitrum approval hash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, mock.Anything, "0", arbitrumUSDCDenom, mock.Anything).Return("arbitrum approval hash", "", nil)

mockDatabse.EXPECT().InsertSubmittedTx(mockContext, db.InsertSubmittedTxParams{
ChainID: arbitrumChainID,
Expand Down Expand Up @@ -806,7 +806,7 @@ func TestFundRebalancer_Rebalance(t *testing.T) {
mockDatabse := mock_database.NewMockDatabase(t)

mockEVMTxExecutor := evm2.NewMockEVMTxExecutor(t)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", nil)
mockEVMTxExecutor.On("ExecuteTx", mockContext, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("arbitrum hash", "", nil)

keystore, err := keys.LoadKeyStoreFromPlaintextFile(f.Name())
assert.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion fundrebalancer/transfermonitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestFundRebalancer_RebalanceWithAbandonedTransfer(t *testing.T) {
Return(txs, nil)

mockEVMClient.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(100), nil)
mockEVMTxExecutor.On("ExecuteTx", ctx, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("new_hash", nil)
mockEVMTxExecutor.On("ExecuteTx", ctx, arbitrumChainID, arbitrumAddress, []byte{}, "999", osmosisAddress, mock.Anything).Return("new_hash", "", nil)

// Rebalancer sees the pending transfer and doesn't create a new one
rebalancer.Rebalance(ctx)
Expand Down
6 changes: 3 additions & 3 deletions hyperlane/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Client interface {
ValidatorsAndThreshold(ctx context.Context, domain string, recipient string, message string) ([]common.Address, uint8, error)
ValidatorStorageLocations(ctx context.Context, domain string, validators []common.Address) ([]*types.ValidatorStorageLocation, error)
MerkleTreeLeafCount(ctx context.Context, domain string) (uint64, error)
Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, error)
Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, string, error)
IsContract(ctx context.Context, domain, address string) (bool, error)
GetHyperlaneDispatch(ctx context.Context, domain, originChainID, initiateTxHash string) (*types.MailboxDispatchEvent, *types.MailboxMerkleHookPostDispatchEvent, error)
QuoteProcessUUSDC(ctx context.Context, domain string, message []byte, metadata []byte) (*big.Int, error)
Expand Down Expand Up @@ -117,10 +117,10 @@ func (c *MultiClient) MerkleTreeLeafCount(ctx context.Context, domain string) (u
return client.MerkleTreeLeafCount(ctx, domain)
}

func (c *MultiClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, error) {
func (c *MultiClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, string, error) {
client, ok := c.clients[domain]
if !ok {
return nil, fmt.Errorf("no configured client for domain %s", domain)
return nil, "", fmt.Errorf("no configured client for domain %s", domain)
}
return client.Process(ctx, domain, message, metadata)
}
Expand Down
2 changes: 1 addition & 1 deletion hyperlane/cosmos/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func (c *HyperlaneClient) MerkleTreeLeafCount(ctx context.Context, domain string
return NewMerkleTreeHookQuerier(c.merkleHookAddress, c.client).Count(ctx)
}

func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, error) {
func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, string, error) {
panic("not implemented")
}

Expand Down
22 changes: 11 additions & 11 deletions hyperlane/ethereum/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,29 +210,29 @@ func (c *HyperlaneClient) getISMAddress(ctx context.Context, recipient string) (
return ismAddress, nil
}

func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, error) {
func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []byte, metadata []byte) ([]byte, string, error) {
destinationMailbox, err := mailbox.NewMailbox(c.mailboxAddress, c.client.Client())
if err != nil {
return nil, fmt.Errorf("creating mailbox contract caller for address %s: %w", c.mailboxAddress.String(), err)
return nil, "", fmt.Errorf("creating mailbox contract caller for address %s: %w", c.mailboxAddress.String(), err)
}

destinationChainID, err := config.GetConfigReader(ctx).GetChainIDByHyperlaneDomain(domain)
if err != nil {
return nil, fmt.Errorf("getting chainID for hyperlane domain %s: %w", domain, err)
return nil, "", fmt.Errorf("getting chainID for hyperlane domain %s: %w", domain, err)
}
destinationChainConfig, err := config.GetConfigReader(ctx).GetChainConfig(destinationChainID)
if err != nil {
return nil, fmt.Errorf("getting destination chain %s config: %w", destinationChainID, err)
return nil, "", fmt.Errorf("getting destination chain %s config: %w", destinationChainID, err)
}

signer, err := c.signer(ctx, domain)
if err != nil {
return nil, fmt.Errorf("getting signer: %w", err)
return nil, "", fmt.Errorf("getting signer: %w", err)
}

addr, err := c.address(ctx, domain)
if err != nil {
return nil, fmt.Errorf("getting address: %w", err)
return nil, "", fmt.Errorf("getting address: %w", err)
}

tx, err := destinationMailbox.Process(&bind.TransactOpts{
Expand All @@ -245,10 +245,10 @@ func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []
NoSend: true, // generate the transaction without sending
}, metadata, message)
if err != nil {
return nil, fmt.Errorf("creating process transaction: %w", err)
return nil, "", fmt.Errorf("creating process transaction: %w", err)
}

txHash, err := c.txExecutor.ExecuteTx(
txHash, rawTx, err := c.txExecutor.ExecuteTx(
ctx,
destinationChainID,
destinationChainConfig.SolverAddress,
Expand All @@ -258,15 +258,15 @@ func (c *HyperlaneClient) Process(ctx context.Context, domain string, message []
signer,
)
if err != nil {
return nil, fmt.Errorf("processing message on destination mailbox: %w", err)
return nil, "", fmt.Errorf("processing message on destination mailbox: %w", err)
}

txHashBytes, err := hex.DecodeString(strings.TrimPrefix(txHash, "0x"))
if err != nil {
return nil, fmt.Errorf("decoding process tx hash %s: %w", txHash, err)
return nil, "", fmt.Errorf("decoding process tx hash %s: %w", txHash, err)
}

return txHashBytes, nil
return txHashBytes, rawTx, nil
}

func (c *HyperlaneClient) QuoteProcessUUSDC(ctx context.Context, domain string, message []byte, metadata []byte) (*big.Int, error) {
Expand Down
Loading

0 comments on commit 1a73bec

Please sign in to comment.