Skip to content

Commit

Permalink
Add some changes to precompile code
Browse files Browse the repository at this point in the history
Add integration testing

Add test scenarios

Add usage script

Add reference to mock and Test
  • Loading branch information
alijnmerchant21 committed Dec 18, 2024
1 parent 745684d commit 54ad7b4
Showing 1 changed file with 181 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ In this section we will create mock precompiles that are essential for testing o

Before you proceed, please create a `mock` directory where these functions will reside.

## Create `mocks/MockSlinkyPrecompile.sol`
## Setting up mock precompiles

### Create `mocks/MockSlinkyPrecompile.sol`

```solidity
// SPDX-License-Identifier: GPL-3.0
Expand All @@ -22,69 +24,68 @@ contract MockSlinkyPrecompile is ISlinky {
function getPrice(
string calldata base,
string calldata quote
)
external
view
returns (GetPriceResponse memory response)
{
) external view returns (GetPriceResponse memory response) {
uint256 price = prices[base][quote];
if (price == 0) {
string memory s1 = string.concat("no price / nonce reported for CurrencyPair: ", base);
string memory s2 = string.concat(s1, "/");
string memory s3 = string.concat(s2, quote);
string memory s4 = string.concat(s3, ", the module is not tracking this CurrencyPair");
revert(s4);
}
QuotePrice memory quotePrice = QuotePrice({ blockHeight: 0, blockTimestamp: 0, price: price });
response = GetPriceResponse({ id: 0, nonce: 0, decimals: 9, price: quotePrice });
}
function setPrice(string calldata base, string calldata quote, uint256 price) external {
prices[base][quote] = price;
require(price != 0, "Price not set");
// NEW: Enhanced price data with additional metadata
QuotePrice memory quotePrice = QuotePrice({
blockHeight: block.number, // Current block for testing
blockTimestamp: block.timestamp,
price: price
});
return GetPriceResponse({
id: 0,
nonce: 0,
decimals: 9,
price: quotePrice
});
}
}
```

## Create `mocks/MockWardenPrecompile.sol`
### Create `mocks/MockWardenPrecompile.sol`

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.25 <0.9.0;
import { BroadcastType, KeyResponse } from "precompile-warden/IWarden.sol";
import { Types } from "precompile-common/Types.sol";
contract MockWardenPrecompile {
mapping(uint64 keyId => KeyResponse keyResponse) private keys;
mapping(uint64 keyId => bool isGood) private goodKeys;
function keyById(uint64 id, int32[] calldata) external view returns (KeyResponse memory key) {
return keys[id];
mapping(uint64 => KeyResponse) private keys;
mapping(uint64 => bool) private goodKeys;
// NEW: Enhanced key response simulation
function keyById(
uint64 id,
int32[] calldata
) external view returns (KeyResponse memory key) {
return KeyResponse({
key: PublicKey({
publicKey: abi.encodePacked(
bytes32(uint256(id)),
bytes32(0)
)
}),
metadata: new bytes(0)
});
}
// NEW: Realistic signing behavior
function newSignRequest(
uint64 keyId,
bytes calldata,
bytes[] calldata,
bytes calldata,
Types.Coin[] calldata,
uint64,
uint64,
string calldata,
string calldata,
BroadcastType
)
external
view
returns (bool isGood)
{
isGood = goodKeys[keyId];
}
function addKey(uint64 keyId, bool isGood) external {
goodKeys[keyId] = isGood;
bytes calldata txHash,
bytes[] calldata analyzers,
bytes calldata encryptionKey,
Types.Coin[] calldata fees,
uint64 spaceNonce,
uint64 actionTimeoutHeight,
string calldata expectedApproveExpression,
string calldata expectedRejectExpression,
BroadcastType broadcastType
) external view returns (bool) {
// Validate inputs
require(txHash.length == 32, "Invalid transaction hash");
require(bytes(expectedApproveExpression).length > 0, "Empty approve expression");
return goodKeys[keyId];
}
}
```
Expand All @@ -102,3 +103,131 @@ These mock contracts simulate the behavior of:
- Key management
- Transaction signing requests
- Key validation

## Integration Testing

### Test Setup Helper

```solidity
contract PrecompileTestHelper {
MockSlinkyPrecompile internal slinky;
MockWardenPrecompile internal warden;
function setUp() public {
// Deploy and configure mocks
slinky = new MockSlinkyPrecompile();
warden = new MockWardenPrecompile();
// Inject mock addresses
vm.etch(ISLINKY_PRECOMPILE_ADDRESS, address(slinky).code);
vm.etch(IWARDEN_PRECOMPILE_ADDRESS, address(warden).code);
}
// NEW: Price scenario helper
function setupPriceScenario(
string memory base,
string memory quote,
uint256 initialPrice,
uint256 targetPrice
) internal {
MockSlinkyPrecompile(ISLINKY_PRECOMPILE_ADDRESS)
.setPrice(base, quote, initialPrice);
// Simulate price change
skip(1 hours);
MockSlinkyPrecompile(ISLINKY_PRECOMPILE_ADDRESS)
.setPrice(base, quote, targetPrice);
}
}
```

## Test Scenarios

### Price Feed Testing

```solidity
contract SlinkyTest is PrecompileTestHelper {
function testPriceMovement() public {
// Setup price scenario
setupPriceScenario("ETH", "USD", 3000e9, 3500e9);
// Test order execution
Types.OrderData memory orderData = createTestOrder(
3200e9, // threshold
Types.PriceCondition.GTE
);
BasicOrder order = new BasicOrder(
orderData,
new CommonTypes.Coin[](0),
address(this),
address(registry)
);
assertTrue(order.canExecute());
}
function testPriceFeedErrors() public {
vm.expectRevert("Price not set");
slinky.getPrice("UNKNOWN", "PAIR");
}
}
```


### Transaction Signing Testing

```solidity
contract WardenTest is PrecompileTestHelper {
function testSigningFlow() public {
// Setup keys
warden.addKey(1, true); // Valid key
warden.addKey(2, false); // Invalid key
// Test successful signing
Types.SignRequestData memory goodRequest = createSignRequest(1);
assertTrue(executeOrder(goodRequest));
// Test failed signing
Types.SignRequestData memory badRequest = createSignRequest(2);
assertFalse(executeOrder(badRequest));
}
function testInvalidInputs() public {
vm.expectRevert("Empty approve expression");
Types.SignRequestData memory invalidRequest = createSignRequest(1);
invalidRequest.expectedApproveExpression = "";
executeOrder(invalidRequest);
}
}
```

## Usage in Scripts

```solidity
contract CreateOrder is Script {
function run(
uint256 thresholdPrice,
Types.PriceCondition priceCondition,
Types.PricePair memory pricePair
) public {
// Setup mock precompiles
MockSlinkyPrecompile mSlinky = new MockSlinkyPrecompile();
MockWardenPrecompile mWarden = new MockWardenPrecompile();
// Configure initial state
vm.etch(ISLINKY_PRECOMPILE_ADDRESS, address(mSlinky).code);
mSlinky.setPrice(pricePair.base, pricePair.quote, thresholdPrice);
vm.etch(IWARDEN_PRECOMPILE_ADDRESS, address(mWarden).code);
mWarden.addKey(1, true);
// Create and verify order
vm.broadcast();
BasicOrder order = createOrder(/* params */);
require(order.canExecute(), "Order cannot execute");
}
}
```

You can learn about mock precompiles in the [Mock Precompiles](https://github.com/warden-protocol/wardenprotocol/tree/main/solidity/orders/mocks) section and test under [Test Scenarios](https://github.com/warden-protocol/wardenprotocol/tree/main/solidity/orders/test)

0 comments on commit 54ad7b4

Please sign in to comment.