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
86 changes: 73 additions & 13 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,25 +1,85 @@
# Wallet Configuration

PRIVATE_KEY="YOUR_PRIVATE_KEY"
# or

MNEMONIC="YOUR_MNEMONIC"

EOA_INDEX=0 # Optional (Default to 0)

CHAINS="sepolia,base-sepolia,arbitrum-sepolia" # Chains to deploy
# Deployment Configuration

CHAINS="ethereum,optimism,base,arbitrum" # Chains to deploy

# Etherscan

ALCHEMY_API_KEY="YOUR_ALCHEMY_API_KEY"
ETHERSCAN_API_KEY="YOUR_ETHERSCAN_API_KEY"

RPC_ETHEREUM="https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_SEPOLIA="https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
# RPC Provider

# Using Alchemy RPC URL

RPC_API_KEY="YOUR_ALCHEMY_API_KEY"

RPC_ETHEREUM="https://eth-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_SEPOLIA="https://eth-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_OPTIMISM="https://opt-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_OPTIMISM_SEPOLIA="https://opt-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_BNB="https://bnb-mainnet.g.alchemy.com/v2//${RPC_API_KEY}"
RPC_BNB_TESTNET="https://bnb-testnet.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_UNICHAIN="https://unichain-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_UNICHAIN_SEPOLIA="https://unichain-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_POLYGON="https://polygon-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_POLYGON_AMOY="https://polygon-amoy.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_BASE="https://base-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_BASE_SEPOLIA="https://base-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_ARBITRUM="https://arb-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_ARBITRUM_SEPOLIA="https://arb-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_AVALANCHE="https://avax-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_AVALANCHE_FUJI="https://avax-fuji.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_LINEA="https://linea-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_LINEA_SEPOLIA="https://linea-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

RPC_SCROLL="https://scroll-mainnet.g.alchemy.com/v2/${RPC_API_KEY}"
RPC_SCROLL_SEPOLIA="https://scroll-sepolia.g.alchemy.com/v2/${RPC_API_KEY}"

# Using Infura RPC URL

RPC_API_KEY="YOUR_INFURA_API_KEY"

RPC_ETHEREUM="https://mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_SEPOLIA="https://sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_OPTIMISM="https://optimism-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_OPTIMISM_SEPOLIA="https://optimism-sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_BNB="https://bsc-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_BNB_TESTNET="https://bsc-testnet.infura.io/v3/${RPC_API_KEY}"

RPC_UNICHAIN="https://unichain-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_UNICHAIN_SEPOLIA="https://unichain-sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_POLYGON="https://polygon-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_POLYGON_AMOY="https://polygon-amoy.infura.io/v3/${RPC_API_KEY}"

RPC_BASE="https://base-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_BASE_SEPOLIA="https://base-sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_OPTIMISM="https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_OPTIMISM_SEPOLIA="https://opt-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_ARBITRUM="https://arbitrum-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_ARBITRUM_SEPOLIA="https://arbitrum-sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_POLYGON="https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_POLYGON_AMOY="https://polygon-amoy.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_AVALANCHE="https://avalanche-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_AVALANCHE_FUJI="https://avalanche-fuji.infura.io/v3/${RPC_API_KEY}"

RPC_BASE="https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_BASE_SEPOLIA="https://base-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_LINEA="https://linea-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_LINEA_SEPOLIA="https://linea-sepolia.infura.io/v3/${RPC_API_KEY}"

RPC_ARBITRUM="https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_ARBITRUM_SEPOLIA="https://arb-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
RPC_SCROLL="https://scroll-mainnet.infura.io/v3/${RPC_API_KEY}"
RPC_SCROLL_SEPOLIA="https://scroll-sepolia.infura.io/v3/${RPC_API_KEY}"
15 changes: 14 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ jobs:
with:
submodules: recursive

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18

- name: Install NPM dependencies
run: npm install
working-directory: script/ts

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

Expand All @@ -32,6 +41,10 @@ jobs:
- name: Run Forge tests
env:
RPC_ETHEREUM: ${{ secrets.RPC_ETHEREUM }}
RPC_OPTIMISM: ${{ secrets.RPC_OPTIMISM }}
RPC_POLYGON: ${{ secrets.RPC_POLYGON }}
RPC_BASE: ${{ secrets.RPC_BASE }}
RPC_ARBITRUM: ${{ secrets.RPC_ARBITRUM }}
run: |
forge test -vvv
forge test -vvv --ffi
id: test
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
foundry.toml
out/
lib/
cache/
cache/
.github/
62 changes: 28 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ If a direct price feed doesn’t exist, the router derives the price through int

### Key Features

- **Direct and Multi-Hop Price Resolution**
Automatically finds the shortest feed path between two assets using a breadth-first traversal
- **Price Derivation Engine**
Supports derived price computation (A/B = A/C \* C/B), feed inversion, and precision normalization
- **Bitmap-Based Graph Storage**
Assets are tracked in a paged bitmap structure for efficient gas usage and scalable pathfinding
- **Batch Feed and Asset Management**
Efficiently register or deregister multiple feeds in single transactions
- **Direct and Multi-Hop Price Resolution**
Automatically finds the shortest feed path between two assets using a breadth-first traversal
- **Price Derivation Engine**
Supports derived price computation (A/B = A/C \* C/B), feed inversion, and precision normalization
- **Bitmap-Based Graph Storage**
Assets are tracked in a paged bitmap structure for efficient gas usage and scalable pathfinding
- **Batch Feed and Asset Management**
Efficiently register or deregister multiple feeds in single transactions

## Deployment

You can checkout the deployment information [here](./depolyments/index.md)

### Usage

Expand Down Expand Up @@ -96,53 +100,53 @@ Finds optimal price path and calculates final price.

**Parameters:**

- `base` - Base asset address to price
- `quote` - Quote asset address to price against
- `base` - Base asset address to price
- `quote` - Quote asset address to price against

**Returns:**

- `path` - Array of feed addresses used in routing
- `answer` - Calculated price with proper decimal scaling
- `path` - Array of feed addresses used in routing
- `answer` - Calculated price with proper decimal scaling

#### `queryFeed(address base, address quote)`

Gets feed address for asset pair (bidirectional search).

**Returns:**

- `feed` - Chainlink aggregator address or `address(0)` if not found
- `feed` - Chainlink aggregator address or `address(0)` if not found

#### `register(bytes calldata params)`

Registers multiple feeds in batch format.

**Parameters:**

- `params` - Packed bytes: `[feed1][base1][quote1][feed2][base2][quote2]...`
- `params` - Packed bytes: `[feed1][base1][quote1][feed2][base2][quote2]...`

#### `deregister(bytes calldata params)`

Deregisters multiple feeds in batch format and cleans up unused assets.

**Parameters:**

- `params` - Packed bytes: `[base1][quote1][base2][quote2]...`
- `params` - Packed bytes: `[base1][quote1][base2][quote2]...`

#### `registerAsset(address asset)`

Registers a single asset in the system.

**Parameters:**

- `asset` - Address of the asset to register
- `asset` - Address of the asset to register

#### `deregisterAsset(address asset)`

Deregisters an asset and removes all associated feeds.

**Parameters:**

- `asset` - Address of the asset to deregister
- `asset` - Address of the asset to deregister

**Note:** USD cannot be deregistered as it serves as the primary reference currency.

Expand Down Expand Up @@ -177,10 +181,10 @@ forge test --match-path test/ChainlinkRouter.t.sol

### Known Limitations

- Maximum 256 assets due to BitMap constraints
- Dependent on Chainlink feed reliability and freshness
- Gas costs increase with routing complexity
- Requires manual feed registration and maintenance
- Maximum 256 assets due to BitMap constraints
- Dependent on Chainlink feed reliability and freshness
- Gas costs increase with routing complexity
- Requires manual feed registration and maintenance

## FAQ

Expand All @@ -205,21 +209,11 @@ The router automatically normalizes decimal places across different assets. Each

</details>

## Deployment

**ChainlinkRouter** is deployed on the following chains:

| Network | Implementation | Proxy |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Sepolia | [0x4c64F98969c6331C8AD934e857914D3104a42809](https://sepolia.etherscan.io/address/0x4c64F98969c6331C8AD934e857914D3104a42809) | [0xFa71F0f28D7B27E590173c7E8214F855612E0D5b](https://sepolia.etherscan.io/address/0xFa71F0f28D7B27E590173c7E8214F855612E0D5b) |
| Arbitrum Sepolia | [0x4c64F98969c6331C8AD934e857914D3104a42809](https://sepolia.arbiscan.io/address/0x4c64F98969c6331C8AD934e857914D3104a42809) | [0xE80049700C9d1Ee7135a2FfB5b1Cfe28cE141bda](https://sepolia.arbiscan.io/address/0xE80049700C9d1Ee7135a2FfB5b1Cfe28cE141bda) |
| Base Sepolia | [0x4c64F98969c6331C8AD934e857914D3104a42809](https://sepolia.basescan.org/address/0x4c64F98969c6331C8AD934e857914D3104a42809) | [0xD1af8CEb001ABC934c86E7d42c4f06D33168a09C](https://sepolia.basescan.org/address/0xD1af8CEb001ABC934c86E7d42c4f06D33168a09C) |

## Resources

- [Chainlink Price Feeds Doc](https://docs.chain.link/data-feeds/price-feeds)
- [Chainlink Data Feeds](https://data.chain.link/feeds)
- [Chainlink Price Feeds Doc](https://docs.chain.link/data-feeds/price-feeds)
- [Chainlink Data Feeds](https://data.chain.link/feeds)

## Author

- [@fomoweth](https://github.com/fomoweth)
- [@fomoweth](https://github.com/fomoweth)
4,056 changes: 4,056 additions & 0 deletions broadcast/Register.s.sol/1/run-1753527853.json

Large diffs are not rendered by default.

4,056 changes: 4,056 additions & 0 deletions broadcast/Register.s.sol/1/run-latest.json

Large diffs are not rendered by default.

Loading