Skip to content

Commit

Permalink
Implement encode/decode 1inch extension (#75)
Browse files Browse the repository at this point in the history
* Add encode/decode 1inch extension

* Fix lint

* Add interaction

* Implement interaction

* Implement encode/decode auction details

* Implement encode/decode settlement post interaction data

* Add fusion extension decode

* Convert auction details to use primitive types

* Convert settlement post interaction data to use primitive types

* Replace extension fields by byte arrays

* Convert string to []byte

* Sink some packages

* Shorten function encode

* Make lint happy

* Remove trim0x function

* Remove ZX global constant

* Use math.PaddedBigBytes instead

* Check data length before get it from bytes

* Add next function at decode package

* Implement bytes iterator

* Remove completely zx

* Remove unused assert in test

* Add check less than 0 when create auction details

* Remove big package in bytes iterator

* Add assert for some tests

* Return offset is a common.Hash
  • Loading branch information
chrisngyn authored Aug 21, 2024
1 parent b6c0d14 commit 213cb3b
Show file tree
Hide file tree
Showing 16 changed files with 1,130 additions and 109 deletions.
41 changes: 16 additions & 25 deletions pkg/oneinch/auction/calculator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"math/big"

"github.com/KyberNetwork/tradinglib/pkg/oneinch/fusionorder"
"github.com/KyberNetwork/tradinglib/pkg/oneinch/fusionutils"
)

const (
Expand All @@ -25,36 +24,27 @@ type Calculator struct {
}

func NewCalculator(
startTime *big.Int,
duration *big.Int,
initialRateBump *big.Int,
startTime int64,
duration int64,
initialRateBump int64,
points []fusionorder.AuctionPoint,
takerFeeRatio *big.Int,
takerFeeRatio int64,
gasCost fusionorder.AuctionGasCostInfo,
) Calculator {
if gasCost.GasBumpEstimate == nil {
gasCost.GasBumpEstimate = big.NewInt(0)
}
if gasCost.GasPriceEstimate == nil {
gasCost.GasPriceEstimate = big.NewInt(0)
}
return Calculator{
startTime: startTime,
duration: duration,
initialRateBump: initialRateBump,
startTime: big.NewInt(startTime),
duration: big.NewInt(duration),
initialRateBump: big.NewInt(initialRateBump),
points: points,
takerFeeRatio: takerFeeRatio,
takerFeeRatio: big.NewInt(takerFeeRatio),
gasCost: gasCost,
}
}

func NewCalculatorFromAuctionData(
takerFeeRatio *big.Int,
takerFeeRatio int64,
auctionDetails fusionorder.AuctionDetails,
) Calculator {
if takerFeeRatio == nil {
takerFeeRatio = big.NewInt(0)
}
return NewCalculator(
auctionDetails.StartTime,
auctionDetails.Duration,
Expand Down Expand Up @@ -82,23 +72,24 @@ func (c Calculator) CalcRateBump(time, blockBaseFee *big.Int) int64 {
}

func (c Calculator) getGasPriceBump(blockBaseFee *big.Int) *big.Int {
zeroBigInt := new(big.Int)
zeroBigInt := big.NewInt(0)
if zeroBigInt.Cmp(blockBaseFee) == 0 {
return zeroBigInt
}
if zeroBigInt.Cmp(c.gasCost.GasPriceEstimate) == 0 {
if c.gasCost.GasPriceEstimate == 0 {
return zeroBigInt
}
if zeroBigInt.Cmp(c.gasCost.GasBumpEstimate) == 0 {
if c.gasCost.GasBumpEstimate == 0 {
return zeroBigInt
}

return new(big.Int).Div(
new(big.Int).Div(
new(big.Int).Mul(
c.gasCost.GasBumpEstimate, blockBaseFee,
big.NewInt(c.gasCost.GasBumpEstimate), blockBaseFee,
),
c.gasCost.GasPriceEstimate),
big.NewInt(c.gasCost.GasPriceEstimate),
),
big.NewInt(GasPriceBase),
)
}
Expand Down Expand Up @@ -171,7 +162,7 @@ func calcAuctionTakingAmount(takingAmount *big.Int, rate int64, takerFeeRatio *b
return auctionTakingAmount
}

return fusionutils.AddRatioToAmount(auctionTakingAmount, takerFeeRatio)
return fusionorder.AddRatioToAmount(auctionTakingAmount, takerFeeRatio)
}

func CalcInitialRateBump(startAmount *big.Int, endAmount *big.Int) int64 {
Expand Down
35 changes: 17 additions & 18 deletions pkg/oneinch/auction/calculator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@ import (
"github.com/KyberNetwork/tradinglib/pkg/convert"
"github.com/KyberNetwork/tradinglib/pkg/oneinch/auction"
"github.com/KyberNetwork/tradinglib/pkg/oneinch/fusionorder"
"github.com/KyberNetwork/tradinglib/pkg/oneinch/fusionutils"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestAuctionCalculator(t *testing.T) {
t.Run("should be created successfully from suffix and salt", func(t *testing.T) {
auctionStartTime := big.NewInt(1708448252)
auctionStartTime := int64(1708448252)
postInteraction, err := fusionorder.NewSettlementPostInteractionDataFromSettlementSuffixData(
fusionorder.SettlementSuffixData{
IntegratorFee: fusionorder.IntegratorFee{
Ratio: fusionutils.BpsToRatioFormat(1),
Ratio: fusionorder.BpsToRatioFormat(1).Int64(),
Receiver: common.BigToAddress(big.NewInt(1)),
},
BankFee: big.NewInt(0),
BankFee: 0,
ResolvingStartTime: auctionStartTime,
Whitelist: []fusionorder.AuctionWhitelistItem{
{
Expand All @@ -36,8 +35,8 @@ func TestAuctionCalculator(t *testing.T) {

actionDetails, err := fusionorder.NewAuctionDetails(
auctionStartTime,
big.NewInt(50_000),
big.NewInt(120),
50_000,
120,
nil,
fusionorder.AuctionGasCostInfo{},
)
Expand All @@ -48,7 +47,7 @@ func TestAuctionCalculator(t *testing.T) {
takingAmount, ok := new(big.Int).SetString("1420000000", 10)
require.True(t, ok)

rate := calculator.CalcRateBump(new(big.Int).Add(auctionStartTime, big.NewInt(60)), big.NewInt(0))
rate := calculator.CalcRateBump(big.NewInt(auctionStartTime+60), big.NewInt(0))
auctionTakingAmount := calculator.CalcAuctionTakingAmount(takingAmount, rate)

assert.Equal(t, int64(25000), rate)
Expand All @@ -57,46 +56,46 @@ func TestAuctionCalculator(t *testing.T) {
}

func TestCalculator_GasBump(t *testing.T) {
now := big.NewInt(time.Now().Unix())
duration := big.NewInt(1800) // 30 minutes
now := time.Now().Unix()
duration := int64(1800) // 30 minutes
takingAmount := parseEther(t, 1)
calculator := auction.NewCalculator(
new(big.Int).Sub(now, big.NewInt(60)),
now-60,
duration,
big.NewInt(1000000),
1000000,
[]fusionorder.AuctionPoint{
{
Delay: 60,
Coefficient: 500000,
},
},
big.NewInt(0),
0,
fusionorder.AuctionGasCostInfo{
GasBumpEstimate: big.NewInt(10000),
GasPriceEstimate: big.NewInt(1000),
GasBumpEstimate: 10_000,
GasPriceEstimate: 1000,
},
)

t.Run("0 gwei = no gas fee", func(t *testing.T) {
bump := calculator.CalcRateBump(now, big.NewInt(0))
bump := calculator.CalcRateBump(big.NewInt(now), big.NewInt(0))
auctionTakingAmount := calculator.CalcAuctionTakingAmount(takingAmount, bump)
assert.Zero(t, auctionTakingAmount.Cmp(parseEther(t, 1.05)))
})

t.Run("0.1 gwei == 0.01% gas fee", func(t *testing.T) {
bump := calculator.CalcRateBump(now, parseUnits(t, 1, 8))
bump := calculator.CalcRateBump(big.NewInt(now), parseUnits(t, 1, 8))
auctionTakingAmount := calculator.CalcAuctionTakingAmount(takingAmount, bump)
assert.Zero(t, auctionTakingAmount.Cmp(parseEther(t, 1.0499)))
})

t.Run("15 gwei == 1.5% gas fee", func(t *testing.T) {
bump := calculator.CalcRateBump(now, parseUnits(t, 15, 9))
bump := calculator.CalcRateBump(big.NewInt(now), parseUnits(t, 15, 9))
auctionTakingAmount := calculator.CalcAuctionTakingAmount(takingAmount, bump)
assert.Zero(t, auctionTakingAmount.Cmp(parseEther(t, 1.035)))
})

t.Run("100 gwei == 10% gas fee", func(t *testing.T) {
bump := calculator.CalcRateBump(now, parseUnits(t, 100, 9))
bump := calculator.CalcRateBump(big.NewInt(now), parseUnits(t, 100, 9))
auctionTakingAmount := calculator.CalcAuctionTakingAmount(takingAmount, bump)
assert.Zero(t, auctionTakingAmount.Cmp(parseEther(t, 1)))
})
Expand Down
80 changes: 80 additions & 0 deletions pkg/oneinch/decode/bytes_iterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package decode

import (
"encoding/binary"
"errors"
)

var ErrOutOfData = errors.New("out of data")

type BytesIterator struct {
data []byte
}

func NewBytesIterator(data []byte) *BytesIterator {
return &BytesIterator{data: data}
}

func (bi *BytesIterator) RemainingData() []byte {
return bi.data
}

func (bi *BytesIterator) HasMore() bool {
return len(bi.data) > 0
}

func (bi *BytesIterator) NextBytes(length int) ([]byte, error) {
if len(bi.data) < length {
return nil, ErrOutOfData
}

result := bi.data[:length]
bi.data = bi.data[length:]

return result, nil
}

func (bi *BytesIterator) NextUint8() (uint8, error) {
result, err := bi.NextBytes(1) // nolint: gomnd
if err != nil {
return 0, err
}

return result[0], nil
}

func (bi *BytesIterator) NextUint16() (uint16, error) {
result, err := bi.NextBytes(2) // nolint: gomnd
if err != nil {
return 0, err
}

return binary.BigEndian.Uint16(result), nil
}

func (bi *BytesIterator) NextUint24() (uint32, error) {
result, err := bi.NextBytes(3) // nolint: gomnd
if err != nil {
return 0, err
}

return binary.BigEndian.Uint32(append([]byte{0}, result...)), nil
}

func (bi *BytesIterator) NextUint32() (uint32, error) {
result, err := bi.NextBytes(4) // nolint: gomnd
if err != nil {
return 0, err
}

return binary.BigEndian.Uint32(result), nil
}

func (bi *BytesIterator) NextUint64() (uint64, error) {
result, err := bi.NextBytes(8) // nolint: gomnd
if err != nil {
return 0, err
}

return binary.BigEndian.Uint64(result), nil
}
19 changes: 19 additions & 0 deletions pkg/oneinch/fusionorder/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fusionorder

import "github.com/ethereum/go-ethereum/common"

const (
addressHalfLength = common.AddressLength / 2
)

type AddressHalf [addressHalfLength]byte

func HalfAddressFromAddress(a common.Address) AddressHalf {
var addressHalf AddressHalf
copy(addressHalf[:], a.Bytes()[common.AddressLength-addressHalfLength:]) // take the last 10 bytes
return addressHalf
}

func AddressFromFirstBytes(s []byte) common.Address {
return common.BytesToAddress(s[:common.AddressLength])
}
Loading

0 comments on commit 213cb3b

Please sign in to comment.