Skip to content

Commit

Permalink
Merge pull request #1 from firstbatchxyz/caglacelik/llm-refactor
Browse files Browse the repository at this point in the history
Added scripts & docs
  • Loading branch information
caglacelik authored Nov 21, 2024
2 parents f64bfc9 + c4088a7 commit 85accaa
Show file tree
Hide file tree
Showing 15 changed files with 327 additions and 112 deletions.
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Deployer key (REQUIRED)
PUBLIC_KEY=

### Base URLs ###
# Mainnet
BASE_MAIN_RPC_URL=

# Testnet
BASE_TEST_RPC_URL=https://sepolia.base.org

# Blockscout API Key
# Foundry expects the API key to be defined as ETHERSCAN_API_KEY
ETHERSCAN_API_KEY=
13 changes: 13 additions & 0 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
LLMOracleCoordinatorTest:test_Deployment() (gas: 86928751)
LLMOracleCoordinatorTest:test_RegisterOracles() (gas: 87213539)
LLMOracleCoordinatorTest:test_ValidatorIsGenerator() (gas: 87630540)
LLMOracleCoordinatorTest:test_WithValidation() (gas: 88289236)
LLMOracleCoordinatorTest:test_WithoutValidation() (gas: 87870279)
LLMOracleRegistryTest:test_Deployment() (gas: 18833944)
LLMOracleRegistryTest:test_RegisterGeneratorOracle() (gas: 19172865)
LLMOracleRegistryTest:test_RegisterValidatorOracle() (gas: 19172934)
LLMOracleRegistryTest:test_RevertWhen_RegisterSameGeneratorTwice() (gas: 19176257)
LLMOracleRegistryTest:test_RevertWhen_RegistryHasNotApprovedByOracle() (gas: 18973195)
LLMOracleRegistryTest:test_RevertWhen_UnregisterSameGeneratorTwice() (gas: 19192397)
LLMOracleRegistryTest:test_UnregisterOracle() (gas: 19189291)
LLMOracleRegistryTest:test_WithdrawStakesAfterUnregistering() (gas: 19214255)
51 changes: 51 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-include .env

.PHONY: build test local-key base-sepolia-key deploy anvil install update doc

# Capture the network name
network := $(word 2, $(MAKECMDGOALS))

# Default to forked base-sepolia network
KEY_NAME := local-key
NETWORK_ARGS := --account local-key --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --broadcast

ifeq ($(network), base-sepolia)
KEY_NAME := base-sepolia-key
NETWORK_ARGS:= --rpc-url $(BASE_TEST_RPC_URL) --account base-sepolia-key --sender $(PUBLIC_KEY) --broadcast --verify --verifier blockscout --verifier-url https://base-sepolia.blockscout.com/api/
endif

# Install Dependencies
install:
forge install foundry-rs/forge-std --no-commit && forge install firstbatchxyz/dria-oracle-contracts --no-commit && forge install OpenZeppelin/openzeppelin-contracts --no-commit && forge install OpenZeppelin/openzeppelin-foundry-upgrades --no-commit && forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit

# Build the contracts
build:
forge clean && forge build

# Generate gas snapshot under snapshots directory
snapshot:
forge snapshot

# Test the contracts on forked base-sepolia network
test:
forge clean && forge test --fork-url $(BASE_TEST_RPC_URL)

anvil:
anvil --fork-url $(BASE_TEST_RPC_URL)

# Create keystores for encrypted private keys by using bls12-381 curve (https://eips.ethereum.org/EIPS/eip-2335)
key:
cast wallet import $(KEY_NAME) --interactive

# Default to local network if no network is specified
deploy:
forge script ./script/Deploy.s.sol:Deploy $(NETWORK_ARGS)

# Generate contract documentation under docs dir. You can also see the docs on http://localhost:4000
doc:
forge doc

# TODO: forge-verify

# Prevent make from interpreting the network name as a target
$(eval $(network):;@:)
122 changes: 86 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,116 @@
## Foundry
# LLM Oracle

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
This document provides instructions for LLM contracts using Foundry.

Foundry consists of:
## Test

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
Compile the contracts:

## Documentation
```sh
make build
```

> [!NOTE]
>
> Please prepare a valid `.env` according to `.env.example` before running tests.
Run tests on forked base-sepolia:

https://book.getfoundry.sh/
```sh
make test
```

## Usage
## Coverage

### Build
Check coverages with:

```shell
$ forge build
```sh
bash coverage.sh
```

### Test
You can see coverages under the coverage directory.

## Storage Layout

Get storage layout with:

```shell
$ forge test
```sh
bash storage.sh
```

### Format
You can see storage layouts under the storage directory.

```shell
$ forge fmt
## Deployment

**Step 1.**
Import your `PUBLIC_KEY` and `ETHERSCAN_API_KEY` to env file.

> [!NOTE]
>
> Foundry expects the API key to be defined as `ETHERSCAN_API_KEY` even though you're using another explorer.
**Step 2.**
Create keystores for deployment. [See more for keystores](https://eips.ethereum.org/EIPS/eip-2335)

```sh
make local-key
```

### Gas Snapshots
or for Base Sepolia

```shell
$ forge snapshot
```sh
make base-sepolia-key
```

### Anvil
> [!NOTE]
>
> Recommended to create keystores on directly on your shell.
> You HAVE to type your password on the terminal to be able to use your keys. (e.g when deploying a contract)
**Step 3.**
Enter your private key (associated with the public key you added to env file) and password on terminal. You'll see your public key on terminal.

```shell
$ anvil
> [!NOTE]
>
> If you want to deploy contracts on localhost please provide localhost public key for the command above.
**Step 4.** Required only for local deployment.

Start a local node with:

```sh
make anvil
```

**Step 5.**
Deploy the contracts on localhost (forked Base Sepolia by default) using Deploy script:

```sh
make deploy
```

### Deploy
or Base Sepolia with the command below:

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```sh
make deploy base-sepolia
```

### Cast
You can see deployed contract addresses under the `deployment/<chainid>.json`

## Gas Snapshot

Take the gas snapshot with:

```shell
$ cast <subcommand>
```sh
make snapshot
```

### Help
You can see the snapshot `.gas-snapshot` file in the current directory.

```shell
$ forge --help
$ anvil --help
$ cast --help
## Generate documentation

```sh
make doc
```

You can see the documentation under the `docs/` directory.
1 change: 1 addition & 0 deletions deployment/31337.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"{ \"LLMOracleRegistry\": { \"proxyAddr\": \"0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0\", \"implAddr\": \"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512\" }, \"LLMOracleCoordinator\": { \"proxyAddr\": \"0xdc64a140aa3e981100a9beca4e685f962f0cf6c9\", \"implAddr\": \"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9\" }"
14 changes: 14 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,19 @@
src = "src"
out = "out"
libs = ["lib"]
test = 'test'
script = 'script'
cache_path = 'cache'
ffi = true
ast = true
build_info = true
optimizer = true
extra_output = ["storageLayout"]
fs_permissions = [{ access = "read", path = "out" }, { access = "write", path = "deployment" }]
remappings = [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/foundry-upgrades=lib/openzeppelin-foundry-upgrades/src",
]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
4 changes: 0 additions & 4 deletions remappings.txt

This file was deleted.

19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

96 changes: 96 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {HelperConfig} from "./HelperConfig.s.sol";
import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol";
import {LLMOracleRegistry} from "../src/LLMOracleRegistry.sol";
import {LLMOracleCoordinator, LLMOracleTaskParameters} from "../src/LLMOracleCoordinator.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Vm} from "forge-std/Vm.sol";

contract Deploy is Script {
// contracts
LLMOracleCoordinator public oracleCoordinator;
LLMOracleRegistry public oracleRegistry;

// implementation addresses
address registryImplementation;
address coordinatorImplementation;

HelperConfig public config;
uint256 chainId;

function run() external {
chainId = block.chainid;
config = new HelperConfig();

vm.startBroadcast();
deployLLM();
vm.stopBroadcast();

writeContractAddresses();
}

function deployLLM() internal {
// get stakes
(uint256 genStake, uint256 valStake) = config.stakes();

// get fees
(uint256 platformFee, uint256 genFee, uint256 valFee) = config.fees();

// deploy llm contracts
address registryProxy = Upgrades.deployUUPSProxy(
"LLMOracleRegistry.sol",
abi.encodeCall(LLMOracleRegistry.initialize, (genStake, valStake, address(config.token())))
);

// wrap proxy with the LLMOracleRegistry
oracleRegistry = LLMOracleRegistry(registryProxy);
registryImplementation = Upgrades.getImplementationAddress(registryProxy);

// deploy coordinator contract
address coordinatorProxy = Upgrades.deployUUPSProxy(
"LLMOracleCoordinator.sol",
abi.encodeCall(
LLMOracleCoordinator.initialize,
(address(oracleRegistry), address(config.token()), platformFee, genFee, valFee)
)
);

oracleCoordinator = LLMOracleCoordinator(coordinatorProxy);
coordinatorImplementation = Upgrades.getImplementationAddress(coordinatorProxy);
}

function writeContractAddresses() internal {
// create a deployment file if not exist
string memory dir = "deployment/";
string memory fileName = Strings.toString(chainId);
string memory path = string.concat(dir, fileName, ".json");

// create dir if not exist
vm.createDir(dir, true);

string memory contracts = string.concat(
"{",
' "LLMOracleRegistry": {',
' "proxyAddr": "',
Strings.toHexString(uint256(uint160(address(oracleRegistry))), 20),
'",',
' "implAddr": "',
Strings.toHexString(uint256(uint160(address(registryImplementation))), 20),
'"',
" },",
' "LLMOracleCoordinator": {',
' "proxyAddr": "',
Strings.toHexString(uint256(uint160(address(oracleCoordinator))), 20),
'",',
' "implAddr": "',
Strings.toHexString(uint256(uint160(address(coordinatorImplementation))), 20),
'"',
" }"
);

vm.writeJson(contracts, path);
}
}
Loading

0 comments on commit 85accaa

Please sign in to comment.