Skip to content

Commit

Permalink
add rfq bebop (#423)
Browse files Browse the repository at this point in the history
Signed-off-by: thanhpp <[email protected]>
  • Loading branch information
tien7668 authored Oct 8, 2024
1 parent f169224 commit 63da885
Show file tree
Hide file tree
Showing 13 changed files with 691 additions and 10 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/deckarep/golang-set/v2 v2.6.0
github.com/dgraph-io/ristretto v0.1.1
github.com/ethereum/go-ethereum v1.13.9
github.com/go-resty/resty/v2 v2.10.0
github.com/go-resty/resty/v2 v2.12.0
github.com/goccy/go-json v0.10.2
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.6.0
Expand Down
22 changes: 13 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo=
github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
Expand Down Expand Up @@ -255,7 +255,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
Expand All @@ -273,7 +274,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -304,25 +306,27 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
Expand Down
115 changes: 115 additions & 0 deletions pkg/liquidity-source/bebop/client/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package client

import (
"context"
"encoding/json"
"errors"

bebop "github.com/KyberNetwork/kyberswap-dex-lib/pkg/liquidity-source/bebop"
"github.com/KyberNetwork/logger"
"github.com/ethereum/go-ethereum/common"
"github.com/go-resty/resty/v2"
)

const (
headerNameKey = "name"
headerAuthKey = "Authorization"

pathQuote = "v3/quote"

errCodeBadRequest = 101
errCodeInsufficientLiquidity = 102
errCodeGasCalculationError = 103
errCodeMinSize = 104
errCodeTokenNotSupported = 105
errCodeGasExceedsSize = 106
errCodeUnexpectedPermitsError = 107
)

var (
ErrRFQFailed = errors.New("rfq failed")

ErrRFQBadRequest = errors.New("rfq: The API request is invalid - incorrect format or missing required fields")
ErrRFQInsufficientLiquidity = errors.New("rfq: There is insufficient liquidity to serve the requested trade size for the given tokens")
ErrRFQGasCalculationError = errors.New("rfq: There was a failure in calculating the gas estimate for this quotes transaction cost - this can occur when gas is fluctuating wildly")
ErrRFQMinSize = errors.New("rfq: User is trying to trade smaller than the minimum acceptable size for the given tokens")
ErrRFQTokenNotSupported = errors.New("rfq: The token user is trying to trade is not supported by Bebop at the moment")
ErrRFQGasExceedsSize = errors.New("rfq: Execution cost (gas) doesn't cover the trade size")
ErrRFQUnexpectedPermitsError = errors.New("rfq: Unexpected error when a user approves tokens via Permit or Permit2 signatures")
)

type HTTPClient struct {
config *bebop.HTTPClientConfig
client *resty.Client
}

func NewHTTPClient(config *bebop.HTTPClientConfig) *HTTPClient {
client := resty.New().
SetBaseURL(config.BaseURL).
SetTimeout(config.Timeout.Duration).
SetRetryCount(config.RetryCount).
SetHeader(headerNameKey, config.Name).
SetAuthToken(config.Authorization)

return &HTTPClient{
config: config,
client: client,
}
}

func (c *HTTPClient) QuoteSingleOrderResult(ctx context.Context, params bebop.QuoteParams) (bebop.QuoteSingleOrderResult, error) {
// token address case-sensitive
req := c.client.R().
SetContext(ctx).
// the SellTokens address must follow the HEX format
SetQueryParam(bebop.ParamsSellTokens, common.HexToAddress(params.SellTokens).Hex()).
// the BuyTokens address must follow the HEX format
SetQueryParam(bebop.ParamsBuyTokens, common.HexToAddress(params.BuyTokens).Hex()).
SetQueryParam(bebop.ParamsSellAmounts, params.SellAmounts).
SetQueryParam(bebop.ParamsTakerAddress, params.TakerAddress).
SetQueryParam(bebop.ParamsReceiverAddress, params.ReceiverAddress).
SetQueryParam(bebop.ParamsApproveType, "Standard").
SetQueryParam(bebop.ParamsSkipValidation, "true"). // not checking balance
SetQueryParam(bebop.ParamsGasLess, "false") // self-execution

var result bebop.QuoteSingleOrderResult
var fail bebop.QuoteFail
resp, err := req.SetResult(&result).SetError(&fail).Get(pathQuote)
if err != nil {
return bebop.QuoteSingleOrderResult{}, err
}

respBytes := resp.Body()
_ = json.Unmarshal(respBytes, &result)
_ = json.Unmarshal(respBytes, &fail)

if !resp.IsSuccess() || fail.Failed() {
return bebop.QuoteSingleOrderResult{}, parseRFQError(fail.Error.ErrorCode, fail.Error.Message)
}

return result, nil
}

func parseRFQError(errorCode int, message string) error {
switch errorCode {
case errCodeBadRequest:
return ErrRFQBadRequest
case errCodeInsufficientLiquidity:
return ErrRFQInsufficientLiquidity
case errCodeGasCalculationError:
return ErrRFQGasCalculationError
case errCodeMinSize:
return ErrRFQMinSize
case errCodeTokenNotSupported:
return ErrRFQTokenNotSupported
case errCodeGasExceedsSize:
return ErrRFQGasExceedsSize
case errCodeUnexpectedPermitsError:
return ErrRFQUnexpectedPermitsError
default:
logger.
WithFields(logger.Fields{"client": "bebop", "errorCode": errorCode, "message": message}).
Error("rfq failed")
return ErrRFQFailed
}
}
39 changes: 39 additions & 0 deletions pkg/liquidity-source/bebop/client/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package client_test

import (
"context"
"testing"
"time"

"github.com/KyberNetwork/blockchain-toolkit/time/durationjson"
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/liquidity-source/bebop"
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/liquidity-source/bebop/client"
"github.com/stretchr/testify/assert"
)

func TestHTTPClient(t *testing.T) {
t.Skip("has rate-limit for non-authorization requests")

c := client.NewHTTPClient(
&bebop.HTTPClientConfig{
BaseURL: "https://api.bebop.xyz/pmm/ethereum",
Timeout: durationjson.Duration{
Duration: time.Second * 5,
},
RetryCount: 1,
Name: "",
Authorization: "",
},
)

resp, err := c.QuoteSingleOrderResult(context.Background(), bebop.QuoteParams{
SellTokens: "0xC02aaA39b223fe8D0A0e5C4F27eAD9083C756Cc2",
BuyTokens: "0xdac17F958D2ee523a2206206994597C13D831ec7",
SellAmounts: "100000000000000000",
TakerAddress: "0x5Bad996643a924De21b6b2875c85C33F3c5bBcB6",
ApprovalType: "Standard",
})
assert.NoError(t, err)

t.Log(resp.ToSign)
}
11 changes: 11 additions & 0 deletions pkg/liquidity-source/bebop/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package bebop

import "github.com/KyberNetwork/blockchain-toolkit/time/durationjson"

type HTTPClientConfig struct {
BaseURL string `mapstructure:"base_url" json:"base_url"`
Timeout durationjson.Duration `mapstructure:"timeout" json:"timeout"`
RetryCount int `mapstructure:"retry_count" json:"retry_count"`
Name string `mapstructure:"name" json:"name"`
Authorization string `mapstructure:"authorization" json:"authorization"`
}
12 changes: 12 additions & 0 deletions pkg/liquidity-source/bebop/constant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package bebop

import (
"math/big"
)

const DexType = "bebop"

var (
zeroBF = big.NewFloat(0)
defaultGas = Gas{Quote: 200000}
)
Loading

0 comments on commit 63da885

Please sign in to comment.