diff --git a/src/pages/guide/bridge-usdc-stargate.mdx b/src/pages/guide/bridge-layerzero.mdx similarity index 60% rename from src/pages/guide/bridge-usdc-stargate.mdx rename to src/pages/guide/bridge-layerzero.mdx index 090a4808..4506fca3 100644 --- a/src/pages/guide/bridge-usdc-stargate.mdx +++ b/src/pages/guide/bridge-layerzero.mdx @@ -1,28 +1,56 @@ --- -title: Bridge USDC via Stargate -description: Bridge USDC to and from Tempo using Stargate and LayerZero. Includes source chain addresses, cast commands, and TypeScript examples with viem. +title: Bridge via LayerZero +description: Bridge tokens to and from Tempo using LayerZero. Covers Stargate pools and standard OFT adapters with cast commands and TypeScript examples. --- -import { Tabs, Tab } from 'vocs' +# Bridge via LayerZero -# Bridge USDC via Stargate +[LayerZero](https://layerzero.network) is the omnichain messaging protocol that powers token bridging on Tempo. Tokens are bridged using the [OFT (Omnichain Fungible Token)](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) standard - the source chain locks or burns tokens and the destination chain mints the bridged equivalent. -[Stargate](https://stargate.finance/) uses [LayerZero](https://layerzero.network) to enable 1:1 USDC bridging between Tempo and other chains. Stargate locks USDC on the source chain and mints **USDC.e** (Bridged USDC) on Tempo, typically in under a minute. +There are two flavors of OFT on Tempo: -## Contracts on Tempo +- **Stargate** - an application built on LayerZero that manages liquidity pools. Tokens like USDC.e and EURC.e use Stargate's `sendToken()` interface. +- **Standard OFT** - token issuers (e.g. Tether for USDT0) deploy their own OFT adapters using LayerZero's `send()` interface directly. + +Both use the same underlying LayerZero endpoint on Tempo. + +## Bridged tokens on Tempo + +| Token | Address | Bridge | +|-------|---------|--------| +| **USDC.e** (Bridged USDC) | [`0x20C000000000000000000000b9537d11c60E8b50`](https://explore.tempo.xyz/address/0x20C000000000000000000000b9537d11c60E8b50) | Stargate | +| **EURC.e** (Bridged EURC) | [`0x20c0000000000000000000001621e21F71CF12fb`](https://explore.tempo.xyz/address/0x20c0000000000000000000001621e21F71CF12fb) | Stargate | +| **USDT0** | [`0x20c00000000000000000000014f22ca97301eb73`](https://explore.tempo.xyz/address/0x20c00000000000000000000014f22ca97301eb73) | OFT | +| **frxUSD** | [`0x20c0000000000000000000003554d28269e0f3c2`](https://explore.tempo.xyz/address/0x20c0000000000000000000003554d28269e0f3c2) | OFT | +| **cUSD** | [`0x20c0000000000000000000000520792dcccccccc`](https://explore.tempo.xyz/address/0x20c0000000000000000000000520792dcccccccc) | OFT | +| **stcUSD** | [`0x20c0000000000000000000008ee4fcff88888888`](https://explore.tempo.xyz/address/0x20c0000000000000000000008ee4fcff88888888) | OFT | +| **GUSD** | [`0x20c0000000000000000000005c0bac7cef389a11`](https://explore.tempo.xyz/address/0x20c0000000000000000000005c0bac7cef389a11) | OFT | +| **rUSD** | [`0x20c0000000000000000000007f7ba549dd0251b9`](https://explore.tempo.xyz/address/0x20c0000000000000000000007f7ba549dd0251b9) | OFT | +| **wsrUSD** | [`0x20c000000000000000000000aeed2ec36a54d0e5`](https://explore.tempo.xyz/address/0x20c000000000000000000000aeed2ec36a54d0e5) | OFT | + +See the full token list at [tokenlist.tempo.xyz](https://tokenlist.tempo.xyz/list/4217). + +## LayerZero contracts on Tempo | Contract | Address | |----------|---------| -| **USDC.e** (Bridged USDC) | [`0x20C000000000000000000000b9537d11c60E8b50`](https://explore.tempo.xyz/address/0x20C000000000000000000000b9537d11c60E8b50) | -| **StargateOFTUSDC** | [`0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392`](https://explore.tempo.xyz/address/0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392) | | **EndpointV2** | [`0x20Bb7C2E2f4e5ca2B4c57060d1aE2615245dCc9C`](https://explore.tempo.xyz/address/0x20Bb7C2E2f4e5ca2B4c57060d1aE2615245dCc9C) | | **LZEndpointDollar** | [`0x0cEb237E109eE22374a567c6b09F373C73FA4cBb`](https://explore.tempo.xyz/address/0x0cEb237E109eE22374a567c6b09F373C73FA4cBb) | Tempo's LayerZero Endpoint ID is **`30410`**. -## Source chain contracts +## Stargate tokens + +[Stargate](https://stargate.finance/) manages liquidity pools for USDC.e and EURC.e. Use the Stargate `sendToken()` interface for these tokens. + +### Stargate contracts on Tempo + +| Token | Stargate OFT Contract | +|-------|----------------------| +| **USDC.e** | [`0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392`](https://explore.tempo.xyz/address/0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392) | +| **EURC.e** | [`0x7753Dc8d4bd48Db599Da21E08b1Ab1D6FDFfdC71`](https://explore.tempo.xyz/address/0x7753Dc8d4bd48Db599Da21E08b1Ab1D6FDFfdC71) | -Use the Stargate pool contract on the source chain to bridge USDC to Tempo, and the StargateOFTUSDC contract on Tempo to bridge back. +### Source chain Stargate pools | Chain | LZ Endpoint ID | Stargate USDC Pool | |-------|---------------:|--------------------| @@ -33,23 +61,20 @@ Use the Stargate pool contract on the source chain to bridge USDC to Tempo, and | Polygon | `30109` | [`0x9Aa02D4Fae7F58b8E8f34c66E756cC734DAc7fe4`](https://polygonscan.com/address/0x9Aa02D4Fae7F58b8E8f34c66E756cC734DAc7fe4) | | Avalanche | `30106` | [`0x5634c4a5FEd09819E3c46D86A965Dd9447d86e47`](https://snowtrace.io/address/0x5634c4a5FEd09819E3c46D86A965Dd9447d86e47) | -## Bridge to Tempo +### Bridge to Tempo via Stargate -### Using the Stargate app +#### Using the Stargate app 1. Go to [stargate.finance](https://stargate.finance/) -2. Select your source chain (e.g. Ethereum) and USDC +2. Select your source chain and token (USDC or EURC) 3. Set **Tempo** as the destination chain 4. Enter the amount, approve, and send -### Using cast (Foundry) +#### Using cast (Foundry) -Bridge USDC from Base to Tempo using `cast`. This calls `sendToken` on the Stargate pool on the source chain. This example uses [taxi mode](#bus-vs-taxi-mode) for immediate delivery. +This example bridges USDC from Base to Tempo. Replace addresses for other tokens or source chains. -#### Step 1 — Get a quote fee estimate from Stargate router - -Use the same parameters you will pass to `sendToken`. Returns `(nativeFee, lzTokenFee)`. -Take the first returned number as ``. +##### Step 1 - Get a quote ```bash cast call 0x27a16dc786820B16E5c9028b75B99F6f604b5d26 \ @@ -59,9 +84,9 @@ cast call 0x27a16dc786820B16E5c9028b75B99F6f604b5d26 \ --rpc-url https://mainnet.base.org ``` -#### Step 2 — Approve USDC on Base +Take the first returned number as ``. -Approve the Stargate router to spend USDC. +##### Step 2 - Approve token on source chain ```bash cast send 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \ @@ -72,34 +97,26 @@ cast send 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \ --private-key $PRIVATE_KEY ``` -#### Step 3 — Send bridge transaction +##### Step 3 - Send bridge transaction ```bash cast send 0x27a16dc786820B16E5c9028b75B99F6f604b5d26 \ 'sendToken((uint32,bytes32,uint256,uint256,bytes,bytes,bytes),(uint256,uint256),address)' \ "(30410,$(cast abi-encode 'f(address)' ),,,0x,0x,0x)" \ "(,0)" \ - \ + \ --value \ --rpc-url https://mainnet.base.org \ --private-key $PRIVATE_KEY ``` -#### Step 4 — Verify transaction status - -Track the bridge with the transaction hash returned by `sendToken`: +##### Step 4 - Verify transaction status ```text https://scan.layerzero-api.com/v1/messages/tx/ ``` -Once delivered, view the destination transaction on Tempo: - -```text -https://explore.tempo.xyz/tx/ -``` - -### Using TypeScript (viem) +#### Using TypeScript (viem) ```typescript import { createWalletClient, createPublicClient, http, parseUnits, pad } from 'viem' @@ -219,7 +236,7 @@ const msgFee = await publicClient.readContract({ args: [sendParam, false], }) -// 2. Approve USDC +// 2. Approve token await walletClient.writeContract({ address: usdc, abi: erc20Abi, @@ -237,18 +254,15 @@ await walletClient.writeContract({ }) ``` -## Bridge from Tempo - -To bridge USDC.e from Tempo back to another chain, call `sendToken` on the **StargateOFTUSDC** contract on Tempo. The process is the same — quote, approve, send — but the source contract and destination EID are swapped. +### Bridge from Tempo via Stargate -### Using cast (Foundry) +To bridge from Tempo back to another chain, call `sendToken` on the Stargate OFT contract on Tempo. The process is the same - quote, approve, send - but the source contract and destination EID are swapped. -Bridge USDC.e from Tempo to Base using `cast`. This calls `sendToken` on the **StargateOFTUSDC** contract on Tempo. This example uses [taxi mode](#bus-vs-taxi-mode) for immediate delivery. +#### Using cast (Foundry) -#### Step 1 — Quote the fee +This example bridges USDC.e from Tempo to Base. -Use the same parameters you will pass to `sendToken`. Returns `(nativeFee, lzTokenFee)`. -Take the first returned number as `` (in stablecoin units, not ETH). +##### Step 1 - Quote the fee ```bash cast call 0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392 \ @@ -258,9 +272,9 @@ cast call 0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392 \ --rpc-url https://rpc.tempo.xyz ``` -#### Step 2 — Approve USDC.e on Tempo +Take the first returned number as `` (in stablecoin units, not ETH). -Approve the StargateOFTUSDC contract to spend USDC.e. +##### Step 2 - Approve token on Tempo ```bash cast send 0x20C000000000000000000000b9537d11c60E8b50 \ @@ -271,9 +285,9 @@ cast send 0x20C000000000000000000000b9537d11c60E8b50 \ --private-key $PRIVATE_KEY ``` -#### Step 3 — Send bridge transaction +##### Step 3 - Send bridge transaction -No `--value` is needed on Tempo — the messaging fee is paid in a TIP-20 stablecoin via [EndpointDollar](#endpointdollar). +No `--value` is needed on Tempo - the messaging fee is paid in a TIP-20 stablecoin via [EndpointDollar](#endpointdollar). ```bash cast send 0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392 \ @@ -285,17 +299,13 @@ cast send 0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392 \ --private-key $PRIVATE_KEY ``` -#### Step 4 — Verify transaction status - -Track the bridge with the transaction hash returned by `sendToken`: +##### Step 4 - Verify transaction status ```text https://scan.layerzero-api.com/v1/messages/tx/ ``` -Once delivered, view the destination transaction on the destination chain explorer. - -### Using TypeScript (viem) +#### Using TypeScript (viem) ```typescript import { createWalletClient, createPublicClient, http, parseUnits, pad } from 'viem' @@ -310,7 +320,7 @@ const walletClient = createWalletClient({ transport: http(), }) -// StargateOFTUSDC on Tempo +// Stargate OFT for USDC.e on Tempo const stargateOFT = '0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392' as const // USDC.e on Tempo const usdce = '0x20C000000000000000000000b9537d11c60E8b50' as const @@ -338,7 +348,7 @@ const msgFee = await publicClient.readContract({ args: [sendParam, false], }) -// 2. Approve USDC.e +// 2. Approve token await walletClient.writeContract({ address: usdce, abi: erc20Abi, @@ -346,7 +356,7 @@ await walletClient.writeContract({ args: [stargateOFT, amount], }) -// 3. Send the bridge transaction (no value — fee handled via EndpointDollar) +// 3. Send the bridge transaction (no value - fee handled via EndpointDollar) await walletClient.writeContract({ address: stargateOFT, abi: stargateAbi, @@ -355,36 +365,24 @@ await walletClient.writeContract({ }) ``` -## EndpointDollar - -Tempo has no native gas token, so there is no `msg.value`. Standard LayerZero endpoints require `msg.value` to pay messaging fees, which doesn't work on Tempo. - -**LZEndpointDollar** ([`0x0cEb237E109eE22374a567c6b09F373C73FA4cBb`](https://explore.tempo.xyz/address/0x0cEb237E109eE22374a567c6b09F373C73FA4cBb)) is an adapter contract that routes LayerZero messaging fees through a TIP-20 stablecoin instead of `msg.value`. It wraps the standard `EndpointV2` so that Stargate's OFT contracts can function on Tempo without modification. - -This is transparent for end users: - -- **Bridging to Tempo** — fees are paid in native gas on the source chain (ETH, MATIC, AVAX, etc.) as normal. -- **Bridging from Tempo** — `LZEndpointDollar` automatically deducts the messaging fee from a TIP-20 stablecoin. No `msg.value` is needed. -- **Developers** don't need to interact with `LZEndpointDollar` directly. The StargateOFTUSDC contract handles it internally. - -## Bus vs. Taxi mode +### Bus vs. Taxi mode Stargate offers two delivery modes: | Mode | `oftCmd` | Delivery | Cost | |------|----------|----------|------| -| **Taxi** | `0x` (empty) | Immediate — message sent right away | Higher gas cost | -| **Bus** | `0x00` (1 byte) | Batched — waits for other passengers | Lower gas cost | +| **Taxi** | `0x` (empty) | Immediate - message sent right away | Higher gas cost | +| **Bus** | `0x00` (1 byte) | Batched - waits for other passengers | Lower gas cost | -All examples above use taxi mode for immediate delivery. To use bus mode, set `oftCmd` to `0x00`: +All examples above use taxi mode. To use bus mode, set `oftCmd` to `0x00`: ```bash -# cast — bus mode +# cast - bus mode oftCmd=0x00 ``` ```typescript -// viem — bus mode +// viem - bus mode const sendParam = { // ... oftCmd: '0x00' as const, // bus mode @@ -395,9 +393,60 @@ const sendParam = { Bus mode is not available on all routes. If a bus route is not configured for your source/destination pair, the transaction will revert. Use taxi mode (`0x`) for guaranteed delivery. ::: +## Standard OFT tokens + +Tokens like USDT0, frxUSD, cUSD, and others are bridged using the standard LayerZero OFT `send()` interface. Each token issuer deploys their own OFT adapter contract. The `send()` interface uses the same `SendParam` struct as Stargate but calls `send()` instead of `sendToken()`. + +To bridge a standard OFT token, you need the OFT adapter contract address on the source chain. Refer to the token issuer's documentation for their deployment addresses: + +- **USDT0** - [Tether](https://tether.io) +- **frxUSD** - [Frax](https://docs.frax.com) +- **cUSD** - [Coinbase](https://docs.cdp.coinbase.com) + +The flow is the same as Stargate - quote, approve, send - but you call `send()` on the OFT adapter instead of `sendToken()` on a Stargate pool: + +```bash +# Quote +cast call \ + 'quoteSend((uint32,bytes32,uint256,uint256,bytes,bytes,bytes),bool)((uint256,uint256))' \ + "(30410,$(cast abi-encode 'f(address)' ),,,0x,0x,0x)" \ + false \ + --rpc-url + +# Approve +cast send \ + 'approve(address,uint256)' \ + \ + \ + --rpc-url \ + --private-key $PRIVATE_KEY + +# Send +cast send \ + 'send((uint32,bytes32,uint256,uint256,bytes,bytes,bytes),(uint256,uint256),address)' \ + "(30410,$(cast abi-encode 'f(address)' ),,,0x,0x,0x)" \ + "(,0)" \ + \ + --value \ + --rpc-url \ + --private-key $PRIVATE_KEY +``` + +## EndpointDollar + +Tempo has no native gas token, so there is no `msg.value`. Standard LayerZero endpoints require `msg.value` to pay messaging fees, which doesn't work on Tempo. + +**LZEndpointDollar** ([`0x0cEb237E109eE22374a567c6b09F373C73FA4cBb`](https://explore.tempo.xyz/address/0x0cEb237E109eE22374a567c6b09F373C73FA4cBb)) is an adapter contract that routes LayerZero messaging fees through a TIP-20 stablecoin instead of `msg.value`. It wraps the standard `EndpointV2` so that OFT contracts can function on Tempo without modification. + +This is transparent for end users: + +- **Bridging to Tempo** - fees are paid in native gas on the source chain (ETH, MATIC, AVAX, etc.) as normal. +- **Bridging from Tempo** - `LZEndpointDollar` automatically deducts the messaging fee from a TIP-20 stablecoin. No `msg.value` is needed. +- **Developers** don't need to interact with `LZEndpointDollar` directly. The OFT contracts on Tempo handle it internally. + ## Further reading -- [Stargate documentation](https://stargateprotocol.gitbook.io/stargate/v2-developer-docs) - [LayerZero V2 documentation](https://docs.layerzero.network/v2) +- [Stargate documentation](https://stargateprotocol.gitbook.io/stargate/v2-developer-docs) - [Bridges & Exchanges on Tempo](/ecosystem/bridges) - [Getting Funds on Tempo](/guide/getting-funds) diff --git a/src/pages/guide/bridge-relay.mdx b/src/pages/guide/bridge-relay.mdx new file mode 100644 index 00000000..8c92ecd7 --- /dev/null +++ b/src/pages/guide/bridge-relay.mdx @@ -0,0 +1,339 @@ +--- +title: Bridge via Relay +description: Bridge tokens to and from Tempo using Relay. Includes supported token discovery, curl commands, TypeScript examples with viem, and status tracking. +--- + +# Bridge via Relay + +[Relay](https://relay.link/) is a cross-chain payments network powered by a solver that fills bridge requests instantly. Users deposit on the source chain and receive funds on the destination chain within seconds - no lock-and-mint or messaging protocol required. + +Tempo's Relay chain ID is **`4217`**. + +## Contracts on Tempo + +| Contract | Address | +|----------|---------| +| **ERC20Router** | [`0xb92fe925dc43a0ecde6c8b1a2709c170ec4fff4f`](https://explore.tempo.xyz/address/0xb92fe925dc43a0ecde6c8b1a2709c170ec4fff4f) | +| **ApprovalProxy** | [`0xccc88a9d1b4ed6b0eaba998850414b24f1c315be`](https://explore.tempo.xyz/address/0xccc88a9d1b4ed6b0eaba998850414b24f1c315be) | + +## Supported tokens + +Query the Relay chains API to see which tokens currently support bridging on Tempo: + +```bash +curl -s "https://api.relay.link/chains" | jq '.chains[] | select(.id == 4217) | .erc20Currencies[] | select(.supportsBridging == true) | {symbol, name, address, decimals}' +``` + +The list of supported tokens changes over time as Relay adds new routes. Always check the API for the latest availability. + +## How Relay works + +Relay uses an intent-based model with three steps: + +1. **Quote** - Request a quote from the Relay API specifying origin chain, destination chain, currencies, and amount. The API returns ready-to-sign transaction data. +2. **Execute** - Submit the transaction to the source chain. The user deposits funds into Relay's depository contract. +3. **Fill** - A Relay solver detects the deposit and fills the request on the destination chain, typically within seconds. + +For ERC-20 tokens, the quote response includes any required approval steps automatically. + +## Bridge to Tempo + +### Using the Relay app + +1. Go to [relay.link/bridge](https://relay.link/bridge) +2. Select your source chain and token +3. Set **Tempo** as the destination chain and choose the destination token +4. Enter the amount and confirm the transaction + +### Using curl + cast (Foundry) + +This example bridges USDC.e (Bridged USDC) from Base to Tempo. Replace the currency addresses and chain IDs for other tokens or routes. + +#### Step 1 - Get a quote + +Replace `` with your wallet address and `` with the amount in base units (e.g. `1000000` for 1 USDC.e with 6 decimals). + +```bash +curl -X POST "https://api.relay.link/quote/v2" \ + -H "Content-Type: application/json" \ + -d '{ + "user": "", + "originChainId": 8453, + "destinationChainId": 4217, + "originCurrency": "", + "destinationCurrency": "", + "amount": "", + "tradeType": "EXACT_INPUT" + }' +``` + +The response contains a `steps` array with transaction data. Save the `requestId` from the step for tracking. + +#### Step 2 - Approve token (if required) + +If the quote response includes an approval step, approve the Relay contract to spend your tokens. The approval target address is provided in the quote response's step data. + +```bash +cast send \ + 'approve(address,uint256)' \ + \ + \ + --rpc-url https://mainnet.base.org \ + --private-key $PRIVATE_KEY +``` + +#### Step 3 - Submit the deposit transaction + +Use the `to`, `data`, and `value` fields from the quote response's transaction step: + +```bash +cast send \ + \ + --value \ + --rpc-url https://mainnet.base.org \ + --private-key $PRIVATE_KEY +``` + +#### Step 4 - Track status + +Poll the status endpoint with the `requestId` from the quote response: + +```bash +curl "https://api.relay.link/intents/status/v3?requestId=" +``` + +Status values: `waiting` -> `depositing` -> `pending` -> `success`. + +Once complete, view the destination transaction on Tempo: + +```text +https://explore.tempo.xyz/tx/ +``` + +### Using TypeScript (viem) + +```typescript +import { createWalletClient, createPublicClient, http } from 'viem' +import { base } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' + +const account = privateKeyToAccount('0x...') + +const walletClient = createWalletClient({ + account, + chain: base, + transport: http(), +}) + +const publicClient = createPublicClient({ + chain: base, + transport: http(), +}) + +// 1. Get a quote from Relay +const quoteRes = await fetch('https://api.relay.link/quote/v2', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + user: account.address, + originChainId: 8453, // Base + destinationChainId: 4217, // Tempo + originCurrency: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base + destinationCurrency: '0x20C000000000000000000000b9537d11c60E8b50', // USDC.e on Tempo + amount: '1000000', // 1 USDC (6 decimals) + tradeType: 'EXACT_INPUT', + }), +}) + +const quote = await quoteRes.json() + +// 2. Execute each step (approval + deposit) +for (const step of quote.steps) { + for (const item of step.items) { + if (step.kind === 'transaction') { + const hash = await walletClient.sendTransaction({ + to: item.data.to, + data: item.data.data, + value: BigInt(item.data.value || '0'), + }) + + // Wait for confirmation + await publicClient.waitForTransactionReceipt({ hash }) + } + } +} + +// 3. Poll for completion +const requestId = quote.steps[0].requestId + +const pollStatus = async () => { + while (true) { + const statusRes = await fetch( + `https://api.relay.link/intents/status/v3?requestId=${requestId}` + ) + const status = await statusRes.json() + + if (status.status === 'success') { + console.log('Bridge complete:', status.txHashes) + return status + } + if (status.status === 'failure') { + throw new Error('Bridge failed') + } + + await new Promise((r) => setTimeout(r, 1000)) + } +} + +await pollStatus() +``` + +## Bridge from Tempo + +To bridge tokens from Tempo to another chain, swap the origin and destination in the quote request. + +### Using curl + cast (Foundry) + +#### Step 1 - Get a quote + +```bash +curl -X POST "https://api.relay.link/quote/v2" \ + -H "Content-Type: application/json" \ + -d '{ + "user": "", + "originChainId": 4217, + "destinationChainId": 8453, + "originCurrency": "", + "destinationCurrency": "", + "amount": "", + "tradeType": "EXACT_INPUT" + }' +``` + +#### Step 2 - Approve token (if required) + +If the quote includes an approval step, approve the Relay contract to spend your tokens on Tempo. + +```bash +cast send \ + 'approve(address,uint256)' \ + \ + \ + --rpc-url https://rpc.tempo.xyz \ + --private-key $PRIVATE_KEY +``` + +#### Step 3 - Submit the deposit transaction + +Use the `to`, `data`, and `value` fields from the quote response: + +```bash +cast send \ + \ + --rpc-url https://rpc.tempo.xyz \ + --private-key $PRIVATE_KEY +``` + +:::info +Tempo has no native gas token, so no `--value` flag is needed. Transaction fees on Tempo are paid in a TIP-20 stablecoin automatically. +::: + +#### Step 4 - Track status + +```bash +curl "https://api.relay.link/intents/status/v3?requestId=" +``` + +### Using TypeScript (viem) + +```typescript +import { createWalletClient, createPublicClient, http } from 'viem' +import { tempo } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' + +const account = privateKeyToAccount('0x...') + +const walletClient = createWalletClient({ + account, + chain: tempo, + transport: http(), +}) + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}) + +// 1. Get a quote from Relay (Tempo -> Base) +const quoteRes = await fetch('https://api.relay.link/quote/v2', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + user: account.address, + originChainId: 4217, // Tempo + destinationChainId: 8453, // Base + originCurrency: '0x20C000000000000000000000b9537d11c60E8b50', // USDC.e on Tempo + destinationCurrency: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base + amount: '1000000', // 1 USDC.e (6 decimals) + tradeType: 'EXACT_INPUT', + }), +}) + +const quote = await quoteRes.json() + +// 2. Execute each step +for (const step of quote.steps) { + for (const item of step.items) { + if (step.kind === 'transaction') { + const hash = await walletClient.sendTransaction({ + to: item.data.to, + data: item.data.data, + value: BigInt(item.data.value || '0'), + }) + + await publicClient.waitForTransactionReceipt({ hash }) + } + } +} + +// 3. Poll for completion +const requestId = quote.steps[0].requestId + +const pollStatus = async () => { + while (true) { + const statusRes = await fetch( + `https://api.relay.link/intents/status/v3?requestId=${requestId}` + ) + const status = await statusRes.json() + + if (status.status === 'success') { + console.log('Bridge complete:', status.txHashes) + return status + } + if (status.status === 'failure') { + throw new Error('Bridge failed') + } + + await new Promise((r) => setTimeout(r, 1000)) + } +} + +await pollStatus() +``` + +## Supported chains + +Relay supports bridging to and from Tempo on many chains. Query the Relay API for the full list: + +```bash +curl "https://api.relay.link/chains" +``` + +Common routes include Ethereum, Base, Arbitrum, Optimism, Polygon, and more. See [Relay's supported chains](https://docs.relay.link/resources/supported-chains) for the complete list. + +## Further reading + +- [Relay documentation](https://docs.relay.link) +- [Relay API reference](https://docs.relay.link/references/api/overview) +- [Bridges & Exchanges on Tempo](/ecosystem/bridges) +- [Getting Funds on Tempo](/guide/getting-funds) diff --git a/vercel.json b/vercel.json index 4bc4289f..edee13aa 100644 --- a/vercel.json +++ b/vercel.json @@ -21,6 +21,16 @@ ], "destination": "https://docs.tempo.xyz/guide/getting-funds", "permanent": false + }, + { + "source": "/guide/bridge-usdc-stargate", + "destination": "/guide/bridge-layerzero", + "permanent": true + }, + { + "source": "/guide/bridge-usdc-relay", + "destination": "/guide/bridge-relay", + "permanent": true } ], "rewrites": [ diff --git a/vocs.config.ts b/vocs.config.ts index 77c68a8a..faad1982 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -282,8 +282,18 @@ export default defineConfig({ link: '/quickstart/verify-contracts', }, { - text: 'Bridge USDC via Stargate', - link: '/guide/bridge-usdc-stargate', + text: 'Bridging Guides', + collapsed: true, + items: [ + { + text: 'Bridge via LayerZero', + link: '/guide/bridge-layerzero', + }, + { + text: 'Bridge via Relay', + link: '/guide/bridge-relay', + }, + ], }, { text: 'Ecosystem',