From 3a72098f2a7256a65bfc86740b01a6b5c339a4c3 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 10:53:41 -0400 Subject: [PATCH 01/19] Feat: add MinBalance to token config --- services/rfq/relayer/relconfig/config.go | 2 ++ services/rfq/relayer/relconfig/getters.go | 35 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/services/rfq/relayer/relconfig/config.go b/services/rfq/relayer/relconfig/config.go index 5d69fbd38f..ed935c680a 100644 --- a/services/rfq/relayer/relconfig/config.go +++ b/services/rfq/relayer/relconfig/config.go @@ -128,6 +128,8 @@ type TokenConfig struct { // Note that this value can be positive or negative; if positive it effectively increases the quoted price // of the given token, and vice versa. QuoteOffsetBps float64 `yaml:"quote_offset_bps"` + // MinBalance is the minimum balance that should be leftover from quoting, in human-readable units. + MinBalance string `yaml:"min_balance"` } // DatabaseConfig represents the configuration for the database. diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index 3bca0f98ce..73960f2231 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -298,6 +298,41 @@ func (c Config) GetQuoteOffsetBps(chainID int, tokenName string, isOrigin bool) return offset, nil } +const defaultMinBalance = 0 + +// GetMinBalance returns the MinBalance for the given chain and address. +// Note that this getter returns the value in native token decimals. +func (c Config) GetMinBalance(chainID int, addr common.Address) *big.Int { + chainCfg, ok := c.Chains[chainID] + if !ok { + return big.NewInt(defaultMinBalance) + } + + var tokenCfg *TokenConfig + for _, cfg := range chainCfg.Tokens { + if common.HexToAddress(cfg.Address).Hex() == addr.Hex() { + cfgCopy := cfg + tokenCfg = &cfgCopy + break + } + } + if tokenCfg == nil { + return big.NewInt(defaultMinBalance) + } + quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MinBalance) + if !ok { + return big.NewInt(defaultMinBalance) + } + if quoteAmountFlt.Cmp(big.NewFloat(0)) <= 0 { + return big.NewInt(defaultMinBalance) + } + + // Scale the minBalance by the token decimals. + denomDecimalsFactor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenCfg.Decimals)), nil) + quoteAmountScaled, _ := new(big.Float).Mul(quoteAmountFlt, new(big.Float).SetInt(denomDecimalsFactor)).Int(nil) + return quoteAmountScaled +} + // GetQuoteWidthBps returns the QuoteWidthBps for the given chainID. func (c Config) GetQuoteWidthBps(chainID int) (value float64, err error) { rawValue, err := c.getChainConfigValue(chainID, "QuoteWidthBps") From c0b19559009b755b7e95b54fc5c1c6a0e6659eb8 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 11:04:50 -0400 Subject: [PATCH 02/19] Feat: add min balance logic --- services/rfq/relayer/quoter/quoter.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index a9d6c32ffe..d51127177b 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -519,13 +519,17 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a quoteAmount = minQuoteAmount } - // Finally, clip the quoteAmount by the balance - if quoteAmount.Cmp(balance) > 0 { - span.AddEvent("quote amount greater than balance", trace.WithAttributes( + // Finally, clip the quoteAmount by the minimum balance + minBalance := m.config.GetMinBalance(dest, address) + quotableBalance := new(big.Int).Sub(balance, minBalance) + if quoteAmount.Cmp(quotableBalance) > 0 { + span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), attribute.String("balance", balance.String()), + attribute.String("quotable_balance", quotableBalance.String()), + attribute.String("min_balance", minBalance.String()), )) - quoteAmount = balance + quoteAmount = quotableBalance } // Deduct gas cost from the quote amount, if necessary From d4f7f51e74130d9bf8ef2690501c07233e5d3583 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 11:07:40 -0400 Subject: [PATCH 03/19] Feat: test min balance --- services/rfq/relayer/quoter/quoter_test.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 507b981e0d..438eaf2868 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -164,10 +164,11 @@ func (s *QuoterSuite) TestGetOriginAmount() { address := common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85") balance := big.NewInt(1000_000_000) // 1000 USDC - setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount string) { + setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount string, minBalance string) { s.config.BaseChainConfig.QuotePct = quotePct destTokenCfg := s.config.Chains[dest].Tokens["USDC"] destTokenCfg.MinQuoteAmount = minQuoteAmount + destTokenCfg.MinBalance = minBalance originTokenCfg := s.config.Chains[origin].Tokens["USDC"] originTokenCfg.QuoteOffsetBps = quoteOffset s.config.Chains[dest].Tokens["USDC"] = destTokenCfg @@ -182,40 +183,47 @@ func (s *QuoterSuite) TestGetOriginAmount() { s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. - setQuoteParams(50, 0, "0") + setQuoteParams(50, 0, "0", "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. - setQuoteParams(50, -100, "0") + setQuoteParams(50, -100, "0", "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500") + setQuoteParams(25, 0, "500", "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500") + setQuoteParams(25, 0, "500", "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. - setQuoteParams(25, 0, "1500") + setQuoteParams(25, 0, "1500", "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) + // Set QuotePct to 25 with MinQuoteAmount of 1500 and MinBalance of 200; should be total balance minus 500. + setQuoteParams(25, 0, "1500", "200") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + s.NoError(err) + expectedAmount = big.NewInt(800_000_000) + s.Equal(expectedAmount, quoteAmount) + // Toggle insufficient gas; should be 0. s.setGasSufficiency(false) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) From 18da8822f91a83d7e355b5afa14ef8154a6bd7f6 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 11:07:42 -0400 Subject: [PATCH 04/19] [goreleaser] From 96bdb548cb2c1bbfad1dbce8501137fe81643405 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 11:12:36 -0400 Subject: [PATCH 05/19] Cleanup: comment --- services/rfq/relayer/quoter/quoter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 438eaf2868..a023965d22 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -217,7 +217,7 @@ func (s *QuoterSuite) TestGetOriginAmount() { expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) - // Set QuotePct to 25 with MinQuoteAmount of 1500 and MinBalance of 200; should be total balance minus 500. + // Set QuotePct to 25 with MinQuoteAmount of 1500 and MinBalance of 200; should be total balance minus 200. setQuoteParams(25, 0, "1500", "200") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) From 605880b4fd1f1cd4d5dc6667c72284e28173f8ef Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 12:21:16 -0400 Subject: [PATCH 06/19] Feat: MinBalance -> MaxBalance --- services/rfq/relayer/relconfig/config.go | 4 ++-- services/rfq/relayer/relconfig/getters.go | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/services/rfq/relayer/relconfig/config.go b/services/rfq/relayer/relconfig/config.go index ed935c680a..e236090872 100644 --- a/services/rfq/relayer/relconfig/config.go +++ b/services/rfq/relayer/relconfig/config.go @@ -128,8 +128,8 @@ type TokenConfig struct { // Note that this value can be positive or negative; if positive it effectively increases the quoted price // of the given token, and vice versa. QuoteOffsetBps float64 `yaml:"quote_offset_bps"` - // MinBalance is the minimum balance that should be leftover from quoting, in human-readable units. - MinBalance string `yaml:"min_balance"` + // MaxBalance is the maximum balance that should be accumulated for this token on this chain (human-readable units) + MaxBalance string `yaml:"max_balance"` } // DatabaseConfig represents the configuration for the database. diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index 73960f2231..da9c72ede9 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -298,14 +298,14 @@ func (c Config) GetQuoteOffsetBps(chainID int, tokenName string, isOrigin bool) return offset, nil } -const defaultMinBalance = 0 +const defaultMaxBalance = 0 -// GetMinBalance returns the MinBalance for the given chain and address. +// GetMaxBalance returns the MaxBalance for the given chain and address. // Note that this getter returns the value in native token decimals. -func (c Config) GetMinBalance(chainID int, addr common.Address) *big.Int { +func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { chainCfg, ok := c.Chains[chainID] if !ok { - return big.NewInt(defaultMinBalance) + return big.NewInt(defaultMaxBalance) } var tokenCfg *TokenConfig @@ -317,14 +317,14 @@ func (c Config) GetMinBalance(chainID int, addr common.Address) *big.Int { } } if tokenCfg == nil { - return big.NewInt(defaultMinBalance) + return big.NewInt(defaultMaxBalance) } - quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MinBalance) + quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MaxBalance) if !ok { - return big.NewInt(defaultMinBalance) + return big.NewInt(defaultMaxBalance) } if quoteAmountFlt.Cmp(big.NewFloat(0)) <= 0 { - return big.NewInt(defaultMinBalance) + return big.NewInt(defaultMaxBalance) } // Scale the minBalance by the token decimals. From 9b87ac9f79a891f88683374c7f3b8a0339cfb651 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 12:50:42 -0400 Subject: [PATCH 07/19] Feat: structure quote input --- services/rfq/relayer/quoter/export_test.go | 4 +- services/rfq/relayer/quoter/quoter.go | 84 ++++++++++++++-------- services/rfq/relayer/quoter/quoter_test.go | 30 ++++---- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/services/rfq/relayer/quoter/export_test.go b/services/rfq/relayer/quoter/export_test.go index af7338a0ea..db90b4aeb2 100644 --- a/services/rfq/relayer/quoter/export_test.go +++ b/services/rfq/relayer/quoter/export_test.go @@ -9,9 +9,9 @@ import ( "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" ) -func (m *Manager) GenerateQuotes(ctx context.Context, chainID int, address common.Address, balance *big.Int) ([]model.PutQuoteRequest, error) { +func (m *Manager) GenerateQuotes(ctx context.Context, chainID int, address common.Address, balance *big.Int, inv map[int]map[common.Address]*big.Int) ([]model.PutQuoteRequest, error) { // nolint: errcheck - return m.generateQuotes(ctx, chainID, address, balance) + return m.generateQuotes(ctx, chainID, address, balance, inv) } func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, address common.Address, balance *big.Int) (*big.Int, error) { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index d51127177b..44451756cc 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -260,7 +260,7 @@ func (m *Manager) prepareAndSubmitQuotes(ctx context.Context, inv map[int]map[co // First, generate all quotes for chainID, balances := range inv { for address, balance := range balances { - quotes, err := m.generateQuotes(ctx, chainID, address, balance) + quotes, err := m.generateQuotes(ctx, chainID, address, balance, inv) if err != nil { return err } @@ -311,7 +311,7 @@ const meterName = "github.com/synapsecns/sanguine/services/rfq/relayer/quoter" // Essentially, if we know a destination chain token balance, then we just need to find which tokens are bridgeable to it. // We can do this by looking at the quotableTokens map, and finding the key that matches the destination chain token. // Generates quotes for a given chain ID, address, and balance. -func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address common.Address, balance *big.Int) (quotes []model.PutQuoteRequest, err error) { +func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address common.Address, balance *big.Int, inv map[int]map[common.Address]*big.Int) (quotes []model.PutQuoteRequest, err error) { ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "generateQuotes", trace.WithAttributes( attribute.Int(metrics.Origin, chainID), attribute.String("address", address.String()), @@ -335,9 +335,36 @@ func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address for _, tokenID := range itemTokenIDs { //nolint:nestif if tokenID == destTokenID { - keyTokenID := k + keyTokenID := k // Parse token info g.Go(func() error { - quote, quoteErr := m.generateQuote(gctx, keyTokenID, chainID, address, balance, destRFQAddr) + originStr := strings.Split(keyTokenID, "-")[0] + origin, tokenErr := strconv.Atoi(originStr) + if err != nil { + span.AddEvent("error converting origin chainID", trace.WithAttributes( + attribute.String("key_token_id", keyTokenID), + attribute.String("error", tokenErr.Error()), + )) + return nil + } + originTokenAddr := common.HexToAddress(strings.Split(keyTokenID, "-")[1]) + + var originBalance *big.Int + originTokens, ok := inv[origin] + if ok { + originBalance = originTokens[originTokenAddr] + } + + input := quoteInput{ + originChainID: origin, + destChainID: chainID, + originTokenAddr: originTokenAddr, + destTokenAddr: address, + originBalance: originBalance, + destBalance: balance, + destRFQAddr: destRFQAddr, + } + + quote, quoteErr := m.generateQuote(gctx, input) if quoteErr != nil { // continue generating quotes even if one fails span.AddEvent("error generating quote", trace.WithAttributes( @@ -363,18 +390,19 @@ func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address return quotes, nil } -func (m *Manager) generateQuote(ctx context.Context, keyTokenID string, chainID int, address common.Address, balance *big.Int, destRFQAddr string) (quote *model.PutQuoteRequest, err error) { - // Parse token info - originStr := strings.Split(keyTokenID, "-")[0] - origin, err := strconv.Atoi(originStr) - if err != nil { - logger.Error("Error converting origin chainID", "error", err) - return nil, fmt.Errorf("error converting origin chainID: %w", err) - } - originTokenAddr := common.HexToAddress(strings.Split(keyTokenID, "-")[1]) +type quoteInput struct { + originChainID int + destChainID int + originTokenAddr common.Address + destTokenAddr common.Address + originBalance *big.Int + destBalance *big.Int + destRFQAddr string +} +func (m *Manager) generateQuote(ctx context.Context, input quoteInput) (quote *model.PutQuoteRequest, err error) { // Calculate the quote amount for this route - originAmount, err := m.getOriginAmount(ctx, origin, chainID, address, balance) + originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.destTokenAddr, input.destBalance) // don't quote if gas exceeds quote if errors.Is(err, errMinGasExceedsQuoteAmount) { originAmount = big.NewInt(0) @@ -384,38 +412,38 @@ func (m *Manager) generateQuote(ctx context.Context, keyTokenID string, chainID } // Calculate the fee for this route - destToken, err := m.config.GetTokenName(uint32(chainID), address.Hex()) + destToken, err := m.config.GetTokenName(uint32(input.destChainID), input.destTokenAddr.Hex()) if err != nil { logger.Error("Error getting dest token ID", "error", err) return nil, fmt.Errorf("error getting dest token ID: %w", err) } - fee, err := m.feePricer.GetTotalFee(ctx, uint32(origin), uint32(chainID), destToken, true) + fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.originChainID), uint32(input.destChainID), destToken, true) if err != nil { logger.Error("Error getting total fee", "error", err) return nil, fmt.Errorf("error getting total fee: %w", err) } - originRFQAddr, err := m.config.GetRFQAddress(origin) + originRFQAddr, err := m.config.GetRFQAddress(input.originChainID) if err != nil { logger.Error("Error getting RFQ address", "error", err) return nil, fmt.Errorf("error getting RFQ address: %w", err) } // Build the quote - destAmount, err := m.getDestAmount(ctx, originAmount, chainID, destToken) + destAmount, err := m.getDestAmount(ctx, originAmount, input.destChainID, destToken) if err != nil { logger.Error("Error getting dest amount", "error", err) return nil, fmt.Errorf("error getting dest amount: %w", err) } quote = &model.PutQuoteRequest{ - OriginChainID: origin, - OriginTokenAddr: originTokenAddr.Hex(), - DestChainID: chainID, - DestTokenAddr: address.Hex(), + OriginChainID: input.originChainID, + OriginTokenAddr: input.originTokenAddr.Hex(), + DestChainID: input.destChainID, + DestTokenAddr: input.destTokenAddr.Hex(), DestAmount: destAmount.String(), MaxOriginAmount: originAmount.String(), FixedFee: fee.String(), OriginFastBridgeAddress: originRFQAddr, - DestFastBridgeAddress: destRFQAddr, + DestFastBridgeAddress: input.destRFQAddr, } return quote, nil } @@ -519,17 +547,13 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a quoteAmount = minQuoteAmount } - // Finally, clip the quoteAmount by the minimum balance - minBalance := m.config.GetMinBalance(dest, address) - quotableBalance := new(big.Int).Sub(balance, minBalance) - if quoteAmount.Cmp(quotableBalance) > 0 { + // Finally, clip the quoteAmount by the balance + if quoteAmount.Cmp(balance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), attribute.String("balance", balance.String()), - attribute.String("quotable_balance", quotableBalance.String()), - attribute.String("min_balance", minBalance.String()), )) - quoteAmount = quotableBalance + quoteAmount = balance } // Deduct gas cost from the quote amount, if necessary diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index a023965d22..91f264216d 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -22,7 +22,8 @@ import ( func (s *QuoterSuite) TestGenerateQuotes() { // Generate quotes for USDC on the destination chain. balance := big.NewInt(1000_000_000) // 1000 USDC - quotes, err := s.manager.GenerateQuotes(s.GetTestContext(), int(s.destination), common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85"), balance) + inv := map[int]map[common.Address]*big.Int{} + quotes, err := s.manager.GenerateQuotes(s.GetTestContext(), int(s.destination), common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85"), balance, inv) s.Require().NoError(err) // Verify the quotes are generated as expected. @@ -43,7 +44,8 @@ func (s *QuoterSuite) TestGenerateQuotes() { func (s *QuoterSuite) TestGenerateQuotesForNativeToken() { // Generate quotes for ETH on the destination chain. balance, _ := new(big.Int).SetString("1000000000000000000", 10) // 1 ETH - quotes, err := s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance) + inv := map[int]map[common.Address]*big.Int{} + quotes, err := s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance, inv) s.Require().NoError(err) minGasToken, err := s.config.GetMinGasToken(int(s.destination)) @@ -68,7 +70,7 @@ func (s *QuoterSuite) TestGenerateQuotesForNativeToken() { s.config.BaseChainConfig.MinGasToken = "100000000000000000" // 0.1 ETH s.manager.SetConfig(s.config) - quotes, err = s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance) + quotes, err = s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance, inv) s.Require().NoError(err) minGasToken, err = s.config.GetMinGasToken(int(s.destination)) @@ -93,7 +95,7 @@ func (s *QuoterSuite) TestGenerateQuotesForNativeToken() { s.config.BaseChainConfig.MinGasToken = "1000000000000000001" // 0.1 ETH s.manager.SetConfig(s.config) - quotes, err = s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance) + quotes, err = s.manager.GenerateQuotes(s.GetTestContext(), int(s.destinationEth), chain.EthAddress, balance, inv) s.NoError(err) s.Equal(quotes[0].DestAmount, "0") s.Equal(quotes[0].MaxOriginAmount, "0") @@ -164,11 +166,10 @@ func (s *QuoterSuite) TestGetOriginAmount() { address := common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85") balance := big.NewInt(1000_000_000) // 1000 USDC - setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount string, minBalance string) { + setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount string) { s.config.BaseChainConfig.QuotePct = quotePct destTokenCfg := s.config.Chains[dest].Tokens["USDC"] destTokenCfg.MinQuoteAmount = minQuoteAmount - destTokenCfg.MinBalance = minBalance originTokenCfg := s.config.Chains[origin].Tokens["USDC"] originTokenCfg.QuoteOffsetBps = quoteOffset s.config.Chains[dest].Tokens["USDC"] = destTokenCfg @@ -183,47 +184,40 @@ func (s *QuoterSuite) TestGetOriginAmount() { s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. - setQuoteParams(50, 0, "0", "0") + setQuoteParams(50, 0, "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. - setQuoteParams(50, -100, "0", "0") + setQuoteParams(50, -100, "0") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500", "0") + setQuoteParams(25, 0, "500") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500", "0") + setQuoteParams(25, 0, "500") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. - setQuoteParams(25, 0, "1500", "0") + setQuoteParams(25, 0, "1500") quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) - // Set QuotePct to 25 with MinQuoteAmount of 1500 and MinBalance of 200; should be total balance minus 200. - setQuoteParams(25, 0, "1500", "200") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) - s.NoError(err) - expectedAmount = big.NewInt(800_000_000) - s.Equal(expectedAmount, quoteAmount) - // Toggle insufficient gas; should be 0. s.setGasSufficiency(false) quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) From 3d05c17bd893e6a6882ecd41d15e7cf63fca0c63 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 12:51:33 -0400 Subject: [PATCH 08/19] Feat: move quote outside goroutine for thread safety --- services/rfq/relayer/quoter/quoter.go | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 44451756cc..baa65ad0ef 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -336,24 +336,24 @@ func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address //nolint:nestif if tokenID == destTokenID { keyTokenID := k // Parse token info - g.Go(func() error { - originStr := strings.Split(keyTokenID, "-")[0] - origin, tokenErr := strconv.Atoi(originStr) - if err != nil { - span.AddEvent("error converting origin chainID", trace.WithAttributes( - attribute.String("key_token_id", keyTokenID), - attribute.String("error", tokenErr.Error()), - )) - return nil - } - originTokenAddr := common.HexToAddress(strings.Split(keyTokenID, "-")[1]) - - var originBalance *big.Int - originTokens, ok := inv[origin] - if ok { - originBalance = originTokens[originTokenAddr] - } + originStr := strings.Split(keyTokenID, "-")[0] + origin, tokenErr := strconv.Atoi(originStr) + if err != nil { + span.AddEvent("error converting origin chainID", trace.WithAttributes( + attribute.String("key_token_id", keyTokenID), + attribute.String("error", tokenErr.Error()), + )) + continue + } + originTokenAddr := common.HexToAddress(strings.Split(keyTokenID, "-")[1]) + + var originBalance *big.Int + originTokens, ok := inv[origin] + if ok { + originBalance = originTokens[originTokenAddr] + } + g.Go(func() error { input := quoteInput{ originChainID: origin, destChainID: chainID, From 6d9b986cc12bc8653955ea9dbac760eeeca936ae Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 12:57:27 -0400 Subject: [PATCH 09/19] Feat: getOriginAmount() takes origin balance --- services/rfq/relayer/quoter/export_test.go | 4 ++-- services/rfq/relayer/quoter/quoter.go | 15 ++++++++------- services/rfq/relayer/quoter/quoter_test.go | 14 +++++++------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/services/rfq/relayer/quoter/export_test.go b/services/rfq/relayer/quoter/export_test.go index db90b4aeb2..293bdb192d 100644 --- a/services/rfq/relayer/quoter/export_test.go +++ b/services/rfq/relayer/quoter/export_test.go @@ -14,8 +14,8 @@ func (m *Manager) GenerateQuotes(ctx context.Context, chainID int, address commo return m.generateQuotes(ctx, chainID, address, balance, inv) } -func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, address common.Address, balance *big.Int) (*big.Int, error) { - return m.getOriginAmount(ctx, origin, dest, address, balance) +func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, address common.Address, originBalance, destBalance *big.Int) (*big.Int, error) { + return m.getOriginAmount(ctx, origin, dest, address, originBalance, destBalance) } func (m *Manager) GetDestAmount(ctx context.Context, quoteAmount *big.Int, chainID int, tokenName string) (*big.Int, error) { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index baa65ad0ef..33e97fdfb3 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -402,7 +402,7 @@ type quoteInput struct { func (m *Manager) generateQuote(ctx context.Context, input quoteInput) (quote *model.PutQuoteRequest, err error) { // Calculate the quote amount for this route - originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.destTokenAddr, input.destBalance) + originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.destTokenAddr, input.originBalance, input.destBalance) // don't quote if gas exceeds quote if errors.Is(err, errMinGasExceedsQuoteAmount) { originAmount = big.NewInt(0) @@ -486,12 +486,13 @@ func (m *Manager) recordQuoteAmounts(_ context.Context, observer metric.Observer // getOriginAmount calculates the origin quote amount for a given route. // //nolint:cyclop -func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, address common.Address, balance *big.Int) (quoteAmount *big.Int, err error) { +func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, address common.Address, originBalance, destBalance *big.Int) (quoteAmount *big.Int, err error) { ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "getOriginAmount", trace.WithAttributes( attribute.String(metrics.Origin, strconv.Itoa(origin)), attribute.String(metrics.Destination, strconv.Itoa(dest)), attribute.String("address", address.String()), - attribute.String("balance", balance.String()), + attribute.String("origin_balance", originBalance.String()), + attribute.String("dest_balance", destBalance.String()), )) defer func() { @@ -523,7 +524,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a if err != nil { return nil, fmt.Errorf("error getting quote pct: %w", err) } - balanceFlt := new(big.Float).SetInt(balance) + balanceFlt := new(big.Float).SetInt(destBalance) quoteAmount, _ = new(big.Float).Mul(balanceFlt, new(big.Float).SetFloat64(quotePct/100)).Int(nil) // Apply the quoteOffset to origin token. @@ -548,12 +549,12 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a } // Finally, clip the quoteAmount by the balance - if quoteAmount.Cmp(balance) > 0 { + if quoteAmount.Cmp(destBalance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), - attribute.String("balance", balance.String()), + attribute.String("balance", destBalance.String()), )) - quoteAmount = balance + quoteAmount = destBalance } // Deduct gas cost from the quote amount, if necessary diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 91f264216d..6edf973ee2 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -178,49 +178,49 @@ func (s *QuoterSuite) TestGetOriginAmount() { } // Set default quote params; should return the balance. - quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount := balance s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. setQuoteParams(50, 0, "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. setQuoteParams(50, -100, "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. setQuoteParams(25, 0, "500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. setQuoteParams(25, 0, "500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. setQuoteParams(25, 0, "1500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) // Toggle insufficient gas; should be 0. s.setGasSufficiency(false) - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) s.NoError(err) expectedAmount = big.NewInt(0) s.Equal(expectedAmount, quoteAmount) From 8a6cf15858c6f27674423164ca67e4611b366209 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 13:19:45 -0400 Subject: [PATCH 10/19] Feat: getOriginAmount properly incorporates MaxBalance --- services/rfq/relayer/quoter/export_test.go | 4 +-- services/rfq/relayer/quoter/quoter.go | 30 ++++++++++++++----- services/rfq/relayer/quoter/quoter_test.go | 35 ++++++++++++++-------- services/rfq/relayer/relconfig/getters.go | 2 ++ 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/services/rfq/relayer/quoter/export_test.go b/services/rfq/relayer/quoter/export_test.go index 293bdb192d..231f831c24 100644 --- a/services/rfq/relayer/quoter/export_test.go +++ b/services/rfq/relayer/quoter/export_test.go @@ -14,8 +14,8 @@ func (m *Manager) GenerateQuotes(ctx context.Context, chainID int, address commo return m.generateQuotes(ctx, chainID, address, balance, inv) } -func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, address common.Address, originBalance, destBalance *big.Int) (*big.Int, error) { - return m.getOriginAmount(ctx, origin, dest, address, originBalance, destBalance) +func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, originAddr common.Address, address common.Address, originBalance, destBalance *big.Int) (*big.Int, error) { + return m.getOriginAmount(ctx, origin, dest, originAddr, address, originBalance, destBalance) } func (m *Manager) GetDestAmount(ctx context.Context, quoteAmount *big.Int, chainID int, tokenName string) (*big.Int, error) { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 33e97fdfb3..0d22e2999b 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -402,7 +402,7 @@ type quoteInput struct { func (m *Manager) generateQuote(ctx context.Context, input quoteInput) (quote *model.PutQuoteRequest, err error) { // Calculate the quote amount for this route - originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.destTokenAddr, input.originBalance, input.destBalance) + originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.originTokenAddr, input.destTokenAddr, input.originBalance, input.destBalance) // don't quote if gas exceeds quote if errors.Is(err, errMinGasExceedsQuoteAmount) { originAmount = big.NewInt(0) @@ -486,11 +486,11 @@ func (m *Manager) recordQuoteAmounts(_ context.Context, observer metric.Observer // getOriginAmount calculates the origin quote amount for a given route. // //nolint:cyclop -func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, address common.Address, originBalance, destBalance *big.Int) (quoteAmount *big.Int, err error) { +func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, originAddress, destAddress common.Address, originBalance, destBalance *big.Int) (quoteAmount *big.Int, err error) { ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "getOriginAmount", trace.WithAttributes( attribute.String(metrics.Origin, strconv.Itoa(origin)), attribute.String(metrics.Destination, strconv.Itoa(dest)), - attribute.String("address", address.String()), + attribute.String("address", destAddress.String()), attribute.String("origin_balance", originBalance.String()), attribute.String("dest_balance", destBalance.String()), )) @@ -528,7 +528,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a quoteAmount, _ = new(big.Float).Mul(balanceFlt, new(big.Float).SetFloat64(quotePct/100)).Int(nil) // Apply the quoteOffset to origin token. - tokenName, err := m.config.GetTokenName(uint32(dest), address.Hex()) + tokenName, err := m.config.GetTokenName(uint32(dest), destAddress.Hex()) if err != nil { return nil, fmt.Errorf("error getting token name: %w", err) } @@ -539,7 +539,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a quoteAmount = m.applyOffset(ctx, quoteOffsetBps, quoteAmount) // Clip the quoteAmount by the minQuoteAmount - minQuoteAmount := m.config.GetMinQuoteAmount(dest, address) + minQuoteAmount := m.config.GetMinQuoteAmount(dest, destAddress) if quoteAmount.Cmp(minQuoteAmount) < 0 { span.AddEvent("quote amount less than min quote amount", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), @@ -548,7 +548,23 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a quoteAmount = minQuoteAmount } - // Finally, clip the quoteAmount by the balance + // Clip the quoteAmount by the max origin balance + maxBalance := m.config.GetMaxBalance(origin, originAddress) + fmt.Printf("maxBalance: %v originBalance: %v\n", maxBalance, originBalance) + if originBalance != nil && maxBalance.Cmp(big.NewInt(0)) > 0 { + quotableBalance := new(big.Int).Sub(maxBalance, originBalance) + if quoteAmount.Cmp(quotableBalance) > 0 { + span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( + attribute.String("quote_amount", quoteAmount.String()), + attribute.String("quotable_balance", quotableBalance.String()), + attribute.String("max_balance", maxBalance.String()), + attribute.String("origin_balance", originBalance.String()), + )) + quoteAmount = quotableBalance + } + } + + // Finally, clip the quoteAmount by the dest balance if quoteAmount.Cmp(destBalance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), @@ -558,7 +574,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, a } // Deduct gas cost from the quote amount, if necessary - quoteAmount, err = m.deductGasCost(ctx, quoteAmount, address, dest) + quoteAmount, err = m.deductGasCost(ctx, quoteAmount, destAddress, dest) if err != nil { return nil, fmt.Errorf("error deducting gas cost: %w", err) } diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 6edf973ee2..fec5e7f631 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -164,63 +164,72 @@ func (s *QuoterSuite) TestGetOriginAmount() { origin := int(s.origin) dest := int(s.destination) address := common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85") + originAddr := common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48") balance := big.NewInt(1000_000_000) // 1000 USDC - setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount string) { + setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount, maxBalance string) { s.config.BaseChainConfig.QuotePct = quotePct destTokenCfg := s.config.Chains[dest].Tokens["USDC"] destTokenCfg.MinQuoteAmount = minQuoteAmount originTokenCfg := s.config.Chains[origin].Tokens["USDC"] originTokenCfg.QuoteOffsetBps = quoteOffset + originTokenCfg.MaxBalance = maxBalance s.config.Chains[dest].Tokens["USDC"] = destTokenCfg s.config.Chains[origin].Tokens["USDC"] = originTokenCfg s.manager.SetConfig(s.config) } // Set default quote params; should return the balance. - quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount := balance s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. - setQuoteParams(50, 0, "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + setQuoteParams(50, 0, "0", "0") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. - setQuoteParams(50, -100, "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + setQuoteParams(50, -100, "0", "0") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + setQuoteParams(25, 0, "500", "0") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. - setQuoteParams(25, 0, "500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + setQuoteParams(25, 0, "500", "0") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. - setQuoteParams(25, 0, "1500") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + setQuoteParams(25, 0, "1500", "0") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) + // Set QuotePct to 25 with MinQuoteAmount of 1500 and MaxBalance of 1200; should be 200. + setQuoteParams(25, 0, "1500", "1200") + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + s.NoError(err) + expectedAmount = big.NewInt(200_000_000) + s.Equal(expectedAmount, quoteAmount) + // Toggle insufficient gas; should be 0. s.setGasSufficiency(false) - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, address, nil, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) s.NoError(err) expectedAmount = big.NewInt(0) s.Equal(expectedAmount, quoteAmount) diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index da9c72ede9..847c6861b9 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -303,6 +303,7 @@ const defaultMaxBalance = 0 // GetMaxBalance returns the MaxBalance for the given chain and address. // Note that this getter returns the value in native token decimals. func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { + fmt.Printf("getmaxbalance for chain %v addr %v\n", chainID, addr) chainCfg, ok := c.Chains[chainID] if !ok { return big.NewInt(defaultMaxBalance) @@ -310,6 +311,7 @@ func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { var tokenCfg *TokenConfig for _, cfg := range chainCfg.Tokens { + fmt.Printf("checking token cfg: %v\n", cfg) if common.HexToAddress(cfg.Address).Hex() == addr.Hex() { cfgCopy := cfg tokenCfg = &cfgCopy From fa5d27f69fd3eab424347478b95c2d6af72c5a28 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 13:31:57 -0400 Subject: [PATCH 11/19] Feat: getOriginQuoteAmount takes QuoteInput struct --- services/rfq/relayer/quoter/export_test.go | 4 +- services/rfq/relayer/quoter/quoter.go | 99 +++++++++++----------- services/rfq/relayer/quoter/quoter_test.go | 25 ++++-- 3 files changed, 69 insertions(+), 59 deletions(-) diff --git a/services/rfq/relayer/quoter/export_test.go b/services/rfq/relayer/quoter/export_test.go index 231f831c24..81d719ae03 100644 --- a/services/rfq/relayer/quoter/export_test.go +++ b/services/rfq/relayer/quoter/export_test.go @@ -14,8 +14,8 @@ func (m *Manager) GenerateQuotes(ctx context.Context, chainID int, address commo return m.generateQuotes(ctx, chainID, address, balance, inv) } -func (m *Manager) GetOriginAmount(ctx context.Context, origin, dest int, originAddr common.Address, address common.Address, originBalance, destBalance *big.Int) (*big.Int, error) { - return m.getOriginAmount(ctx, origin, dest, originAddr, address, originBalance, destBalance) +func (m *Manager) GetOriginAmount(ctx context.Context, input QuoteInput) (*big.Int, error) { + return m.getOriginAmount(ctx, input) } func (m *Manager) GetDestAmount(ctx context.Context, quoteAmount *big.Int, chainID int, tokenName string) (*big.Int, error) { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 0d22e2999b..d6d017494f 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -354,14 +354,14 @@ func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address } g.Go(func() error { - input := quoteInput{ - originChainID: origin, - destChainID: chainID, - originTokenAddr: originTokenAddr, - destTokenAddr: address, - originBalance: originBalance, - destBalance: balance, - destRFQAddr: destRFQAddr, + input := QuoteInput{ + OriginChainID: origin, + DestChainID: chainID, + OriginTokenAddr: originTokenAddr, + DestTokenAddr: address, + OriginBalance: originBalance, + DestBalance: balance, + DestRFQAddr: destRFQAddr, } quote, quoteErr := m.generateQuote(gctx, input) @@ -390,19 +390,20 @@ func (m *Manager) generateQuotes(parentCtx context.Context, chainID int, address return quotes, nil } -type quoteInput struct { - originChainID int - destChainID int - originTokenAddr common.Address - destTokenAddr common.Address - originBalance *big.Int - destBalance *big.Int - destRFQAddr string +// QuoteInput is a wrapper struct for input arguments to generateQuote. +type QuoteInput struct { + OriginChainID int + DestChainID int + OriginTokenAddr common.Address + DestTokenAddr common.Address + OriginBalance *big.Int + DestBalance *big.Int + DestRFQAddr string } -func (m *Manager) generateQuote(ctx context.Context, input quoteInput) (quote *model.PutQuoteRequest, err error) { +func (m *Manager) generateQuote(ctx context.Context, input QuoteInput) (quote *model.PutQuoteRequest, err error) { // Calculate the quote amount for this route - originAmount, err := m.getOriginAmount(ctx, input.originChainID, input.destChainID, input.originTokenAddr, input.destTokenAddr, input.originBalance, input.destBalance) + originAmount, err := m.getOriginAmount(ctx, input) // don't quote if gas exceeds quote if errors.Is(err, errMinGasExceedsQuoteAmount) { originAmount = big.NewInt(0) @@ -412,38 +413,38 @@ func (m *Manager) generateQuote(ctx context.Context, input quoteInput) (quote *m } // Calculate the fee for this route - destToken, err := m.config.GetTokenName(uint32(input.destChainID), input.destTokenAddr.Hex()) + destToken, err := m.config.GetTokenName(uint32(input.DestChainID), input.DestTokenAddr.Hex()) if err != nil { logger.Error("Error getting dest token ID", "error", err) return nil, fmt.Errorf("error getting dest token ID: %w", err) } - fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.originChainID), uint32(input.destChainID), destToken, true) + fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.OriginChainID), uint32(input.DestChainID), destToken, true) if err != nil { logger.Error("Error getting total fee", "error", err) return nil, fmt.Errorf("error getting total fee: %w", err) } - originRFQAddr, err := m.config.GetRFQAddress(input.originChainID) + originRFQAddr, err := m.config.GetRFQAddress(input.OriginChainID) if err != nil { logger.Error("Error getting RFQ address", "error", err) return nil, fmt.Errorf("error getting RFQ address: %w", err) } // Build the quote - destAmount, err := m.getDestAmount(ctx, originAmount, input.destChainID, destToken) + destAmount, err := m.getDestAmount(ctx, originAmount, input.DestChainID, destToken) if err != nil { logger.Error("Error getting dest amount", "error", err) return nil, fmt.Errorf("error getting dest amount: %w", err) } quote = &model.PutQuoteRequest{ - OriginChainID: input.originChainID, - OriginTokenAddr: input.originTokenAddr.Hex(), - DestChainID: input.destChainID, - DestTokenAddr: input.destTokenAddr.Hex(), + OriginChainID: input.OriginChainID, + OriginTokenAddr: input.OriginTokenAddr.Hex(), + DestChainID: input.DestChainID, + DestTokenAddr: input.DestTokenAddr.Hex(), DestAmount: destAmount.String(), MaxOriginAmount: originAmount.String(), FixedFee: fee.String(), OriginFastBridgeAddress: originRFQAddr, - DestFastBridgeAddress: input.destRFQAddr, + DestFastBridgeAddress: input.DestRFQAddr, } return quote, nil } @@ -486,13 +487,14 @@ func (m *Manager) recordQuoteAmounts(_ context.Context, observer metric.Observer // getOriginAmount calculates the origin quote amount for a given route. // //nolint:cyclop -func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, originAddress, destAddress common.Address, originBalance, destBalance *big.Int) (quoteAmount *big.Int, err error) { +func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) (quoteAmount *big.Int, err error) { ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "getOriginAmount", trace.WithAttributes( - attribute.String(metrics.Origin, strconv.Itoa(origin)), - attribute.String(metrics.Destination, strconv.Itoa(dest)), - attribute.String("address", destAddress.String()), - attribute.String("origin_balance", originBalance.String()), - attribute.String("dest_balance", destBalance.String()), + attribute.Int(metrics.Origin, input.OriginChainID), + attribute.Int(metrics.Destination, input.DestChainID), + attribute.String("dest_address", input.DestTokenAddr.String()), + attribute.String("origin_address", input.OriginTokenAddr.String()), + attribute.String("origin_balance", input.OriginBalance.String()), + attribute.String("dest_balance", input.DestBalance.String()), )) defer func() { @@ -503,11 +505,11 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, o // First, check if we have enough gas to complete the a bridge for this route // If not, set the quote amount to zero to make sure a stale quote won't be used // TODO: handle in-flight gas; for now we can set a high min_gas_token - sufficentGasOrigin, err := m.inventoryManager.HasSufficientGas(ctx, origin, nil) + sufficentGasOrigin, err := m.inventoryManager.HasSufficientGas(ctx, input.OriginChainID, nil) if err != nil { return nil, fmt.Errorf("error checking sufficient gas: %w", err) } - sufficentGasDest, err := m.inventoryManager.HasSufficientGas(ctx, dest, nil) + sufficentGasDest, err := m.inventoryManager.HasSufficientGas(ctx, input.DestChainID, nil) if err != nil { return nil, fmt.Errorf("error checking sufficient gas: %w", err) } @@ -520,26 +522,26 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, o } // Apply the quotePct - quotePct, err := m.config.GetQuotePct(dest) + quotePct, err := m.config.GetQuotePct(input.DestChainID) if err != nil { return nil, fmt.Errorf("error getting quote pct: %w", err) } - balanceFlt := new(big.Float).SetInt(destBalance) + balanceFlt := new(big.Float).SetInt(input.DestBalance) quoteAmount, _ = new(big.Float).Mul(balanceFlt, new(big.Float).SetFloat64(quotePct/100)).Int(nil) // Apply the quoteOffset to origin token. - tokenName, err := m.config.GetTokenName(uint32(dest), destAddress.Hex()) + tokenName, err := m.config.GetTokenName(uint32(input.DestChainID), input.DestTokenAddr.Hex()) if err != nil { return nil, fmt.Errorf("error getting token name: %w", err) } - quoteOffsetBps, err := m.config.GetQuoteOffsetBps(origin, tokenName, true) + quoteOffsetBps, err := m.config.GetQuoteOffsetBps(input.OriginChainID, tokenName, true) if err != nil { return nil, fmt.Errorf("error getting quote offset bps: %w", err) } quoteAmount = m.applyOffset(ctx, quoteOffsetBps, quoteAmount) // Clip the quoteAmount by the minQuoteAmount - minQuoteAmount := m.config.GetMinQuoteAmount(dest, destAddress) + minQuoteAmount := m.config.GetMinQuoteAmount(input.DestChainID, input.DestTokenAddr) if quoteAmount.Cmp(minQuoteAmount) < 0 { span.AddEvent("quote amount less than min quote amount", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), @@ -549,32 +551,31 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, origin, dest int, o } // Clip the quoteAmount by the max origin balance - maxBalance := m.config.GetMaxBalance(origin, originAddress) - fmt.Printf("maxBalance: %v originBalance: %v\n", maxBalance, originBalance) - if originBalance != nil && maxBalance.Cmp(big.NewInt(0)) > 0 { - quotableBalance := new(big.Int).Sub(maxBalance, originBalance) + maxBalance := m.config.GetMaxBalance(input.OriginChainID, input.OriginTokenAddr) + if input.OriginBalance != nil && maxBalance.Cmp(big.NewInt(0)) > 0 { + quotableBalance := new(big.Int).Sub(maxBalance, input.OriginBalance) if quoteAmount.Cmp(quotableBalance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), attribute.String("quotable_balance", quotableBalance.String()), attribute.String("max_balance", maxBalance.String()), - attribute.String("origin_balance", originBalance.String()), + attribute.String("origin_balance", input.OriginBalance.String()), )) quoteAmount = quotableBalance } } // Finally, clip the quoteAmount by the dest balance - if quoteAmount.Cmp(destBalance) > 0 { + if quoteAmount.Cmp(input.DestBalance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), - attribute.String("balance", destBalance.String()), + attribute.String("balance", input.DestBalance.String()), )) - quoteAmount = destBalance + quoteAmount = input.DestBalance } // Deduct gas cost from the quote amount, if necessary - quoteAmount, err = m.deductGasCost(ctx, quoteAmount, destAddress, dest) + quoteAmount, err = m.deductGasCost(ctx, quoteAmount, input.DestTokenAddr, input.DestChainID) if err != nil { return nil, fmt.Errorf("error deducting gas cost: %w", err) } diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index fec5e7f631..094ad3a29c 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -179,57 +179,66 @@ func (s *QuoterSuite) TestGetOriginAmount() { s.manager.SetConfig(s.config) } + input := quoter.QuoteInput{ + OriginChainID: origin, + DestChainID: dest, + OriginTokenAddr: originAddr, + DestTokenAddr: address, + OriginBalance: balance, + DestBalance: balance, + } + // Set default quote params; should return the balance. - quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err := s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount := balance s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with MinQuoteAmount of 0; should be 50% of balance. setQuoteParams(50, 0, "0", "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 50 with QuoteOffset of -1%. Should be 1% less than 50% of balance. setQuoteParams(50, -100, "0", "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(495_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. setQuoteParams(25, 0, "500", "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 500; should be 50% of balance. setQuoteParams(25, 0, "500", "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(500_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500; should be total balance. setQuoteParams(25, 0, "1500", "0") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(1000_000_000) s.Equal(expectedAmount, quoteAmount) // Set QuotePct to 25 with MinQuoteAmount of 1500 and MaxBalance of 1200; should be 200. setQuoteParams(25, 0, "1500", "1200") - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(200_000_000) s.Equal(expectedAmount, quoteAmount) // Toggle insufficient gas; should be 0. s.setGasSufficiency(false) - quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), origin, dest, originAddr, address, balance, balance) + quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input) s.NoError(err) expectedAmount = big.NewInt(0) s.Equal(expectedAmount, quoteAmount) From a0a32a2054a6b6f0e752ccc556cfe8a2ed15768d Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 25 Jul 2024 13:31:58 -0400 Subject: [PATCH 12/19] [goreleaser] From 0db5b5b12ae933cc97d07b76a893de84f3260616 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 17:40:48 +0200 Subject: [PATCH 13/19] Feat: check for negative quotable balance --- services/rfq/relayer/quoter/quoter.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index d6d017494f..b03ab0dabc 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -554,7 +554,14 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) ( maxBalance := m.config.GetMaxBalance(input.OriginChainID, input.OriginTokenAddr) if input.OriginBalance != nil && maxBalance.Cmp(big.NewInt(0)) > 0 { quotableBalance := new(big.Int).Sub(maxBalance, input.OriginBalance) - if quoteAmount.Cmp(quotableBalance) > 0 { + if quotableBalance.Cmp(big.NewInt(0)) < 0 { + span.AddEvent("negative quotable balance", trace.WithAttributes( + attribute.String("quotable_balance", quotableBalance.String()), + attribute.String("max_balance", maxBalance.String()), + attribute.String("origin_balance", input.OriginBalance.String()), + )) + quoteAmount = big.NewInt(0) + } else if quoteAmount.Cmp(quotableBalance) > 0 { span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), attribute.String("quotable_balance", quotableBalance.String()), From eaec1ab251cc35f20fa4f10c0413d2550f3d8da0 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 18:26:41 +0200 Subject: [PATCH 14/19] Feat: convert MaxBalance to string ptr --- services/rfq/relayer/quoter/quoter_test.go | 2 +- services/rfq/relayer/relconfig/config.go | 2 +- services/rfq/relayer/relconfig/getters.go | 17 +++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 7eadd2c026..9b0075bdc6 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -173,7 +173,7 @@ func (s *QuoterSuite) TestGetOriginAmount() { destTokenCfg.MinQuoteAmount = minQuoteAmount originTokenCfg := s.config.Chains[origin].Tokens["USDC"] originTokenCfg.QuoteOffsetBps = quoteOffset - originTokenCfg.MaxBalance = maxBalance + originTokenCfg.MaxBalance = &maxBalance s.config.Chains[dest].Tokens["USDC"] = destTokenCfg s.config.Chains[origin].Tokens["USDC"] = originTokenCfg s.manager.SetConfig(s.config) diff --git a/services/rfq/relayer/relconfig/config.go b/services/rfq/relayer/relconfig/config.go index dfe674a9ec..2608611928 100644 --- a/services/rfq/relayer/relconfig/config.go +++ b/services/rfq/relayer/relconfig/config.go @@ -129,7 +129,7 @@ type TokenConfig struct { // of the given token, and vice versa. QuoteOffsetBps float64 `yaml:"quote_offset_bps"` // MaxBalance is the maximum balance that should be accumulated for this token on this chain (human-readable units) - MaxBalance string `yaml:"max_balance"` + MaxBalance *string `yaml:"max_balance"` } // DatabaseConfig represents the configuration for the database. diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index 2126ff43c5..44b7b45165 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -2,11 +2,12 @@ package relconfig import ( "fmt" - "github.com/synapsecns/sanguine/core" "math/big" "reflect" "time" + "github.com/synapsecns/sanguine/core" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/ethergo/signer/config" @@ -316,7 +317,7 @@ func (c Config) GetQuoteOffsetBps(chainID int, tokenName string, isOrigin bool) return offset, nil } -const defaultMaxBalance = 0 +var defaultMaxBalance *big.Int // default to nil, signifies 'positive inf' // GetMaxBalance returns the MaxBalance for the given chain and address. // Note that this getter returns the value in native token decimals. @@ -324,7 +325,7 @@ func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { fmt.Printf("getmaxbalance for chain %v addr %v\n", chainID, addr) chainCfg, ok := c.Chains[chainID] if !ok { - return big.NewInt(defaultMaxBalance) + return defaultMaxBalance } var tokenCfg *TokenConfig @@ -336,15 +337,15 @@ func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { break } } - if tokenCfg == nil { - return big.NewInt(defaultMaxBalance) + if tokenCfg == nil || tokenCfg.MaxBalance == nil { + return defaultMaxBalance } - quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MaxBalance) + quoteAmountFlt, ok := new(big.Float).SetString(*tokenCfg.MaxBalance) if !ok { - return big.NewInt(defaultMaxBalance) + return defaultMaxBalance } if quoteAmountFlt.Cmp(big.NewFloat(0)) <= 0 { - return big.NewInt(defaultMaxBalance) + return defaultMaxBalance } // Scale the minBalance by the token decimals. From 045bc6801bc4fc8a7ee9f9dac7dab76a8c84cdb0 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 18:28:20 +0200 Subject: [PATCH 15/19] Feat: handle nil as positive inf --- services/rfq/relayer/quoter/quoter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index b03ab0dabc..165b269070 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -552,10 +552,10 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) ( // Clip the quoteAmount by the max origin balance maxBalance := m.config.GetMaxBalance(input.OriginChainID, input.OriginTokenAddr) - if input.OriginBalance != nil && maxBalance.Cmp(big.NewInt(0)) > 0 { + if maxBalance != nil && input.OriginBalance != nil { quotableBalance := new(big.Int).Sub(maxBalance, input.OriginBalance) - if quotableBalance.Cmp(big.NewInt(0)) < 0 { - span.AddEvent("negative quotable balance", trace.WithAttributes( + if quotableBalance.Cmp(big.NewInt(0)) <= 0 { + span.AddEvent("non-positive quotable balance", trace.WithAttributes( attribute.String("quotable_balance", quotableBalance.String()), attribute.String("max_balance", maxBalance.String()), attribute.String("origin_balance", input.OriginBalance.String()), From d6a236e3d1458d6248018bf0d03675d0367f9a03 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 18:41:44 +0200 Subject: [PATCH 16/19] Cleanup: prints --- services/rfq/relayer/relconfig/getters.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/rfq/relayer/relconfig/getters.go b/services/rfq/relayer/relconfig/getters.go index 44b7b45165..090b7ee6b6 100644 --- a/services/rfq/relayer/relconfig/getters.go +++ b/services/rfq/relayer/relconfig/getters.go @@ -322,7 +322,6 @@ var defaultMaxBalance *big.Int // default to nil, signifies 'positive inf' // GetMaxBalance returns the MaxBalance for the given chain and address. // Note that this getter returns the value in native token decimals. func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { - fmt.Printf("getmaxbalance for chain %v addr %v\n", chainID, addr) chainCfg, ok := c.Chains[chainID] if !ok { return defaultMaxBalance @@ -330,7 +329,6 @@ func (c Config) GetMaxBalance(chainID int, addr common.Address) *big.Int { var tokenCfg *TokenConfig for _, cfg := range chainCfg.Tokens { - fmt.Printf("checking token cfg: %v\n", cfg) if common.HexToAddress(cfg.Address).Hex() == addr.Hex() { cfgCopy := cfg tokenCfg = &cfgCopy From 0bbb60a0085e1a89c363eac5d7bec4c628635ad7 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 18:57:01 +0200 Subject: [PATCH 17/19] Cleanup: tracing msg --- services/rfq/relayer/quoter/quoter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 165b269070..7c830a9f97 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -574,7 +574,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) ( // Finally, clip the quoteAmount by the dest balance if quoteAmount.Cmp(input.DestBalance) > 0 { - span.AddEvent("quote amount greater than quotable balance", trace.WithAttributes( + span.AddEvent("quote amount greater than destination balance", trace.WithAttributes( attribute.String("quote_amount", quoteAmount.String()), attribute.String("balance", input.DestBalance.String()), )) From 62680b71a69461ca394740a956c44a246094c86c Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Sun, 28 Jul 2024 18:57:03 +0200 Subject: [PATCH 18/19] [goreleaser] From 7d003185a981e4d56898c3c5baeecc82248bd0ed Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 7 Aug 2024 10:30:23 -0400 Subject: [PATCH 19/19] [goreleaser]