Skip to main content

Documentation Index

Fetch the complete documentation index at: https://eco.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

This recipe builds a server-side rebalancer that programmatically moves treasury USDC between chains based on a threshold (e.g. utilization, yield differential, opportunity).

When to use

  • Multi-chain protocols managing distributed treasury
  • Yield managers chasing the highest opportunity across chains
  • Operational treasuries that want to remove manual rebalancing

1. Define the trigger

interface RebalancePolicy {
  sourceChain: number;
  destChain: number;
  token: string;            // USDC on dest
  threshold: bigint;        // Trigger amount
  minTransfer: bigint;
}

async function shouldRebalance(p: RebalancePolicy): Promise<bigint | null> {
  const sourceBal = await getBalance(p.sourceChain);
  const destBal = await getBalance(p.destChain);
  const delta = sourceBal - destBal;
  if (delta < p.threshold) return null;
  return delta / 2n;        // Move half the gap
}

2. Get a quote for the rebalance

A treasury rebalance is a simple transfer between two of your wallets. Use the V3 quote API with the source treasury as funder and the destination treasury as recipient.
const res = await fetch('https://quotes.eco.com/api/v3/quotes/single', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    dAppID: 'treasury-rebalancer',
    quoteRequest: {
      sourceChainID: policy.sourceChain,
      destinationChainID: policy.destChain,
      sourceToken: policy.sourceToken,
      destinationToken: policy.destToken,
      sourceAmount: amount.toString(),
      funder: SOURCE_TREASURY,
      recipient: DEST_TREASURY,
    },
  }),
});
const quote = await res.json();

3. Approve, publish, fund

Approve the reward token to quote.data.contracts.sourcePortal, then call publishAndFund(destinationChainID, encodedRoute, reward, false) — same exact pattern as Sending USDC across chains.

4. Run on a schedule

async function tick() {
  for (const policy of POLICIES) {
    const amount = await shouldRebalance(policy);
    if (amount && amount > policy.minTransfer) {
      await publishRebalance(policy, amount);
    }
  }
}

setInterval(tick, 60_000);

5. Atomicity guarantee

Each rebalance is a single intent. It either fully completes or refunds. There is no partial-state reconciliation. If a single intent expires, the refund service returns funds and the next tick can retry.

Audit trail

Every rebalance leaves a verifiable on-chain trail:
  • IntentPublished on source Portal (with reward + amount)
  • IntentFulfilled on destination Portal (with claimant)
  • IntentWithdrawn on source Portal (reward release)
You’ve successfully built an atomic, auditable cross-chain rebalancer.