Skip to content

Commit

Permalink
Merge pull request #778 from rainlanguage/2024-08-16-arb-task
Browse files Browse the repository at this point in the history
2024 08 16 arb task
  • Loading branch information
thedavidmeister authored Aug 19, 2024
2 parents 6d88d73 + fcbdfce commit 794bb26
Show file tree
Hide file tree
Showing 36 changed files with 744 additions and 629 deletions.
476 changes: 237 additions & 239 deletions .gas-snapshot

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions .github/workflows/git-clean.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ jobs:
- uses: DeterminateSystems/magic-nix-cache-action@main

# Build metas etc. required to do a correct pointer build.
- run: nix develop -c raindex-prelude

- run: nix develop -c forge script ./script/BuildPointers.sol
- run: ./pointers.sh

# Format the repo after generating pointers so that the pointer files are
# formatted too.
Expand Down
13 changes: 1 addition & 12 deletions .github/workflows/rainix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,7 @@ jobs:
uses: DeterminateSystems/nix-installer-action@v4
- uses: DeterminateSystems/magic-nix-cache-action@v2

- run: nix develop -c rainix-sol-prelude
working-directory: lib/rain.interpreter
- run: nix develop -c rainix-rs-prelude
working-directory: lib/rain.interpreter
- run: nix develop -c rainix-sol-prelude
working-directory: lib/rain.interpreter/lib/rain.metadata
- run: nix develop -c rainix-rs-prelude
working-directory: lib/rain.interpreter/lib/rain.metadata

- run: nix develop -c rainix-sol-prelude
- run: nix develop -c rainix-rs-prelude
- run: nix develop -c raindex-prelude
- run: ./pointers.sh

- name: Run ${{ matrix.task }}
env:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ serde = { workspace = true, features = ["derive", "rc"] }
serde_yaml = { workspace = true }
serde_json = { workspace = true }
strict-yaml-rust = { workspace = true }
alloy = { workspace = true, features = ["serde"] }
alloy = { workspace = true, features = ["serde", "rand"] }
typeshare = { workspace = true }
reqwest = { workspace = true }

[dev-dependencies]
tokio = { workspace = true }
httpmock = "0.7.0"
75 changes: 71 additions & 4 deletions crates/settings/src/config_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,17 @@ impl ConfigSource {
#[cfg(test)]
mod tests {
use super::*;
use httpmock::{Method::GET, MockServer};
use serde_json::json;

#[tokio::test]
async fn parse_yaml_into_configstrings() {
let yaml_data = r#"
let mocked_chain_id_server = MockServer::start_async().await;
let yaml_data = format!(
r#"
using-networks-from:
chainid:
url: https://chainid.network/chains.json
url: {}
format: chainid
networks:
Expand Down Expand Up @@ -341,8 +345,36 @@ deployments:
scenario: mainScenario
order: buyETH
sentry: true"#
.to_string();
sentry: true"#,
mocked_chain_id_server.url("/json")
);

let mocked_chain_id_response = json!([
{
"name": "Ethereum Mainnet",
"chain": "ETH",
"rpc": ["https://abcd.com/v3/${API_KEY}","https://api.mycryptoapi.com/eth","https://cloudflare-eth.com"],
"nativeCurrency": {"name": "Ether","symbol": "ETH","decimals": 18},
"infoURL": "https://ethereum.org",
"shortName": "eth",
"chainId": 1,
"networkId": 1
},
{
"name": "Polygon Mainnet",
"chain": "Polygon",
"rpc": ["https://polygon-rpc.com/","wss://polygon.drpc.org"],
"nativeCurrency": {"name": "MATIC","symbol": "MATIC","decimals": 18},
"infoURL": "https://polygon.technology/",
"shortName": "matic",
"chainId": 137,
"networkId": 137
}
]);
mocked_chain_id_server.mock(|when, then| {
when.method(GET).path("/json");
then.json_body_obj(&mocked_chain_id_response);
});

let config = ConfigSource::try_from_string(yaml_data).await.unwrap();

Expand Down Expand Up @@ -417,4 +449,39 @@ sentry: true"#
assert_eq!(order.deployer, expected_order.deployer);
assert_eq!(order.orderbook, expected_order.orderbook);
}

#[tokio::test]
async fn test_remote_chain_configstrings_unhappy() {
let mocked_chain_id_server = MockServer::start_async().await;
let yaml_data = format!(
r#"
using-networks-from:
chainid:
url: {}
format: chainid"#,
mocked_chain_id_server.url("/json")
);

let mocked_chain_id_response = json!([
{
"name": "Ethereum Mainnet",
"chain": "ETH",
"rpc": ["https://abcd.com, wss://abcd.com/ws"],
"nativeCurrency": {"name": "Ether","symbol": "ETH","decimals": 18},
"infoURL": "https://ethereum.org",
"shortName": "eth",
"chainId": 1,
"networkId": 1
}
]);
mocked_chain_id_server.mock(|when, then| {
when.method(GET).path("/json");
then.json_body_obj(&mocked_chain_id_response);
});

let config = ConfigSource::try_from_string(yaml_data)
.await
.expect_err("expected to fail");
matches!(config, ConfigSourceError::ChainIdError(_));
}
}
2 changes: 0 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ optimizer_runs = 1000000
bytecode_hash = "none"
cbor_metadata = false

evm_version = "cancun"

# Build metadata used for testing rain meta aware contracts in this folder rather
# than expose ffi to forge.
fs_permissions = [
Expand Down
15 changes: 15 additions & 0 deletions pointers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

set -euxo pipefail

(cd lib/rain.interpreter && nix develop -c rainix-sol-prelude)
(cd lib/rain.interpreter && nix develop -c rainix-rs-prelude)
(cd lib/rain.interpreter && nix develop -c i9r-prelude)
(cd lib/rain.interpreter/lib/rain.metadata && nix develop -c rainix-sol-prelude)
(cd lib/rain.interpreter/lib/rain.metadata && nix develop -c rainix-rs-prelude)

nix develop -c rainix-sol-prelude
nix develop -c rainix-rs-prelude
nix develop -c raindex-prelude

nix develop -c forge script script/BuildPointers.sol
29 changes: 21 additions & 8 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
pragma solidity =0.8.25;

import {Script} from "forge-std/Script.sol";
import {OrderBook, EvaluableV3} from "src/concrete/ob/OrderBook.sol";
import {OrderBook, EvaluableV3, TaskV1, SignedContextV1} from "src/concrete/ob/OrderBook.sol";
import {OrderBookSubParser} from "src/concrete/parser/OrderBookSubParser.sol";
import {GenericPoolOrderBookV4ArbOrderTaker} from "src/concrete/arb/GenericPoolOrderBookV4ArbOrderTaker.sol";
import {RouteProcessorOrderBookV4ArbOrderTaker} from "src/concrete/arb/RouteProcessorOrderBookV4ArbOrderTaker.sol";
import {GenericPoolOrderBookV4FlashBorrower} from "src/concrete/arb/GenericPoolOrderBookV4FlashBorrower.sol";
import {OrderBookV4ArbConfigV1} from "src/abstract/OrderBookV4ArbCommon.sol";
import {OrderBookV4ArbConfigV2} from "src/abstract/OrderBookV4ArbCommon.sol";
import {IMetaBoardV1_2} from "rain.metadata/interface/unstable/IMetaBoardV1_2.sol";
import {LibDescribedByMeta} from "rain.metadata/lib/LibDescribedByMeta.sol";
import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/IInterpreterStoreV2.sol";
Expand Down Expand Up @@ -86,23 +86,36 @@ contract Deploy is Script {

// Order takers.
new GenericPoolOrderBookV4ArbOrderTaker(
OrderBookV4ArbConfigV1(
address(raindex), EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), ""), ""
OrderBookV4ArbConfigV2(
address(raindex),
TaskV1({
evaluable: EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), hex""),
signedContext: new SignedContextV1[](0)
}),
""
)
);

new RouteProcessorOrderBookV4ArbOrderTaker(
OrderBookV4ArbConfigV1(
OrderBookV4ArbConfigV2(
address(raindex),
EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), ""),
TaskV1({
evaluable: EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), hex""),
signedContext: new SignedContextV1[](0)
}),
abi.encode(routeProcessor)
)
);

// Flash borrowers.
new GenericPoolOrderBookV4FlashBorrower(
OrderBookV4ArbConfigV1(
raindex, EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), ""), ""
OrderBookV4ArbConfigV2(
raindex,
TaskV1({
evaluable: EvaluableV3(IInterpreterV3(address(0)), IInterpreterStoreV2(address(0)), hex""),
signedContext: new SignedContextV1[](0)
}),
""
)
);
}
Expand Down
6 changes: 3 additions & 3 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ fs.writeFileSync(
"./cjs.js",
'"use strict";\n\nmodule.exports = require("./dist/cjs/index");\n'
);
fs.writeFileSync("./cjs.d.ts", 'export * from "./dist/cjs/index";\n');
fs.writeFileSync("./cjs.d.ts", 'export * from "./dist/types/index";\n');
fs.writeFileSync("./esm.js", 'export * from "./dist/esm/index";\n');
fs.writeFileSync("./esm.d.ts", 'export * from "./dist/esm/index";\n');
fs.writeFileSync("./esm.d.ts", 'export * from "./dist/types/index";\n');

// create dist dir
fs.mkdirSync("./dist/cjs", { recursive: true });
Expand All @@ -20,7 +20,7 @@ execSync("npm run build-wasm");

// build specified packages and include them in final index file
// list of packages to build can be extended by adding new package
// names to the below list
// names to the list below
const packages = ["common", "quote"];
for (const package of packages) {
execSync(`node scripts/buildPackage ${package}`);
Expand Down
56 changes: 15 additions & 41 deletions src/abstract/OrderBookV4ArbCommon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,24 @@ import {
SourceIndexV2,
DEFAULT_STATE_NAMESPACE
} from "rain.interpreter.interface/interface/IInterpreterV3.sol";
import {IOrderBookV4} from "rain.orderbook.interface/interface/IOrderBookV4.sol";
import {IOrderBookV4, TaskV1} from "rain.orderbook.interface/interface/IOrderBookV4.sol";
import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol";
import {LibNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol";
import {LibEvaluable} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol";

/// Thrown when the minimum output for the sender is not met after the arb.
/// @param minimum The minimum output expected by the sender.
/// @param actual The actual output that would be received by the sender.
error MinimumOutput(uint256 minimum, uint256 actual);

/// Thrown when the stack is not empty after the access control dispatch.
error NonZeroBeforeArbStack();

/// Thrown when the lender is not the trusted `OrderBook`.
/// @param badLender The untrusted lender calling `onFlashLoan`.
error BadLender(address badLender);

/// Configuration for an arb contract to construct.
/// @param orderBook The `OrderBook` contract to arb against.
/// @param evaluable The `EvaluableV3` to use as a pre-hook for each arb.
/// @param tasks The tasks to use as post for each arb.
/// @param implementationData The constructor data for the specific
/// implementation of the arb contract.
struct OrderBookV4ArbConfigV1 {
struct OrderBookV4ArbConfigV2 {
address orderBook;
EvaluableV3 evaluable;
TaskV1 task;
bytes implementationData;
}

/// Thrown when the evaluable does not match the expected hash.
error WrongEvaluable();
/// Thrown when the task does not match the expected hash.
error WrongTask();

/// @dev "Before arb" is evaluated before the flash loan is taken. Ostensibly
/// allows for some kind of access control to the arb.
Expand All @@ -45,36 +33,22 @@ SourceIndexV2 constant BEFORE_ARB_SOURCE_INDEX = SourceIndexV2.wrap(0);
abstract contract OrderBookV4ArbCommon {
using LibEvaluable for EvaluableV3;

event Construct(address sender, OrderBookV4ArbConfigV1 config);
event Construct(address sender, OrderBookV4ArbConfigV2 config);

bytes32 public immutable iEvaluableHash;
bytes32 public immutable iTaskHash = 0;

constructor(OrderBookV4ArbConfigV1 memory config) {
constructor(OrderBookV4ArbConfigV2 memory config) {
// Emit events before any external calls are made.
emit Construct(msg.sender, config);

iEvaluableHash = config.evaluable.hash();
if (config.task.evaluable.bytecode.length != 0) {
iTaskHash = keccak256(abi.encode(config.task));
}
}

modifier onlyValidEvaluable(EvaluableV3 calldata evaluable) {
if (evaluable.hash() != iEvaluableHash) {
revert WrongEvaluable();
}
if (evaluable.bytecode.length > 0) {
(uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval3(
evaluable.store,
LibNamespace.qualifyNamespace(DEFAULT_STATE_NAMESPACE, address(this)),
evaluable.bytecode,
BEFORE_ARB_SOURCE_INDEX,
LibContext.build(new uint256[][](0), new SignedContextV1[](0)),
new uint256[](0)
);
// We don't care about the stack.
(stack);
// Persist any state changes from the expression.
if (kvs.length > 0) {
evaluable.store.set(DEFAULT_STATE_NAMESPACE, kvs);
}
modifier onlyValidTask(TaskV1 memory task) {
if (iTaskHash != bytes32(0) && iTaskHash != keccak256(abi.encode(task))) {
revert WrongTask();
}
_;
}
Expand Down
Loading

0 comments on commit 794bb26

Please sign in to comment.