Skip to content

Commit

Permalink
feat(rfq-indexer): add request column to BridgeRequested for refu…
Browse files Browse the repository at this point in the history
…nds (#3287)

* feat(rfq-relayer): add MaxRelayAmount (#3259)

* Feat: add quoteParams helper for test

* Feat: add MaxQuoteAmount to relconfig

* Feat: use MaxQuoteAmount

* Feat: handle MaxQuoteAmount in quoter test

* Replace: MaxQuoteAmount -> MaxRelayAmount

* Feat: shouldProcess() returns false if max relay amount exceeded

* Feat: add test for MaxRelayAmount

* add request field for refunds

* adding to events typing

---------

Co-authored-by: dwasse <wassermandaniel8@gmail.com>
Co-authored-by: defi-moses <jakedinero@protonmail.com>
  • Loading branch information
3 people authored Oct 16, 2024
1 parent 1dbcd96 commit 6b4c78e
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/rfq-indexer/api/src/graphql/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const qDeposits = () => {
'BridgeRequestEvents.originAmountFormatted',
'BridgeRequestEvents.destAmountFormatted',
'BridgeRequestEvents.sender',
'BridgeRequestEvents.request',
'BridgeRequestEvents.sendChainGas',
])
.where('BridgeRequestEvents.blockTimestamp', '>', 1722729600)
Expand Down
1 change: 1 addition & 0 deletions packages/rfq-indexer/api/src/graphql/types/events.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ scalar BigInt
destAmountFormatted: String!
destChainId: Int!
destChain: String!
request: String!
sendChainGas: Boolean!
}

Expand Down
1 change: 1 addition & 0 deletions packages/rfq-indexer/api/src/queries/depositsQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const qDeposits = () => {
'BridgeRequestEvents.originAmountFormatted',
'BridgeRequestEvents.destAmountFormatted',
'BridgeRequestEvents.sender',
'BridgeRequestEvents.request',
'BridgeRequestEvents.sendChainGas',
])
.where('BridgeRequestEvents.blockTimestamp', '>', 1722729600)
Expand Down
1 change: 1 addition & 0 deletions packages/rfq-indexer/api/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface BridgeRequestEvents {
originChainId: ColumnType<number>
originChain: ColumnType<string>
sender: ColumnType<string>
request: ColumnType<string>
originToken: ColumnType<string>
destToken: ColumnType<string>
originAmount: ColumnType<bigint>
Expand Down
1 change: 1 addition & 0 deletions packages/rfq-indexer/indexer/ponder.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default createSchema((p) => ({
id: p.string(),
transactionId: p.string(),
sender: p.string(),
request: p.string(),
originToken: p.string(),
destToken: p.string(),
originAmount: p.bigint().optional(),
Expand Down
2 changes: 2 additions & 0 deletions packages/rfq-indexer/indexer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ponder.on('FastBridgeV2:BridgeRequested', async ({ event, context }) => {
args: {
transactionId,
sender,
request,
destChainId,
originToken,
destToken,
Expand All @@ -33,6 +34,7 @@ ponder.on('FastBridgeV2:BridgeRequested', async ({ event, context }) => {
data: {
transactionId,
sender: trim(sender),
request: request,
originChainId: Number(chainId),
originChain: getChainName(Number(chainId)),
destChainId: Number(destChainId),
Expand Down
21 changes: 20 additions & 1 deletion services/rfq/relayer/quoter/quoter.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ func (m *Manager) ShouldProcess(parentCtx context.Context, quote reldb.QuoteRequ
return false, nil
}

// check relay amount
maxRelayAmount := m.config.GetMaxRelayAmount(int(quote.Transaction.OriginChainId), quote.Transaction.OriginToken)
if maxRelayAmount != nil {
if quote.Transaction.OriginAmount.Cmp(maxRelayAmount) > 0 {
span.AddEvent("origin amount is greater than max relay amount")
return false, nil
}
}

// all checks have passed
return true, nil
}
Expand Down Expand Up @@ -713,7 +722,7 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) (
}
}

// Finally, clip the quoteAmount by the dest balance
// Clip the quoteAmount by the dest balance
if quoteAmount.Cmp(input.DestBalance) > 0 {
span.AddEvent("quote amount greater than destination balance", trace.WithAttributes(
attribute.String("quote_amount", quoteAmount.String()),
Expand All @@ -722,6 +731,16 @@ func (m *Manager) getOriginAmount(parentCtx context.Context, input QuoteInput) (
quoteAmount = input.DestBalance
}

// Clip the quoteAmount by the maxQuoteAmount
maxQuoteAmount := m.config.GetMaxRelayAmount(input.DestChainID, input.DestTokenAddr)
if maxQuoteAmount != nil && quoteAmount.Cmp(maxQuoteAmount) > 0 {
span.AddEvent("quote amount greater than max quote amount", trace.WithAttributes(
attribute.String("quote_amount", quoteAmount.String()),
attribute.String("max_quote_amount", maxQuoteAmount.String()),
))
quoteAmount = maxQuoteAmount
}

// Deduct gas cost from the quote amount, if necessary
quoteAmount, err = m.deductGasCost(ctx, quoteAmount, input.DestTokenAddr, input.DestChainID)
if err != nil {
Expand Down
82 changes: 71 additions & 11 deletions services/rfq/relayer/quoter/quoter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ func (s *QuoterSuite) TestShouldProcess() {
s.False(s.manager.ShouldProcess(s.GetTestContext(), quote))
s.manager.SetRelayPaused(false)
s.True(s.manager.ShouldProcess(s.GetTestContext(), quote))

// Set max relay amount
originTokenCfg := s.config.Chains[int(s.origin)].Tokens["USDC"]
originTokenCfg.MaxRelayAmount = "900" // less than balance
s.config.Chains[int(s.origin)].Tokens["USDC"] = originTokenCfg
s.manager.SetConfig(s.config)
s.False(s.manager.ShouldProcess(s.GetTestContext(), quote))
}

func (s *QuoterSuite) TestIsProfitable() {
Expand Down Expand Up @@ -173,13 +180,23 @@ func (s *QuoterSuite) TestGetOriginAmount() {
originAddr := common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
balance := big.NewInt(1000_000_000) // 1000 USDC

setQuoteParams := func(quotePct, quoteOffset float64, minQuoteAmount, maxBalance string) {
s.config.BaseChainConfig.QuotePct = &quotePct
type quoteParams struct {
quotePct float64
quoteOffset float64
minQuoteAmount string
maxBalance string
maxQuoteAmount string
}

setQuoteParams := func(params quoteParams) {
s.config.BaseChainConfig.QuotePct = &params.quotePct
destTokenCfg := s.config.Chains[dest].Tokens["USDC"]
destTokenCfg.MinQuoteAmount = minQuoteAmount
destTokenCfg.MinQuoteAmount = params.minQuoteAmount
destTokenCfg.MaxRelayAmount = params.maxQuoteAmount
originTokenCfg := s.config.Chains[origin].Tokens["USDC"]
originTokenCfg.QuoteOffsetBps = quoteOffset
originTokenCfg.MaxBalance = &maxBalance
originTokenCfg.QuoteOffsetBps = params.quoteOffset
originTokenCfg.MaxBalance = &params.maxBalance
originTokenCfg.MaxRelayAmount = params.maxQuoteAmount
s.config.Chains[dest].Tokens["USDC"] = destTokenCfg
s.config.Chains[origin].Tokens["USDC"] = originTokenCfg
s.manager.SetConfig(s.config)
Expand All @@ -201,42 +218,85 @@ 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(quoteParams{
quotePct: 50,
quoteOffset: 0,
minQuoteAmount: "0",
maxBalance: "0",
})
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")
setQuoteParams(quoteParams{
quotePct: 50,
quoteOffset: -100,
minQuoteAmount: "0",
maxBalance: "0",
})
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")
setQuoteParams(quoteParams{
quotePct: 25,
quoteOffset: 0,
minQuoteAmount: "500",
maxBalance: "0",
})
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")
setQuoteParams(quoteParams{
quotePct: 25,
quoteOffset: 0,
minQuoteAmount: "500",
maxBalance: "0",
})
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")
setQuoteParams(quoteParams{
quotePct: 25,
quoteOffset: 0,
minQuoteAmount: "1500",
maxBalance: "0",
})
quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input)
s.NoError(err)
expectedAmount = big.NewInt(1000_000_000)
s.Equal(expectedAmount, quoteAmount)

// Set QuotePct to 100 with MinQuoteAmount of 0 and MaxRelayAmount of 500; should be 500.
setQuoteParams(quoteParams{
quotePct: 100,
quoteOffset: 0,
minQuoteAmount: "0",
maxBalance: "0",
maxQuoteAmount: "500",
})
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 and MaxBalance of 1200; should be 200.
setQuoteParams(25, 0, "1500", "1200")
setQuoteParams(quoteParams{
quotePct: 25,
quoteOffset: 0,
minQuoteAmount: "1500",
maxBalance: "1200",
})
quoteAmount, err = s.manager.GetOriginAmount(s.GetTestContext(), input)
s.NoError(err)
expectedAmount = big.NewInt(200_000_000)
Expand Down
2 changes: 2 additions & 0 deletions services/rfq/relayer/relconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ type TokenConfig struct {
PriceUSD float64 `yaml:"price_usd"`
// MinQuoteAmount is the minimum amount to quote for this token in human-readable units.
MinQuoteAmount string `yaml:"min_quote_amount"`
// MaxRelayAmount is the maximum amount to quote and relay for this token in human-readable units.
MaxRelayAmount string `yaml:"max_relay_amount"`
// RebalanceMethods are the supported methods for rebalancing.
RebalanceMethods []string `yaml:"rebalance_methods"`
// MaintenanceBalancePct is the percentage of the total balance under which a rebalance will be triggered.
Expand Down
35 changes: 35 additions & 0 deletions services/rfq/relayer/relconfig/getters.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,41 @@ func (c Config) GetMinQuoteAmount(chainID int, addr common.Address) *big.Int {
return quoteAmountScaled
}

var defaultMaxRelayAmount *big.Int // nil

// GetMaxRelayAmount returns the quote amount for the given chain and address.
// Note that this getter returns the value in native token decimals.
func (c Config) GetMaxRelayAmount(chainID int, addr common.Address) *big.Int {
chainCfg, ok := c.Chains[chainID]
if !ok {
return defaultMaxRelayAmount
}

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 defaultMaxRelayAmount
}
quoteAmountFlt, ok := new(big.Float).SetString(tokenCfg.MaxRelayAmount)
if !ok {
return defaultMaxRelayAmount
}
if quoteAmountFlt.Cmp(big.NewFloat(0)) <= 0 {
return defaultMaxRelayAmount
}

// Scale the minQuoteAmount 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
}

var defaultMinRebalanceAmount = big.NewInt(1000)

// GetMinRebalanceAmount returns the min rebalance amount for the given chain and address.
Expand Down

0 comments on commit 6b4c78e

Please sign in to comment.