Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7ed6630
init commit
grasphoper Jan 28, 2026
f356bf0
update interfaces
grasphoper Jan 30, 2026
8b494c5
new interfaces version
grasphoper Jan 30, 2026
51b2815
update interfaces
grasphoper Jan 30, 2026
097286d
add submitterReqResponse
grasphoper Jan 30, 2026
20b0e0f
comments
grasphoper Jan 30, 2026
ca20d2d
temp
grasphoper Jan 30, 2026
d7544a7
random
grasphoper Jan 31, 2026
155c71d
good; Interfaces4.sol
grasphoper Feb 2, 2026
15ff14d
ploish
grasphoper Feb 2, 2026
621b07d
finalize Interfaces4.sol
grasphoper Feb 3, 2026
a031f57
remove all except the v4 interfaces
grasphoper Feb 3, 2026
aa4461d
whitespace
grasphoper Feb 3, 2026
33ef79f
polish
grasphoper Feb 4, 2026
3ea7e64
README + diagram
grasphoper Feb 4, 2026
506e025
introduce Interfaces2
grasphoper Feb 12, 2026
0db06cc
add token transfer types and add executor knowledge of strating tokens
grasphoper Feb 12, 2026
0c1ac54
add Interfaces3
grasphoper Feb 28, 2026
1fd8cbb
update README to match Interfaces3
grasphoper Feb 28, 2026
175cb5f
update diagram and rename Interfaces3
grasphoper Feb 28, 2026
3968fa6
fix ForwardingAmounts
grasphoper Mar 2, 2026
253d292
update diagram
grasphoper Mar 2, 2026
a71536f
abstract contracts -> interfaces
grasphoper Mar 2, 2026
170bcee
OrderGateway scaffolding
grasphoper Mar 2, 2026
7e46a27
implement OrderGateway
grasphoper Mar 3, 2026
7d5456e
Executor scaffolding
grasphoper Mar 3, 2026
e89656d
Interfaces4, generic over executor
grasphoper Mar 3, 2026
9190fae
polish gateway
grasphoper Mar 4, 2026
9c2b880
update OrderGateway implementation
grasphoper Mar 4, 2026
680d2a9
add some production-ready libs
grasphoper Mar 4, 2026
6f54ee9
ExecutorV1
grasphoper Mar 4, 2026
98f62a2
Interfaces5
grasphoper Mar 5, 2026
b3876dc
add refundSettings
grasphoper Mar 6, 2026
d610468
progress
grasphoper Mar 11, 2026
1aec132
progress
grasphoper Mar 11, 2026
1aa415c
comment
grasphoper Mar 11, 2026
348b6a7
add leaner Interfaces6.sol
grasphoper Mar 25, 2026
31dd6fe
update with latest decisions
grasphoper Mar 27, 2026
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
189 changes: 189 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Across Protocol Smart Contracts

This repository contains production smart contracts for the Across Protocol cross-chain bridge.

## Development Frameworks

- **Foundry** (primary) - Used for new tests and deployment scripts
- **Hardhat** (legacy) - Some tests still use Hardhat; we're migrating to Foundry

## Project Structure

```
contracts/ # Smart contract source files
chain-adapters/ # L1 chain adapters
interfaces/ # Interface definitions
libraries/ # Shared libraries
test/evm/
foundry/ # Foundry tests (.t.sol)
local/ # Local unit tests
fork/ # Fork tests
hardhat/ # Legacy Hardhat tests (.ts)
script/ # Foundry deployment scripts (.s.sol)
utils/ # Script utilities (Constants.sol, DeploymentUtils.sol)
lib/ # External dependencies (git submodules)
```

## Build & Test Commands

```bash
# Build contracts
forge build # Foundry
yarn build-evm # Hardhat

# Run tests
yarn test-evm-foundry # Foundry local tests (recommended; uses FOUNDRY_PROFILE=local-test)
FOUNDRY_PROFILE=local-test forge test # Required for local Foundry tests in this repo
yarn test-evm-hardhat # Hardhat tests (legacy)

# Run specific Foundry tests
FOUNDRY_PROFILE=local-test forge test --match-test testDeposit
FOUNDRY_PROFILE=local-test forge test --match-contract Router_Adapter
FOUNDRY_PROFILE=local-test forge test -vvv # Verbose output
```

Use `FOUNDRY_PROFILE=local-test` (or `yarn test-evm-foundry`) for local Foundry test runs; do not use plain `forge test`.

## Naming Conventions

### Contract Files

- PascalCase with underscores for chain-specific: `Arbitrum_SpokePool.sol`, `OP_Adapter.sol`
- Interfaces: `I` prefix: `ISpokePool.sol`, `IArbitrumBridge.sol`
- Libraries: `<Name>Lib.sol`

### Test Files

- Foundry: `.t.sol` suffix: `Router_Adapter.t.sol`, `Arbitrum_Adapter.t.sol`
- Test contracts: `contract <Name>Test is Test { ... }`
- Test functions: `function test<Description>() public`

### Deployment Scripts

- Numbered with `.s.sol` suffix: `001DeployHubPool.s.sol`, `004DeployArbitrumAdapter.s.sol`
- Script contracts: `contract Deploy<ContractName> is Script, Test, Constants`

## Writing Tests

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { Test } from "forge-std/Test.sol";
import { MyContract } from "../contracts/MyContract.sol";

contract MyContractTest is Test {
MyContract public myContract;

function setUp() public {
myContract = new MyContract();
}

function testBasicFunctionality() public {
// Test implementation
assertEq(myContract.value(), expected);
}

function testRevertOnInvalidInput() public {
vm.expectRevert();
myContract.doSomething(invalidInput);
}
}
```

### Test Gotchas

- **Mocks**: Check `contracts/test/` for existing mocks before creating new ones (MockCCTP.sol, ArbitrumMocks.sol, etc.)
- **MockSpokePool**: Requires UUPS proxy deployment: `new ERC1967Proxy(address(new MockSpokePool(weth)), abi.encodeCall(MockSpokePool.initialize, (...)))`
- **vm.mockCall pattern** (prefer over custom mocks for simple return values):
```solidity
vm.etch(fakeAddr, hex"00"); // Bypass extcodesize check
vm.mockCall(fakeAddr, abi.encodeWithSelector(SELECTOR), abi.encode(returnVal));
vm.expectCall(fakeAddr, msgValue, abi.encodeWithSelector(SELECTOR, arg1));
```
- **Delegatecall context**: Adapter tests via HubPool emit events from HubPool's address; `vm.expectRevert()` may lose error data

## Deployment Scripts

Scripts follow a numbered pattern and use shared utilities from `script/utils/`.

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { Script } from "forge-std/Script.sol";
import { Test } from "forge-std/Test.sol";
import { console } from "forge-std/console.sol";
import { Constants } from "./utils/Constants.sol";
import { MyContract } from "../contracts/MyContract.sol";

// How to run:
// 1. `source .env` where `.env` has MNEMONIC="x x x ... x" and ETHERSCAN_API_KEY="x"
// 2. forge script script/00XDeployMyContract.s.sol:DeployMyContract --rpc-url $NODE_URL_1 -vvvv
// 3. Verify simulation works
// 4. Deploy: forge script script/00XDeployMyContract.s.sol:DeployMyContract --rpc-url $NODE_URL_1 --broadcast --verify -vvvv

contract DeployMyContract is Script, Test, Constants {
function run() external {
string memory deployerMnemonic = vm.envString("MNEMONIC");
uint256 deployerPrivateKey = vm.deriveKey(deployerMnemonic, 0);

uint256 chainId = block.chainid;
// Validate chain if needed
require(chainId == getChainId("MAINNET"), "Deploy on mainnet only");

vm.startBroadcast(deployerPrivateKey);

MyContract myContract = new MyContract /* constructor args */();

console.log("Chain ID:", chainId);
console.log("MyContract deployed to:", address(myContract));

vm.stopBroadcast();
}
}
```

For upgradeable contracts, use `DeploymentUtils` which provides `deployNewProxy()`.

## Configuration

See `foundry.toml` for Foundry configuration. Key settings:

- Source: `contracts/`
- Tests: `test/evm/foundry/`
- Solidity: 0.8.30
- EVM: Prague
- Optimizer: 800 runs with via-ir

**Do not modify `foundry.toml` without asking** - explain what you want to change and why.

## Security Practices

- Follow CEI (Checks-Effects-Interactions) pattern
- Use OpenZeppelin for access control and upgrades
- Validate all inputs at system boundaries
- Use `_requireAdminSender()` for admin-only functions
- UUPS proxy pattern for upgradeable contracts
- Cross-chain ownership: HubPool owns all SpokePool contracts

## Code Style

**Prioritize succinctness.** Express features in the least lines possible. This often leads to the most elegant solution:

- Consolidate duplicate code paths (e.g., one function call with different parameters instead of multiple branches with similar calls)
- Compute values before branching, then use them in a single code path
- Avoid redundant intermediate variables when the expression is clear (although consider gas cost implications, especially for mainnet contracts)
- Prefer early returns to reduce nesting

## Linting

```bash
yarn lint-solidity # Solhint for Solidity
yarn lint-js # Prettier for JS/TS
yarn lint-fix # Auto-fix all
```

## License

BUSL-1.1 (see LICENSE file for exceptions)
190 changes: 1 addition & 189 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,189 +1 @@
# Across Protocol Smart Contracts

This repository contains production smart contracts for the Across Protocol cross-chain bridge.

## Development Frameworks

- **Foundry** (primary) - Used for new tests and deployment scripts
- **Hardhat** (legacy) - Some tests still use Hardhat; we're migrating to Foundry

## Project Structure

```
contracts/ # Smart contract source files
chain-adapters/ # L1 chain adapters
interfaces/ # Interface definitions
libraries/ # Shared libraries
test/evm/
foundry/ # Foundry tests (.t.sol)
local/ # Local unit tests
fork/ # Fork tests
hardhat/ # Legacy Hardhat tests (.ts)
script/ # Foundry deployment scripts (.s.sol)
utils/ # Script utilities (Constants.sol, DeploymentUtils.sol)
lib/ # External dependencies (git submodules)
```

## Build & Test Commands

```bash
# Build contracts
forge build # Foundry
yarn build-evm # Hardhat

# Run tests
yarn test-evm-foundry # Foundry local tests (recommended; uses FOUNDRY_PROFILE=local-test)
FOUNDRY_PROFILE=local-test forge test # Required for local Foundry tests in this repo
yarn test-evm-hardhat # Hardhat tests (legacy)

# Run specific Foundry tests
FOUNDRY_PROFILE=local-test forge test --match-test testDeposit
FOUNDRY_PROFILE=local-test forge test --match-contract Router_Adapter
FOUNDRY_PROFILE=local-test forge test -vvv # Verbose output
```

Use `FOUNDRY_PROFILE=local-test` (or `yarn test-evm-foundry`) for local Foundry test runs; do not use plain `forge test`.

## Naming Conventions

### Contract Files

- PascalCase with underscores for chain-specific: `Arbitrum_SpokePool.sol`, `OP_Adapter.sol`
- Interfaces: `I` prefix: `ISpokePool.sol`, `IArbitrumBridge.sol`
- Libraries: `<Name>Lib.sol`

### Test Files

- Foundry: `.t.sol` suffix: `Router_Adapter.t.sol`, `Arbitrum_Adapter.t.sol`
- Test contracts: `contract <Name>Test is Test { ... }`
- Test functions: `function test<Description>() public`

### Deployment Scripts

- Numbered with `.s.sol` suffix: `001DeployHubPool.s.sol`, `004DeployArbitrumAdapter.s.sol`
- Script contracts: `contract Deploy<ContractName> is Script, Test, Constants`

## Writing Tests

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { Test } from "forge-std/Test.sol";
import { MyContract } from "../contracts/MyContract.sol";

contract MyContractTest is Test {
MyContract public myContract;

function setUp() public {
myContract = new MyContract();
}

function testBasicFunctionality() public {
// Test implementation
assertEq(myContract.value(), expected);
}

function testRevertOnInvalidInput() public {
vm.expectRevert();
myContract.doSomething(invalidInput);
}
}
```

### Test Gotchas

- **Mocks**: Check `contracts/test/` for existing mocks before creating new ones (MockCCTP.sol, ArbitrumMocks.sol, etc.)
- **MockSpokePool**: Requires UUPS proxy deployment: `new ERC1967Proxy(address(new MockSpokePool(weth)), abi.encodeCall(MockSpokePool.initialize, (...)))`
- **vm.mockCall pattern** (prefer over custom mocks for simple return values):
```solidity
vm.etch(fakeAddr, hex"00"); // Bypass extcodesize check
vm.mockCall(fakeAddr, abi.encodeWithSelector(SELECTOR), abi.encode(returnVal));
vm.expectCall(fakeAddr, msgValue, abi.encodeWithSelector(SELECTOR, arg1));
```
- **Delegatecall context**: Adapter tests via HubPool emit events from HubPool's address; `vm.expectRevert()` may lose error data

## Deployment Scripts

Scripts follow a numbered pattern and use shared utilities from `script/utils/`.

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { Script } from "forge-std/Script.sol";
import { Test } from "forge-std/Test.sol";
import { console } from "forge-std/console.sol";
import { Constants } from "./utils/Constants.sol";
import { MyContract } from "../contracts/MyContract.sol";

// How to run:
// 1. `source .env` where `.env` has MNEMONIC="x x x ... x" and ETHERSCAN_API_KEY="x"
// 2. forge script script/00XDeployMyContract.s.sol:DeployMyContract --rpc-url $NODE_URL_1 -vvvv
// 3. Verify simulation works
// 4. Deploy: forge script script/00XDeployMyContract.s.sol:DeployMyContract --rpc-url $NODE_URL_1 --broadcast --verify -vvvv

contract DeployMyContract is Script, Test, Constants {
function run() external {
string memory deployerMnemonic = vm.envString("MNEMONIC");
uint256 deployerPrivateKey = vm.deriveKey(deployerMnemonic, 0);

uint256 chainId = block.chainid;
// Validate chain if needed
require(chainId == getChainId("MAINNET"), "Deploy on mainnet only");

vm.startBroadcast(deployerPrivateKey);

MyContract myContract = new MyContract /* constructor args */();

console.log("Chain ID:", chainId);
console.log("MyContract deployed to:", address(myContract));

vm.stopBroadcast();
}
}
```

For upgradeable contracts, use `DeploymentUtils` which provides `deployNewProxy()`.

## Configuration

See `foundry.toml` for Foundry configuration. Key settings:

- Source: `contracts/`
- Tests: `test/evm/foundry/`
- Solidity: 0.8.30
- EVM: Prague
- Optimizer: 800 runs with via-ir

**Do not modify `foundry.toml` without asking** - explain what you want to change and why.

## Security Practices

- Follow CEI (Checks-Effects-Interactions) pattern
- Use OpenZeppelin for access control and upgrades
- Validate all inputs at system boundaries
- Use `_requireAdminSender()` for admin-only functions
- UUPS proxy pattern for upgradeable contracts
- Cross-chain ownership: HubPool owns all SpokePool contracts

## Code Style

**Prioritize succinctness.** Express features in the least lines possible. This often leads to the most elegant solution:

- Consolidate duplicate code paths (e.g., one function call with different parameters instead of multiple branches with similar calls)
- Compute values before branching, then use them in a single code path
- Avoid redundant intermediate variables when the expression is clear (although consider gas cost implications, especially for mainnet contracts)
- Prefer early returns to reduce nesting

## Linting

```bash
yarn lint-solidity # Solhint for Solidity
yarn lint-js # Prettier for JS/TS
yarn lint-fix # Auto-fix all
```

## License

BUSL-1.1 (see LICENSE file for exceptions)
@AGENTS.md
Loading