Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
{
// solidity
"solidity.packageDefaultDependenciesContractsDirectory": "src",
"solidity.packageDefaultDependenciesDirectory": "lib",
"editor.formatOnSave": true,
"[solidity]": {
"editor.defaultFormatter": "JuanBlanco.solidity"
},
"solidity.formatter": "forge",
"solidity.compileUsingRemoteVersion": "v0.8.26",
"solidity.defaultCompiler": "localFile"
"solidity.defaultCompiler": "localFile",
// remappings.txt here fixes random errors
"solidity.remappingsUnix": [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
],
"material-icon-theme.files.associations": {
".gas-snapshot": "bench-ts"
}
}
72 changes: 36 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ To interact with the blockchain, we require an RPC endpoint. You can get one fro

You will use this endpoint for the commands that interact with the blockchain, such as deploying and upgrading; or while doing fork tests.

### Deploy & Verify Contract
### Deploy Contract

Deploy the contract with:

Expand All @@ -116,9 +116,23 @@ forge script ./script/Deploy.s.sol:Deploy<CONTRACT_NAME> \
--broadcast
```

You can see deployed contract addresses under the `deployment/<chainid>.json`
You can see deployed contract addresses under the [`deployments/<chainid>.json`](./deployments/) folder.

You can verify the contract during deployment by adding the verification arguments as well:
You will need the contract ABIs to interact with them as well, thankfully there is a nice short-hand command to export that:

```sh
forge inspect <CONTRACT_NAME> abi > ./deployments/abis/<CONTRACT_NAME>.json
```

### Verify Contract

Verification requires the following values, based on which provider you are using:

- **Provider**: can accept any of `etherscan`, `blockscout`, `sourcify`, `oklink` or `custom` for more fine-grained stuff.
- **URL**: based on the chosen provider, we require its URL as well, e.g. `https://base-sepolia.blockscout.com/api/` for `blockscout` on Base Sepolia
- **API Key**: an API key from the chosen provider, must be stored as `ETHERSCAN_API_KEY` in environment no matter whicih provider it is!.

You can actually verify the contract during deployment by adding the verification arguments as well:

```sh
forge script ./script/Deploy.s.sol:Deploy<CONTRACT_NAME> \
Expand All @@ -129,39 +143,35 @@ forge script ./script/Deploy.s.sol:Deploy<CONTRACT_NAME> \
--verifier-url <VERIFIER_URL>
```

You can verify an existing contract with:
Alternatively, you can verify an existing contract (perhaps deployed from a factory) with:

```sh
forge verify-contract <CONTRACT_ADDRESS> ./src/<CONTRACT_NAME>.sol:<CONTRACT_NAME> \
--verifier blockscout \
--verifier-url <VERIFIER_URL>
--verifier blockscout --verifier-url <VERIFIER_URL>
```

Note that the `--verifier-url` value should be the target explorer's homepage URL. Some example URLs are:

- `https://base.blockscout.com/api/` for Base (Mainnet)
- `https://base-sepolia.blockscout.com/api/` for Base Sepolia (Testnet)

> [!NOTE]
>
> URL should not contain the API key! Foundry will read your `ETHERSCAN_API_KEY` from environment.

> [!NOTE]
>
> The `--verifier` can accept any of the following: `etherscan`, `blockscout`, `sourcify`, `oklink`. We are using Blockscout most of the time.
### Upgrade Contract

### Generate ABIs
Upgrading an existing contract is done as per the instructions in [openzeppelin-foundry-upgrades](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades) repository.

To interact with the contracts, you need the contract ABIs. We store the ABIs under the [`abis`](./abis/) folder, and these can be generated using the following script:
First, we create a new contract with its name as `ContractNameV2`, and then we execute the following command:

```sh
./export-abis.sh
forge script ./script/Deploy.s.sol:Upgrade<CONTRACT_NAME> \
--rpc-url <RPC_URL> \
--account <WALLET_NAME> --broadcast \
--sender <WALLET_ADDRESS> \
--verify --verifier blockscout \
--verifier-url <VERIFIER_URL>
```

### Upgrade Contract

Upgrading an existing contract is done as per the instructions in [openzeppelin-foundry-upgrades](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades) repository.
The `--sender <ADDRESS>` field is required when deploying a contract,
> [!NOTE]
>
> The `--sender <ADDRESS>` field is mandatory when deploying a contract, it can be obtained with the command below, which will prompt for keystore password:
>
> ```sh
> cast wallet address --account <WALLET_NAME>
> ```

## Testing & Diagnostics

Expand Down Expand Up @@ -194,16 +204,6 @@ Alternatively, you can see a summarized text-only output as well:
forge coverage --no-match-coverage "(test|mock|script)"
```

### Storage Layout

You can print storage layouts for each contract using:

```sh
./storage.sh
```

The resulting Markdown files will be created under the [`storage`](./storage/) directory.

### Gas Snapshot

You can examine the gas usage metrics using the command:
Expand All @@ -225,7 +225,7 @@ forge fmt ./src/**/*.sol ./script/**/*.sol
If you have solhint installed, you can lint all contracts with:

```sh
solhint 'contracts/**/*.sol'
solhint 'src/**/*.sol'
```

## Documentation
Expand Down
24 changes: 0 additions & 24 deletions abis/parseAbi.cjs

This file was deleted.

136 changes: 68 additions & 68 deletions broadcast/Deploy.s.sol/84532/run-latest.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion deployment/.gitignore

This file was deleted.

1 change: 1 addition & 0 deletions deployments/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
31337/
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -1192,4 +1192,4 @@
}
]
}
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -585,4 +585,4 @@
}
]
}
]
]
8 changes: 0 additions & 8 deletions export-abis.sh

This file was deleted.

2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ force = true
# fs permissions for deployment (false by default)
fs_permissions = [
{ access = "read", path = "out" },
{ access = "read-write", path = "deployment" },
{ access = "read-write", path = "deployments" },
]
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
61 changes: 37 additions & 24 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {Upgrades, UnsafeUpgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol";
import {Upgrades, UnsafeUpgrades, Options} from "@openzeppelin/foundry-upgrades/Upgrades.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
Expand Down Expand Up @@ -32,13 +32,13 @@ contract DeployLLMOracleRegistry is Script {

function run() external returns (address proxy, address impl) {
vm.startBroadcast();
(proxy, impl) = this.deploy();
(proxy, impl) = deploy();
vm.stopBroadcast();

helper.writeProxyAddresses("LLMOracleRegistry", proxy, impl);
}

function deploy() external returns (address proxy, address impl) {
function deploy() public returns (address proxy, address impl) {
proxy = Upgrades.deployUUPSProxy(
"LLMOracleRegistry.sol",
abi.encodeCall(
Expand Down Expand Up @@ -82,7 +82,7 @@ contract DeployLLMOracleCoordinator is Script {
token = address(0x4200000000000000000000000000000000000006);
}

function run() external returns (address proxy, address impl) {
function run() public {
// read registry address
string memory deployments = helper.getDeploymentsJson();
require(vm.keyExistsJson(deployments, "$.LLMOracleRegistry"), "Please deploy LLMOracleRegistry first");
Expand All @@ -92,13 +92,13 @@ contract DeployLLMOracleCoordinator is Script {
require(registryImlp != address(0), "LLMOracleRegistry implementation address is invalid");

vm.startBroadcast();
(proxy, impl) = this.deploy(registryProxy);
(address proxy, address impl) = deploy(registryProxy);
vm.stopBroadcast();

helper.writeProxyAddresses("LLMOracleCoordinator", proxy, impl);
}

function deploy(address registryAddr) external returns (address proxy, address impl) {
function deploy(address registryAddr) public returns (address proxy, address impl) {
proxy = Upgrades.deployUUPSProxy(
"LLMOracleCoordinator.sol",
abi.encodeCall(
Expand All @@ -111,37 +111,50 @@ contract DeployLLMOracleCoordinator is Script {
}
}

contract UpgradeLLMOracleRegistry is Script {
contract UpgradeLLMOracleCoordinator is Script {
Helper public helper;
Stakes public stakes;
uint256 public minRegistrationTimeSec;
address public token;

constructor() {
helper = new Helper();
}

// parameters
minRegistrationTimeSec = 1 days;
stakes = Stakes({generator: 0.0001 ether, validator: 0.000001 ether});
token = address(0x4200000000000000000000000000000000000006); // WETH
function run() public returns (address impl) {
// todo: get proxy address
address proxy = 0xe3Ab5D57Feb189d7CD1685336FD638856391b9EB;

vm.startBroadcast();
impl = upgrade(proxy);
vm.stopBroadcast();

helper.writeProxyAddresses("LLMOracleCoordinator", proxy, impl);
}

function run() external returns (address proxy, address impl) {
function upgrade(address proxy) public returns (address impl) {
Upgrades.upgradeProxy(proxy, "LLMOracleCoordinatorV2.sol", "");
impl = Upgrades.getImplementationAddress(proxy);
}
}

contract UpgradeLLMOracleRegistry is Script {
Helper public helper;

constructor() {
helper = new Helper();
}

function run() public returns (address impl) {
// todo: get proxy address
address proxy = 0x568Cfb5363E70Cde784f8603E2748e614c3420a7;

vm.startBroadcast();
(proxy, impl) = this.deploy();
impl = upgrade(proxy);
vm.stopBroadcast();

helper.writeProxyAddresses("LLMOracleRegistry", proxy, impl);
}

function deploy() external returns (address proxy, address impl) {
proxy = Upgrades.deployUUPSProxy(
"LLMOracleRegistry.sol",
abi.encodeCall(
LLMOracleRegistry.initialize, (stakes.generator, stakes.validator, token, minRegistrationTimeSec)
)
);

function upgrade(address proxy) public returns (address impl) {
Upgrades.upgradeProxy(proxy, "LLMOracleRegistryV2.sol", "");
impl = Upgrades.getImplementationAddress(proxy);
}
}
11 changes: 5 additions & 6 deletions script/Helper.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ contract Helper is Script {
/// @dev You are expect to use JSON-related commands with the returned string,
/// see https://book.getfoundry.sh/cheatcodes/external for more.
function getDeploymentsJson() external view returns (string memory) {
string memory dir = "deployment/";
string memory fileName = Strings.toString(block.chainid);
string memory path = string.concat(dir, fileName, ".json");
string memory chainId = Strings.toString(block.chainid);
string memory path = string.concat("deployments/", chainId, "addresses.json");

return vm.readFile(path);
}

function writeProxyAddresses(string memory name, address _proxy, address _impl) external {
// create a deployment file if not exist
string memory dir = "deployment/";
string memory fileName = Strings.toString(block.chainid);
string memory path = string.concat(dir, fileName, ".json");
string memory dir = "deployments/";
string memory chainId = Strings.toString(block.chainid);
string memory path = string.concat(dir, chainId, ".json");

string memory proxy = Strings.toHexString(uint256(uint160(_proxy)), 20);
string memory impl = Strings.toHexString(uint256(uint160(_impl)), 20);
Expand Down
22 changes: 0 additions & 22 deletions storage.sh

This file was deleted.

2 changes: 1 addition & 1 deletion test/LLMOracleCoordinator.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol";

import {LLMOracleTask, LLMOracleTaskParameters} from "../src/LLMOracleTask.sol";
import {LLMOracleRegistry, LLMOracleKind} from "../src/LLMOracleRegistry.sol";
Expand Down
2 changes: 1 addition & 1 deletion test/LLMOracleRegistry.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol";

import {LLMOracleRegistry, LLMOracleKind} from "../src/LLMOracleRegistry.sol";

Expand Down
3 changes: 2 additions & 1 deletion test/Statistics.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pragma solidity ^0.8.20;

import {Vm} from "forge-std/Vm.sol";
import {Test, console} from "forge-std/Test.sol";
import {Statistics} from "../src/Statistics.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

import {Statistics} from "../src/Statistics.sol";

contract StatisticsTest is Test {
uint8 constant MAX_SCORE = 255; // max value of uint8
uint8 constant MIN_SCORE = 1;
Expand Down
Loading
Loading