diff --git a/precompile/contracts/bibliophile/client.go b/precompile/contracts/bibliophile/client.go index 107f33904d..46271614d9 100644 --- a/precompile/contracts/bibliophile/client.go +++ b/precompile/contracts/bibliophile/client.go @@ -22,6 +22,7 @@ type BibliophileClient interface { GetShortOpenOrdersAmount(trader common.Address, ammIndex *big.Int) *big.Int GetReduceOnlyAmount(trader common.Address, ammIndex *big.Int) *big.Int IsTradingAuthority(trader, senderOrSigner common.Address) bool + IsValidator(senderOrSigner common.Address) bool // Limit Order GetBlockPlaced(orderHash [32]byte) *big.Int GetOrderFilledAmount(orderHash [32]byte) *big.Int @@ -118,6 +119,10 @@ func (b *bibliophileClient) IsTradingAuthority(trader, senderOrSigner common.Add return IsTradingAuthority(b.accessibleState.GetStateDB(), trader, senderOrSigner) } +func (b *bibliophileClient) IsValidator(senderOrSigner common.Address) bool { + return IsValidator(b.accessibleState.GetStateDB(), senderOrSigner) +} + func (b *bibliophileClient) IOC_GetExpirationCap() *big.Int { return iocGetExpirationCap(b.accessibleState.GetStateDB()) } diff --git a/precompile/contracts/bibliophile/client_mock.go b/precompile/contracts/bibliophile/client_mock.go index 6685b8ba77..e14dfebfee 100644 --- a/precompile/contracts/bibliophile/client_mock.go +++ b/precompile/contracts/bibliophile/client_mock.go @@ -432,15 +432,29 @@ func (mr *MockBibliophileClientMockRecorder) IOC_GetOrderStatus(orderHash interf } // IsTradingAuthority mocks base method. -func (m *MockBibliophileClient) IsTradingAuthority(senderOrSigner, trader common.Address) bool { +func (m *MockBibliophileClient) IsTradingAuthority(trader, senderOrSigner common.Address) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsTradingAuthority", senderOrSigner, trader) + ret := m.ctrl.Call(m, "IsTradingAuthority", trader, senderOrSigner) ret0, _ := ret[0].(bool) return ret0 } // IsTradingAuthority indicates an expected call of IsTradingAuthority. -func (mr *MockBibliophileClientMockRecorder) IsTradingAuthority(senderOrSigner, trader interface{}) *gomock.Call { +func (mr *MockBibliophileClientMockRecorder) IsTradingAuthority(trader, senderOrSigner interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTradingAuthority", reflect.TypeOf((*MockBibliophileClient)(nil).IsTradingAuthority), senderOrSigner, trader) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTradingAuthority", reflect.TypeOf((*MockBibliophileClient)(nil).IsTradingAuthority), trader, senderOrSigner) +} + +// IsValidator mocks base method. +func (m *MockBibliophileClient) IsValidator(senderOrSigner common.Address) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsValidator", senderOrSigner) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsValidator indicates an expected call of IsValidator. +func (mr *MockBibliophileClientMockRecorder) IsValidator(senderOrSigner interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsValidator", reflect.TypeOf((*MockBibliophileClient)(nil).IsValidator), senderOrSigner) } diff --git a/precompile/contracts/bibliophile/orderbook.go b/precompile/contracts/bibliophile/orderbook.go index 607174a7b7..c879995f30 100644 --- a/precompile/contracts/bibliophile/orderbook.go +++ b/precompile/contracts/bibliophile/orderbook.go @@ -14,6 +14,7 @@ import ( const ( ORDERBOOK_GENESIS_ADDRESS = "0x0300000000000000000000000000000000000000" ORDER_INFO_SLOT int64 = 53 + IS_VALIDATOR_SLOT int64 = 54 REDUCE_ONLY_AMOUNT_SLOT int64 = 55 IS_TRADING_AUTHORITY_SLOT int64 = 61 LONG_OPEN_ORDERS_SLOT int64 = 65 @@ -79,6 +80,11 @@ func IsTradingAuthority(stateDB contract.StateDB, trader, senderOrSigner common. return stateDB.GetState(common.HexToAddress(ORDERBOOK_GENESIS_ADDRESS), common.BytesToHash(tradingAuthorityMappingSlot)).Big().Cmp(big.NewInt(1)) == 0 } +func IsValidator(stateDB contract.StateDB, senderOrSigner common.Address) bool { + isValidatorMappingSlot := crypto.Keccak256(append(common.LeftPadBytes(senderOrSigner.Bytes(), 32), common.LeftPadBytes(big.NewInt(IS_VALIDATOR_SLOT).Bytes(), 32)...)) + return stateDB.GetState(common.HexToAddress(ORDERBOOK_GENESIS_ADDRESS), common.BytesToHash(isValidatorMappingSlot)).Big().Cmp(big.NewInt(1)) == 0 +} + // Business Logic func ValidateOrdersAndDetermineFillPrice(stateDB contract.StateDB, inputStruct *ValidateOrdersAndDetermineFillPriceInput) (*ValidateOrdersAndDetermineFillPriceOutput, error) { diff --git a/precompile/contracts/juror/contract.go b/precompile/contracts/juror/contract.go index 75766c777b..be92b10d3d 100644 --- a/precompile/contracts/juror/contract.go +++ b/precompile/contracts/juror/contract.go @@ -441,7 +441,7 @@ func validateCancelLimitOrder(accessibleState contract.AccessibleState, caller c } // CUSTOM CODE STARTS HERE bibliophile := bibliophile.NewBibliophileClient(accessibleState) - output := ValidateCancelLimitOrderV2(bibliophile, &inputStruct) + output := ValidateCancelLimitOrderV2(bibliophile, &inputStruct, new(big.Int).SetUint64(accessibleState.GetBlockContext().Timestamp())) packedOutput, err := PackValidateCancelLimitOrderOutput(*output) if err != nil { return nil, remainingGas, err diff --git a/precompile/contracts/juror/contract_test.go b/precompile/contracts/juror/contract_test.go index 7aa7a0ff63..447cb2bf08 100644 --- a/precompile/contracts/juror/contract_test.go +++ b/precompile/contracts/juror/contract_test.go @@ -1636,14 +1636,14 @@ func TestValidateCancelLimitOrder(t *testing.T) { order := getOrder(ammIndex, trader, longBaseAssetQuantity, price, salt, reduceOnly, postOnly) input := getValidateCancelLimitOrderInput(order, sender, assertLowMargin) mockBibliophile.EXPECT().IsTradingAuthority(order.Trader, sender).Return(false).Times(1) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, ErrNoTradingAuthority.Error(), output.Err) }) t.Run("it returns error for a short order", func(t *testing.T) { order := getOrder(ammIndex, trader, shortBaseAssetQuantity, price, salt, reduceOnly, postOnly) input := getValidateCancelLimitOrderInput(order, sender, assertLowMargin) mockBibliophile.EXPECT().IsTradingAuthority(order.Trader, sender).Return(false).Times(1) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, ErrNoTradingAuthority.Error(), output.Err) }) }) @@ -1655,7 +1655,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(longOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Invalid)).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Invalid", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1666,7 +1666,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(shortOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Invalid)).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Invalid", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1679,7 +1679,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(longOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Cancelled)).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Cancelled", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1690,7 +1690,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(shortOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Cancelled)).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Cancelled", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1703,7 +1703,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(longOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Filled)).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Filled", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1714,7 +1714,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { orderHash := getOrderV2Hash(shortOrder) mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Filled)).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Filled", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1734,7 +1734,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Placed)).Times(1) mockBibliophile.EXPECT().GetAvailableMargin(longOrder.Trader).Return(big.NewInt(0)).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Not Low Margin", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1747,7 +1747,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Placed)).Times(1) mockBibliophile.EXPECT().GetAvailableMargin(shortOrder.Trader).Return(big.NewInt(0)).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Not Low Margin", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) @@ -1764,7 +1764,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Placed)).Times(1) mockBibliophile.EXPECT().GetAvailableMargin(longOrder.Trader).Return(newMargin).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Not Low Margin", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1777,7 +1777,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(Placed)).Times(1) mockBibliophile.EXPECT().GetAvailableMargin(shortOrder.Trader).Return(newMargin).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "Not Low Margin", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, common.Address{}, output.Res.Amm) @@ -1797,7 +1797,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(longOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1813,7 +1813,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(shortOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1832,7 +1832,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(longOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1850,7 +1850,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(shortOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1872,7 +1872,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(longOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1887,7 +1887,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(shortOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1905,7 +1905,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(longOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(longOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) @@ -1922,7 +1922,7 @@ func TestValidateCancelLimitOrder(t *testing.T) { mockBibliophile.EXPECT().GetMarketAddressFromMarketID(shortOrder.AmmIndex.Int64()).Return(ammAddress).Times(1) input := getValidateCancelLimitOrderInput(shortOrder, trader, assertLowMargin) - output := ValidateCancelLimitOrderV2(mockBibliophile, &input) + output := ValidateCancelLimitOrderV2(mockBibliophile, &input, nil) assert.Equal(t, "", output.Err) assert.Equal(t, orderHash, common.BytesToHash(output.OrderHash[:])) assert.Equal(t, ammAddress, output.Res.Amm) diff --git a/precompile/contracts/juror/logic.go b/precompile/contracts/juror/logic.go index abd5a9c829..6abd3a6df5 100644 --- a/precompile/contracts/juror/logic.go +++ b/precompile/contracts/juror/logic.go @@ -514,8 +514,8 @@ func GetBaseQuote(bibliophile b.BibliophileClient, ammAddress common.Address, qu } // Limit Orders V2 -func ValidateCancelLimitOrderV2(bibliophile b.BibliophileClient, inputStruct *ValidateCancelLimitOrderInput) *ValidateCancelLimitOrderOutput { - errorString, orderHash, ammAddress, unfilledAmount := validateCancelLimitOrderV2(bibliophile, inputStruct.Order, inputStruct.Trader, inputStruct.AssertLowMargin) +func ValidateCancelLimitOrderV2(bibliophile b.BibliophileClient, inputStruct *ValidateCancelLimitOrderInput, blockTimestamp *big.Int) *ValidateCancelLimitOrderOutput { + errorString, orderHash, ammAddress, unfilledAmount := validateCancelLimitOrderV2(bibliophile, inputStruct.Order, inputStruct.Trader, inputStruct.AssertLowMargin, blockTimestamp) return &ValidateCancelLimitOrderOutput{ Err: errorString, OrderHash: orderHash, @@ -526,12 +526,23 @@ func ValidateCancelLimitOrderV2(bibliophile b.BibliophileClient, inputStruct *Va } } -func validateCancelLimitOrderV2(bibliophile b.BibliophileClient, order ILimitOrderBookOrderV2, sender common.Address, assertLowMargin bool) (errorString string, orderHash [32]byte, ammAddress common.Address, unfilledAmount *big.Int) { +// Sunday, 3 September 2023 10:35:00 UTC +var V4ActivationDate *big.Int = new(big.Int).SetInt64(1693737300) + +func validateCancelLimitOrderV2(bibliophile b.BibliophileClient, order ILimitOrderBookOrderV2, sender common.Address, assertLowMargin bool, blockTimestamp *big.Int) (errorString string, orderHash [32]byte, ammAddress common.Address, unfilledAmount *big.Int) { unfilledAmount = big.NewInt(0) trader := order.Trader - if trader != sender && !bibliophile.IsTradingAuthority(trader, sender) { - errorString = ErrNoTradingAuthority.Error() - return + if blockTimestamp != nil && blockTimestamp.Cmp(V4ActivationDate) == 1 { + if (!assertLowMargin && trader != sender && !bibliophile.IsTradingAuthority(trader, sender)) || + (assertLowMargin && !bibliophile.IsValidator(sender)) { + errorString = ErrNoTradingAuthority.Error() + return + } + } else { + if trader != sender && !bibliophile.IsTradingAuthority(trader, sender) { + errorString = ErrNoTradingAuthority.Error() + return + } } orderHash, err := GetLimitOrderV2Hash(&order) if err != nil {