-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement TakerTraits type for 1inch limit order (#79)
* Implement TakerTraits type for 1inch limit order
- Loading branch information
Showing
8 changed files
with
244 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package limitorder | ||
|
||
import ( | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
) | ||
|
||
type AmountMode uint | ||
|
||
const ( | ||
makerAmountFlag = 255 | ||
argsHasReceiver = 251 | ||
|
||
AmountModeTaker AmountMode = 0 | ||
AmountModeMaker AmountMode = 1 | ||
) | ||
|
||
//nolint:gochecknoglobals,gomnd,mnd | ||
var ( | ||
// 224-247 bits `ARGS_EXTENSION_LENGTH` - The length of the extension calldata in the args. | ||
argsExtensionLenMask = newBitMask(224, 248) | ||
// 200-223 bits `ARGS_INTERACTION_LENGTH` - The length of the interaction calldata in the args. | ||
argsInteractionLenMask = newBitMask(200, 224) | ||
// 0-184 bits - The threshold amount. | ||
amountThresholdMask = newBitMask(0, 185) | ||
) | ||
|
||
type TakerTraits struct { | ||
flags *big.Int | ||
receiver *common.Address | ||
extension *Extension | ||
interaction *Interaction | ||
} | ||
|
||
func NewTakerTraits( | ||
flags *big.Int, receiver *common.Address, extension *Extension, interaction *Interaction, | ||
) *TakerTraits { | ||
return &TakerTraits{ | ||
flags: flags, | ||
receiver: receiver, | ||
extension: extension, | ||
interaction: interaction, | ||
} | ||
} | ||
|
||
func NewDefaultTakerTraits() *TakerTraits { | ||
return &TakerTraits{ | ||
flags: new(big.Int), | ||
} | ||
} | ||
|
||
func (t *TakerTraits) SetAmountMode(mode AmountMode) *TakerTraits { | ||
t.flags.SetBit(t.flags, makerAmountFlag, uint(mode)) | ||
return t | ||
} | ||
|
||
// SetAmountThreshold sets threshold amount. | ||
// | ||
// In taker amount mode: the minimum amount a taker agrees to receive in exchange for a taking amount. | ||
// In maker amount mode: the maximum amount a taker agrees to give in exchange for a making amount. | ||
func (t *TakerTraits) SetAmountThreshold(threshold *big.Int) *TakerTraits { | ||
setMask(t.flags, amountThresholdMask, threshold) | ||
return t | ||
} | ||
|
||
// SetExtension sets extension, it is required to provide same extension as in order creation (if any). | ||
func (t *TakerTraits) SetExtension(ext Extension) *TakerTraits { | ||
t.extension = &ext | ||
return t | ||
} | ||
|
||
func (t *TakerTraits) Encode() (common.Hash, []byte) { | ||
var extension, interaction []byte | ||
if t.extension != nil { | ||
extension = t.extension.Encode() | ||
} | ||
if t.interaction != nil { | ||
interaction = t.interaction.Encode() | ||
} | ||
|
||
flags := new(big.Int).Set(t.flags) | ||
if t.receiver != nil { | ||
flags.SetBit(flags, argsHasReceiver, 1) | ||
} | ||
|
||
// Set length for extension and interaction. | ||
setMask(flags, argsExtensionLenMask, big.NewInt(int64(len(extension)))) | ||
setMask(flags, argsInteractionLenMask, big.NewInt(int64(len(interaction)))) | ||
|
||
var args []byte | ||
if t.receiver == nil { | ||
args = make([]byte, 0, len(extension)+len(interaction)) | ||
} else { | ||
args = make([]byte, 0, len(t.receiver)+len(extension)+len(interaction)) | ||
args = append(args, t.receiver.Bytes()...) | ||
} | ||
args = append(append(args, extension...), interaction...) | ||
|
||
return common.BigToHash(flags), args | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//nolint:testpackage | ||
package limitorder | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
//nolint:lll | ||
func TestEncodeTakerTraits(t *testing.T) { | ||
extension := Extension{ | ||
MakerAssetSuffix: []byte{0x01}, | ||
TakerAssetSuffix: []byte{0x02}, | ||
MakingAmountData: []byte{0x03}, | ||
TakingAmountData: []byte{0x04}, | ||
Predicate: []byte{0x05}, | ||
MakerPermit: []byte{0x06}, | ||
PreInteraction: []byte{0x07}, | ||
PostInteraction: []byte{0x08}, | ||
CustomData: []byte{0xff}, | ||
} | ||
|
||
takerTraits := NewDefaultTakerTraits() | ||
takerTraits.SetExtension(extension).SetAmountMode(AmountModeMaker).SetAmountThreshold(big.NewInt(1)) | ||
|
||
encodedTakerTraits, args := takerTraits.Encode() | ||
assert.Equal(t, common.HexToHash("0x8000002900000000000000000000000000000000000000000000000000000001"), encodedTakerTraits) | ||
assert.Equal(t, hexutil.Encode(extension.Encode()), hexutil.Encode(args)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package limitorder | ||
|
||
import "math/big" | ||
|
||
func newBitMask(start uint, end uint) *big.Int { | ||
mask := big.NewInt(1) | ||
mask.Lsh(mask, end) | ||
mask.Sub(mask, big.NewInt(1)) | ||
if start == 0 { | ||
return mask | ||
} | ||
|
||
notMask := newBitMask(0, start) | ||
notMask.Not(notMask) | ||
mask.And(mask, notMask) | ||
|
||
return mask | ||
} | ||
|
||
func setMask(n *big.Int, mask *big.Int, value *big.Int) { | ||
// Clear bits in range. | ||
n.And(n, new(big.Int).Not(mask)) | ||
|
||
// Shift value to correct position and ensure value fits in mask. | ||
value = new(big.Int).Lsh(value, mask.TrailingZeroBits()) | ||
value.And(value, mask) | ||
|
||
// Set the bits in range. | ||
n.Or(n, value) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//nolint:testpackage | ||
package limitorder | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewBitMask(t *testing.T) { | ||
tests := []struct { | ||
start uint | ||
end uint | ||
expect *big.Int | ||
}{ | ||
{ | ||
start: 0, | ||
end: 10, | ||
expect: big.NewInt(0b1111111111), | ||
}, | ||
{ | ||
start: 5, | ||
end: 17, | ||
expect: big.NewInt(0b11111111111100000), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
assert.Equal(t, test.expect, newBitMask(test.start, test.end)) | ||
} | ||
} | ||
|
||
func TestSetMask(t *testing.T) { | ||
tests := []struct { | ||
n *big.Int | ||
mask *big.Int | ||
value *big.Int | ||
expect *big.Int | ||
}{ | ||
{ | ||
n: big.NewInt(0b1111111111111110101111111111100111), | ||
mask: newBitMask(0, 10), | ||
value: big.NewInt(0b0011110101), | ||
expect: big.NewInt(0b1111111111111110101111110011110101), | ||
}, | ||
{ | ||
n: big.NewInt(0b1111111111111110101111111111100111), | ||
mask: newBitMask(0, 10), | ||
value: big.NewInt(0b11110011110101), | ||
expect: big.NewInt(0b1111111111111110101111110011110101), | ||
}, | ||
{ | ||
n: big.NewInt(0b1111111111111110101111111111100111), | ||
mask: newBitMask(5, 15), | ||
value: big.NewInt(0b0011110101), | ||
expect: big.NewInt(0b1111111111111110101001111010100111), | ||
}, | ||
{ | ||
n: big.NewInt(0b1111111111111110101111111111100111), | ||
mask: newBitMask(5, 15), | ||
value: big.NewInt(0b11110011110101), | ||
expect: big.NewInt(0b1111111111111110101001111010100111), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
setMask(test.n, test.mask, test.value) | ||
assert.Equal(t, test.expect, test.n, "expect: %s, actual: %s", test.expect.Text(2), test.n.Text(2)) | ||
} | ||
} |