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
17 changes: 2 additions & 15 deletions packages/bridge-contracts/deploy/deployOFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,7 @@ import { ethers } from 'hardhat';
import Contracts from '@gooddollar/goodprotocol/releases/deployment.json';
import { getImplementationAddress } from '@openzeppelin/upgrades-core';
import { verifyContract } from './utils/verifyContract';

// Network-specific LayerZero endpoints
const lzEndpoints: { [key: string]: string } = {
'development-celo': '0x1a44076050125825900e736c501f859c50fE728c',
'production-celo': '0x1a44076050125825900e736c501f859c50fE728c',
'development-xdc': '0xcb566e3B6934Fa77258d68ea18E931fa75e1aaAa',
'production-xdc': '0xcb566e3B6934Fa77258d68ea18E931fa75e1aaAa',
};
import { getLzEndpoint } from './utils/getLzEndpoint';

const func: DeployFunction = async function (hre) {
const { deployments, network } = hre;
Expand Down Expand Up @@ -77,13 +70,7 @@ const func: DeployFunction = async function (hre) {
}
}

// Get LayerZero endpoint
const lzEndpoint = lzEndpoints[networkName] || process.env.LAYERZERO_ENDPOINT;
if (!lzEndpoint) {
throw new Error(
`LayerZero endpoint not found. Please set LAYERZERO_ENDPOINT environment variable or add default for network ${networkName}`,
);
}
const lzEndpoint = getLzEndpoint(networkName);

console.log('Deployment parameters:', {
tokenAddress,
Expand Down
15 changes: 2 additions & 13 deletions packages/bridge-contracts/deploy/upgradeOFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ import { ethers } from "hardhat";
import Contracts from "@gooddollar/goodprotocol/releases/deployment.json";
import { getImplementationAddress } from "@openzeppelin/upgrades-core";
import { getOftDeploymentAddresses } from "./utils/getOftDeploymentAddresses";

const lzEndpoints: { [key: string]: string } = {
"development-celo": "0x1a44076050125825900e736c501f859c50fE728c",
"production-celo": "0x1a44076050125825900e736c501f859c50fE728c",
"development-xdc": "0xcb566e3B6934Fa77258d68ea18E931fa75e1aaAa",
"production-xdc": "0xcb566e3B6934Fa77258d68ea18E931fa75e1aaAa",
};
import { getLzEndpoint } from "./utils/getLzEndpoint";

const func: DeployFunction = async function (hre) {
const { deployments, network } = hre;
Expand Down Expand Up @@ -61,12 +55,7 @@ const func: DeployFunction = async function (hre) {
);
}

const lzEndpoint = lzEndpoints[networkName] || process.env.LAYERZERO_ENDPOINT;
if (!lzEndpoint) {
throw new Error(
`LayerZero endpoint not found. Please set LAYERZERO_ENDPOINT or add default for network ${networkName}`
);
}
const lzEndpoint = getLzEndpoint(networkName);

console.log("\nDeployment parameters (same as deployOFT):");
console.log("Token:", tokenAddress);
Expand Down
19 changes: 19 additions & 0 deletions packages/bridge-contracts/deploy/utils/getLzEndpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const celoMainnetEndpoint = require("@layerzerolabs/lz-evm-sdk-v2/deployments/celo-mainnet/EndpointV2.json");
const xdcMainnetEndpoint = require("@layerzerolabs/lz-evm-sdk-v2/deployments/xdc-mainnet/EndpointV2.json");

const LZ_ENDPOINT_BY_NETWORK: Record<string, string> = {
"development-celo": celoMainnetEndpoint.address,
"production-celo": celoMainnetEndpoint.address,
"development-xdc": xdcMainnetEndpoint.address,
"production-xdc": xdcMainnetEndpoint.address,
};

export function getLzEndpoint(networkName: string): string {
const endpoint = LZ_ENDPOINT_BY_NETWORK[networkName] || process.env.LAYERZERO_ENDPOINT;
if (!endpoint) {
throw new Error(
`LayerZero EndpointV2 not mapped for "${networkName}". Set LAYERZERO_ENDPOINT or add a mapping in deploy/utils/getLzEndpoint.ts`
);
}
return endpoint;
}
2 changes: 2 additions & 0 deletions packages/bridge-contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import * as envEnc from '@chainlink/env-enc';
import '@layerzerolabs/toolbox-hardhat'
import { EndpointId } from '@layerzerolabs/lz-definitions'

import './scripts/oft/configure-oft';

configDotenv();
envEnc.config();

Expand Down
89 changes: 0 additions & 89 deletions packages/bridge-contracts/layerzero.config.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/bridge-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build": "hardhat compile",
"test": "hardhat test",
"test:oft": "hardhat test ./test/GoodDollarOFT.test.ts",
"oft:configure": "hardhat oft:configure",
"updateabi": "find ./artifacts/contracts/ -iregex '.*/[a-z]*.json' -exec cp \"{}\" ../bridge-app/src/abi \\;",
"start:dev": "hardhat node & yarn build && yarn updateabi && hardhat run scripts/deployDevEnv.ts --network localhost",
"mpb:deploy": "hardhat deploy --export-all ./release/mpb.json"
Expand All @@ -30,6 +31,7 @@
"@layerzerolabs/devtools-evm-hardhat": "^4.0.4",
"@layerzerolabs/lz-definitions": "^3.0.151",
"@layerzerolabs/lz-evm-protocol-v2": "^3.0.151",
"@layerzerolabs/lz-evm-sdk-v2": "^3.0.148",
"@layerzerolabs/lz-v2-utilities": "^3.0.156",
"@layerzerolabs/metadata-tools": "^3.0.3",
"@layerzerolabs/oapp-evm": "^0.4.1",
Expand Down
109 changes: 109 additions & 0 deletions packages/bridge-contracts/scripts/oft/OFT_CONFIGURING_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# OFT bridge deploy & configure

From `packages/bridge-contracts`. Addresses are written to git-ignored hardhat-deploy artifacts:

`deployments/<network>/GoodDollarOFTAdapter.json`
`deployments/<network>/GoodDollarOFTMinterBurner.json`

## Deploy

```bash
npx hardhat deploy --tags OFT --network production-xdc
npx hardhat deploy --tags OFT --network production-celo
```

Use `development-xdc` / `development-celo` for staging. Deploy **both** chains before configuring (LayerZero wire needs both adapters, and must run while the deployer still owns the OApp).

### Deploy parameters (`deploy/deployOFT.ts`)

| Parameter | Source | Notes |
|-----------|--------|--------|
| Token / NameService / Controller | `@gooddollar/goodprotocol` `deployment.json` for the Hardhat network | Required |
| LayerZero endpoint | `@layerzerolabs/lz-evm-sdk-v2` `EndpointV2.json` via `deploy/utils/getLzEndpoint.ts` (fallback: `LAYERZERO_ENDPOINT` if network unmapped) | Celo/XDC mainnet deployments |
| Proxy CREATE2 salt | `Development-…V1` or `Production-…V1` string hash | Fixed proxy address per env |
| Implementation CREATE2 salt | `keccak256(bytecode)` | Changes when code changes |

## Configure

Hardhat task (`package.json` → `hardhat oft:configure`):

```bash
yarn oft:configure --network production-xdc
yarn oft:configure --network production-celo
```

### Steps (in order)

1. **LayerZero wire** — `lz:oapp:wire --ci` using `scripts/oft/layerzero.config.ts` (peers / DVNs / options). Must run **before** ownership transfer; after Avatar owns the adapter, wiring is not possible from the deployer key.
2. **Minter role** — grant `MINTER_ROLE` on G$ to `GoodDollarOFTMinterBurner` via Controller/Avatar
3. **Bridge limits** — `setBridgeLimits` from `scripts/oft/oft.config.json` (still as deployer owner)
4. **Adapter ownership** — transfer `GoodDollarOFTAdapter` owner to DAO Avatar (**last**)

### Skip flags

```bash
yarn oft:configure --network production-xdc --skip-wire
yarn oft:configure --network production-celo --skip-minter --skip-limits --skip-adapter-ownership
```

| Flag | Skips |
|------|--------|
| `--skip-wire` | Step 1 |
| `--skip-minter` | Step 2 |
| `--skip-limits` | Step 3 |
| `--skip-adapter-ownership` | Step 4 |

### Limit parameters (`oft.config.json`)

Values are **G$ amounts** (e.g. `"100"` → 100 G$), not wei:

| Field | Meaning |
|-------|---------|
| `dailyLimit` | Max G$ bridged per 24h (all users) |
| `txLimit` | Max G$ in one tx |
| `accountDailyLimit` | Max G$ per account per 24h |
| `minAmount` | Min G$ per tx |
| `onlyWhitelisted` | `true` → only Identity-whitelisted senders |

### LayerZero pair env

`oft:configure` sets these from the explicit network pair map in `configure-oft.ts`:

- `OFT_XDC_NETWORK`
- `OFT_CELO_NETWORK`

## Upgrade

Proxy addresses stay the same:

```bash
npx hardhat deploy --tags OFT-Upgrade --network production-xdc
npx hardhat deploy --tags OFT-Upgrade --network production-celo
```

## Bridge (smoke test)

After deploy + configure on **both** chains, send ~1 G$ from the source network:

```bash
npx hardhat run scripts/oft/bridge-oft-token.ts --network production-xdc
npx hardhat run scripts/oft/bridge-oft-token.ts --network production-celo
```

`--network` is the **source** chain (XDC → CELO or CELO → XDC). Needs G$ on source, native gas for the tx + LayerZero fee, peers wired, and minter role on both sides. Track delivery on [LayerZero Scan](https://layerzeroscan.com/).

## Add a network for LayerZero wiring

Today the stack is built for **XDC ↔ CELO** (`layerzero.config.ts`, `OFT_NETWORK_PAIRS`). Adding a third chain needs more than a one-line append — those two-chain helpers must be extended or refactored.

Suggested order:

1. **Hardhat** — add the network in `hardhat.config.ts` (RPC, accounts, and `eid: EndpointId.<CHAIN>_V2_…` like the existing celo/xdc entries)
2. **Deploy endpoint** — map Hardhat name → `@layerzerolabs/lz-evm-sdk-v2` `deployments/<lz-network>/EndpointV2.json` in `getLzEndpoint.ts`, or set `LAYERZERO_ENDPOINT` for that run (required by the OFT adapter **constructor**, not by `lz:oapp:wire`)
3. **GoodProtocol** — ensure `deployment.json` (or local overrides) has GoodDollar / NameService / Controller / Avatar for that network (configure steps need them)
4. **Deploy** — `npx hardhat deploy --tags OFT --network <new-network>` → `deployments/<network>/GoodDollarOFTAdapter.json`
5. **`layerzero.config.ts`** — add an `OmniPointHardhat` (eid + adapter from `getOftDeploymentAddresses`); add `pathways` for each pair you want (e.g. new↔CELO, new↔XDC). The current file is a single XDC↔CELO pathway driven by `OFT_XDC_NETWORK` / `OFT_CELO_NETWORK` — multi-chain needs that structure updated, not only one new pathway line
6. **Configure helpers** — `oft.config.json` limits; extend/refactor `OFT_NETWORK_PAIRS` in `configure-oft.ts` so `oft:configure` knows how to set peer env for wiring
7. **Wire then configure** — `yarn oft:configure --network <new-network>` (and on each peer). Wire runs **first** (deployer must still own the OApp); ownership transfer to Avatar is **last**

`EndpointId` / DVN names: `@layerzerolabs/lz-definitions` and LayerZero metadata for that chain.
Loading
Loading