Skip to content

Commit

Permalink
[Bebop] Support aggregate order (#672)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisngyn authored Dec 30, 2024
1 parent a17ef20 commit 66ea3db
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 6 deletions.
100 changes: 99 additions & 1 deletion pkg/liquidity-source/bebop/rfq.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
"github.com/KyberNetwork/logger"
"github.com/goccy/go-json"
"github.com/mitchellh/mapstructure"
)

Expand Down Expand Up @@ -51,14 +52,111 @@ func (h *RFQHandler) RFQ(ctx context.Context, params pool.RFQParams) (*pool.RFQR
return nil, fmt.Errorf("quote single order result: %w", err)
}

newAmountOut, _ := new(big.Int).SetString(result.ToSign.MakerAmount, 10)
newAmountOut, err := getAmountOutFromToSign(result.OnchainOrderType, result.ToSign)
if err != nil {
return nil, fmt.Errorf("get amount out from to sign: %w", err)
}

return &pool.RFQResult{
NewAmountOut: newAmountOut,
Extra: result,
}, nil
}

func getAmountOutFromToSign(onchainOrderType string, rawTxSign json.RawMessage) (*big.Int, error) {
switch onchainOrderType {
case OnchainOrderTypeSingleOrder:
return getAmountOutOfSingleOrderToSign(rawTxSign)
case OnchainOrderTypeAggregateOrder:
return getAmountOutOfAggregateOrderToSign(rawTxSign)
case OnchainOrderTypeOrderWithPermit2:
return getAmountOutOfOrderWithPermit2ToSign(rawTxSign)
case OnchainOrderTypeOrderWithBatchPermit2:
return getAmountOutOfOrderWithBatchPermit2ToSign(rawTxSign)
default:
return nil, fmt.Errorf("unsupported onchain order type: %s", onchainOrderType)
}
}

func getAmountOutOfSingleOrderToSign(rawTxSign json.RawMessage) (*big.Int, error) {
var toSign SingleOrderToSign
if err := json.Unmarshal(rawTxSign, &toSign); err != nil {
return nil, fmt.Errorf("unmarshal single order result: %w", err)
}
amountOut, ok := new(big.Int).SetString(toSign.MakerAmount, 10)
if !ok {
return nil, fmt.Errorf("invalid maker amount: %s", toSign.MakerAmount)
}
return amountOut, nil
}

func getAmountOutOfAggregateOrderToSign(rawTxSign json.RawMessage) (*big.Int, error) {
var toSign AggregateOrderToSign
if err := json.Unmarshal(rawTxSign, &toSign); err != nil {
return nil, fmt.Errorf("unmarshal aggregate order result: %w", err)
}

// With the aggregate order, it has some fields with format:
// - TakerAddress: common.Address
// - MakerAddress: [m]common.Address
// - TakerTokens: [m][n]common.Address
// - MakerTokens: [m][n]common.Address
// - TakerAmounts: [m][n]*big.Int
// - MakerAmounts: [m][n]*big.Int
// With m is number of makers and n is number of swap token pairs.
// Because we currently only support swap 1-1 token pair so n is always 1.
// So we can simplify the check by only checking the first element of each field in the logic below.

totalAmountOut := big.NewInt(0)

for _, amounts := range toSign.MakerAmounts {
if len(amounts) != 1 {
return nil, fmt.Errorf("invalid maker amounts: %v", amounts)
}
amountOut, ok := new(big.Int).SetString(amounts[0], 10)
if !ok {
return nil, fmt.Errorf("invalid maker amount: %s", amounts[0])
}
totalAmountOut.Add(totalAmountOut, amountOut)
}

return totalAmountOut, nil
}

func getAmountOutOfOrderWithPermit2ToSign(rawTxSign json.RawMessage) (*big.Int, error) {
var toSign OrderWithPermit2ToSign
if err := json.Unmarshal(rawTxSign, &toSign); err != nil {
return nil, fmt.Errorf("unmarshal order with permit2 result: %w", err)
}
amountOut, ok := new(big.Int).SetString(toSign.Witness.MakerAmount, 10)
if !ok {
return nil, fmt.Errorf("invalid maker amount: %s", toSign.Witness.MakerAmount)
}
return amountOut, nil
}

func getAmountOutOfOrderWithBatchPermit2ToSign(rawTxSign json.RawMessage) (*big.Int, error) {
var toSign OrderWithBatchPermit2ToSign
if err := json.Unmarshal(rawTxSign, &toSign); err != nil {
return nil, fmt.Errorf("unmarshal order with batch permit2 result: %w", err)
}

// logic here same as getAmountOutOfAggregateOrderToSign
totalAmountOut := big.NewInt(0)
for _, amounts := range toSign.Witness.MakerAmounts {
if len(amounts) != 1 {
return nil, fmt.Errorf("invalid maker amounts: %v", amounts)
}
amountOut, ok := new(big.Int).SetString(amounts[0], 10)
if !ok {
return nil, fmt.Errorf("invalid maker amount: %s", amounts[0])
}
totalAmountOut.Add(totalAmountOut, amountOut)
}

return totalAmountOut, nil
}

func (h *RFQHandler) BatchRFQ(context.Context, []pool.RFQParams) ([]*pool.RFQResult, error) {
return nil, nil
}
88 changes: 83 additions & 5 deletions pkg/liquidity-source/bebop/type.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package bebop

import "github.com/goccy/go-json"

type QueryParams = string

const (
Expand All @@ -18,6 +20,13 @@ const (
ParamsSourceAuth QueryParams = "source-auth"
)

const (
OnchainOrderTypeSingleOrder = "SingleOrder"
OnchainOrderTypeAggregateOrder = "AggregateOrder"
OnchainOrderTypeOrderWithPermit2 = "OrderWithPermit2"
OnchainOrderTypeOrderWithBatchPermit2 = "OrderWithBatchPermit2"
)

type QuoteParams struct {
// The tokens that will be supplied by the taker
SellTokens string
Expand Down Expand Up @@ -93,7 +102,16 @@ type QuoteSingleOrderResult struct {
Gas int `json:"gas"`
GasPrice int64 `json:"gasPrice"`
} `json:"tx"`
ToSign struct { // the toSign part uses snake_case
ToSign json.RawMessage `json:"toSign"`
OnchainOrderType string `json:"onchainOrderType"`
PartialFillOffset int `json:"partialFillOffset"`
}

// ToSign struct will depend on the OnchainOrderType field of the QuoteSingleOrderResult.
// Although, bebop support get quote for one to many and many to one, but we will only use one to one for now.
// So, we will only define the ToSign struct for one to one.
type (
SingleOrderToSign struct {
PartnerID int `json:"partner_id"`
Expiry int `json:"expiry"`
TakerAddress string `json:"taker_address"`
Expand All @@ -105,7 +123,67 @@ type QuoteSingleOrderResult struct {
MakerAmount string `json:"maker_amount"`
Receiver string `json:"receiver"`
PackedCommands string `json:"packed_commands"`
} `json:"toSign"`
OnchainOrderType string `json:"onchainOrderType"`
PartialFillOffset int `json:"partialFillOffset"`
}
}

AggregateOrderToSign struct {
PartnerID int `json:"partner_id"`
Expiry int `json:"expiry"`
TakerAddress string `json:"taker_address"`
MakerAddresses []string `json:"maker_addresses"`
MakerNonces []string `json:"maker_nonces"`
TakerTokens [][]string `json:"taker_tokens"`
MakerTokens [][]string `json:"maker_tokens"`
TakerAmounts [][]string `json:"taker_amounts"`
MakerAmounts [][]string `json:"maker_amounts"`
Receiver string `json:"receiver"`
Commands string `json:"commands"`
}

OrderWithPermit2ToSign struct {
Permitted struct {
Token string `json:"token"`
Amount string `json:"amount"`
} `json:"permitted"`
Spender string `json:"spender"`
Nonce string `json:"nonce"`
Deadline int64 `json:"deadline"`
Witness struct {
PartnerID int `json:"partner_id"`
Expiry int `json:"expiry"`
TakerAddress string `json:"taker_address"`
MakerAddress string `json:"maker_address"`
MakerNonce string `json:"maker_nonce"`
TakerToken string `json:"taker_token"`
MakerToken string `json:"maker_token"`
TakerAmount string `json:"taker_amount"`
MakerAmount string `json:"maker_amount"`
Receiver string `json:"receiver"`
PackedCommands string `json:"packed_commands"`
HooksHash string `json:"hooksHash"`
} `json:"witness"`
}

OrderWithBatchPermit2ToSign struct {
Permitted []struct {
Token string `json:"token"`
Amount string `json:"amount"`
} `json:"permitted"`
Spender string `json:"spender"`
Nonce string `json:"nonce"`
Deadline int64 `json:"deadline"`
Witness struct {
PartnerID int `json:"partner_id"`
Expiry int `json:"expiry"`
TakerAddress string `json:"taker_address"`
MakerAddresses []string `json:"maker_addresses"`
MakerNonces []string `json:"maker_nonces"`
TakerTokens [][]string `json:"taker_tokens"`
MakerTokens [][]string `json:"maker_tokens"`
TakerAmounts [][]string `json:"taker_amounts"`
MakerAmounts [][]string `json:"maker_amounts"`
Receiver string `json:"receiver"`
Commands string `json:"commands"`
HooksHash string `json:"hooksHash"`
} `json:"witness"`
}
)

0 comments on commit 66ea3db

Please sign in to comment.