|
| 1 | +--- |
| 2 | +name: bridge |
| 3 | +description: Bridge tokens across chains using the LayerZero OFT adapter (`GoodDollarOFTAdapter`, call `send(...)` with `SendParam`). Use when the user asks to bridge via the OFT path, needs `quoteSend(...)` fee estimation, must set the OFT `peer`, and needs to approve the underlying token to the `minterBurner`. |
| 4 | +--- |
| 5 | + |
| 6 | +# Bridge Tokens (GoodDollarOFTAdapter + viem) |
| 7 | + |
| 8 | +## Instructions |
| 9 | + |
| 10 | +When the user wants to bridge assets cross-chain: |
| 11 | + |
| 12 | +1. Identify inputs |
| 13 | + - `oftAdapterAddress` (source chain `GoodDollarOFTAdapter` proxy address) |
| 14 | + - `dstEid` (destination LayerZero Endpoint ID used by OFT) |
| 15 | + - `recipient` (address to receive on the destination chain) |
| 16 | + - `amountLD` (amount in local token decimals, used in `SendParam`) |
| 17 | + - `minAmountLD` (min amount for slippage protection; commonly equals `amountLD`) |
| 18 | + - `walletClient` / `publicClient` (viem clients) and the `account` that sends from |
| 19 | + - `privateKey` (if you only have a private key) |
| 20 | + |
| 21 | +2. OFT wiring checks (peer + options) |
| 22 | + - Ensure the destination peer is configured on the source adapter: |
| 23 | + - read `oftAdapter.peers(dstEid)` and confirm it matches the destination adapter address as `bytes32` (normally `hexZeroPad(destOftAdapterAddress, 32)`). |
| 24 | + - If you get enforced-options failures (or `InvalidWorkerOptions`), you likely need correct LayerZero wiring for both chains; then retry with proper `extraOptions` (see step 4). |
| 25 | + |
| 26 | +3. Approve the underlying token to the minter/burner (required) |
| 27 | + - `GoodDollarOFTAdapter.approvalRequired()` returns `false` (adapter itself doesn't pull ERC20), but the *minterBurner* still needs allowance because it calls `burnFrom`. |
| 28 | + - Read `underlyingToken = oftAdapter.token()` |
| 29 | + - Read `minterBurner = oftAdapter.minterBurner()` |
| 30 | + - Check `underlyingToken.allowance(account.address, minterBurner)` |
| 31 | + - If allowance is insufficient, send `underlyingToken.approve(minterBurner, amountLD)` |
| 32 | + |
| 33 | +4. Build `SendParam` and estimate LayerZero fees |
| 34 | + - `SendParam` fields: |
| 35 | + - `dstEid` |
| 36 | + - `to`: `hexZeroPad(recipient, 32)` (OFT expects `bytes32`) |
| 37 | + - `amountLD` |
| 38 | + - `minAmountLD` |
| 39 | + - `extraOptions`: usually `0x` (but may need adapter-specific enforced options) |
| 40 | + - `composeMsg`: `0x` (unless you know you need compose functionality) |
| 41 | + - `oftCmd`: `0x` (unused in default) |
| 42 | + - Optionally build options via `oftAdapter.combineOptions(dstEid, 1 /* SEND */, "0x")` if available and if `0x` fails. |
| 43 | + - Estimate messaging fees: |
| 44 | + - call `oftAdapter.quoteSend(sendParam, false /* payInLzToken */)` to get `{ nativeFee, lzTokenFee }`. |
| 45 | + |
| 46 | +5. Send the OFT transfer |
| 47 | + - call `oftAdapter.send(sendParam, messagingFee, refundAddress, { value: messagingFee.nativeFee })` |
| 48 | + - `refundAddress` is typically `account.address`. |
| 49 | + |
| 50 | +6. Confirm initiation / track completion |
| 51 | + - On the source chain tx receipt, look for the `Send` event (its `amountLD` and `to` tell you what was initiated). |
| 52 | + - Completion on destination is asynchronous via LayerZero; track via [LayerZeroScan](https://layerzeroscan.com/) using the source tx hash (and/or wait for the destination mint/credit, then check the recipient balance). |
| 53 | + |
| 54 | +## Common failure modes (quick diagnosis) |
| 55 | + |
| 56 | +- `NoPeer` / peer mismatch: destination peer not set; configure `oftAdapter.setPeer(dstEid, bytes32(destOftAdapterAddress))` (or run LayerZero wiring). |
| 57 | +- `InvalidWorkerOptions` / enforced options failures: `"extraOptions"` needs to be derived via `combineOptions(...)` and/or LayerZero wiring must be completed. |
| 58 | + |
| 59 | +## Output to the user |
| 60 | + |
| 61 | +- tx hash |
| 62 | +- recipient |
| 63 | +- amountLD / minAmountLD |
| 64 | +- (best-effort) destination completion guidance (LayerZero is async) |
| 65 | + |
0 commit comments