Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Bridge, swap, or send funds from any wallet whose private key is in `.env`, routing through the LI.FI API. Three modes — `bridge` (move the native gas asset cross-chain, same wallet on both ends), `swap` (same-chain native↔ERC-20 in either direction, same wallet), and `send` (gas asset to a different recipient). Use whenever an agent or engineer needs to move or provision funds for one of our wallets: "the dev wallet is out of gas on BSC", "bridge some ETH to base to test a route", "swap native
.claude/skills/lifinance-manage-wallet-funds/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 19% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 22% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 50% | 0% |
Move funds for any wallet we hold the key for, using the LI.FI API as the router. The engine is script/tasks/manageWalletFunds.ts; this document is the policy around it.
/manage-wallet-funds <free-form request>cast do not apply there;route to /interact-tron. Say so and stop.
request-dev-funds (a PR flow), not this direct-key path.
Custody is the line. A move that keeps funds inside one wallet cannot lose them to anyone, so it needs no human in the loop. A move that changes who controls the funds can, so it always does.
| Mode | Destination | Behaviour | |------|-------------|-----------| | bridge | same wallet, other chain | autonomous — no confirmation | | swap | same wallet, same chain | autonomous — no confirmation | | send | a different recipient | refuses to broadcast without --confirm |
For bridge/swap the script quotes with toAddress == fromAddress and asserts it before broadcasting; if anything makes the destination differ from the source, it aborts. For send, the recipient differs by definition, so the script prints the report and exits unless a human passes --confirm after reading it. An agent or sub-agent must never supply --confirm itself, and must never treat a broad task ("get the deployment working") as standing permission to send funds to another address.
The script reads a private key from .env and signs a real, irreversible transaction.
report. The script only ever surfaces the derived address.
host, never the query string.
Pass --wallet as a role or a raw address:
devWallet, refundWallet, deployerWallet, pauserWallet,withdrawWallet, backendSignerProduction, …) → resolved via config/global.json walletKeys to the matching .env variable, then the address is derived from the key.
0x… → matched against the addresses derived from every key in the registryand any other *PRIVATE_KEY* variable in .env. If no key derives to it, the script refuses — it can only move funds it holds the key for.
The address is always derived from the key, and cross-checked against the address global.json records for that role; a mismatch aborts — a wrong or stale key must not silently operate a different wallet, so if the wallet was rotated, update global.json first. feeCollectorOwner has no key in .env and cannot be driven here.
Prefer the wallet the request names. refundWallet / withdrawWallet are CTO-owned — double-check intent before moving their funds.
Add --dry-run first to validate the route and the same-wallet gate without signing — useful before any real move.
bash# bridge native gas, same wallet, arbitrum -> bsc bunx tsx script/tasks/manageWalletFunds.ts bridge --wallet devWallet \ --from-network arbitrum --to-network bsc --amount 0.01 [--dry-run] # swap native -> USDC on base, same wallet bunx tsx script/tasks/manageWalletFunds.ts swap --wallet devWallet \ --network base --from-token native --to-token USDC --amount 0.01 [--dry-run] # send native gas to a different recipient — prints a report and STOPS bunx tsx script/tasks/manageWalletFunds.ts send --wallet devWallet \ --network bsc --to 0xRecipient --amount 0.01
For send, a human appends --confirm to the command above after reading the report. An agent must never add it — that is the whole point of the gate, so the example is intentionally left un-confirmed.
One broadcast per invocation: each command signs at most one transaction; confirm the result before running the next. Do not loop this script to fire several transfers inside a single step.
Amount is either --amount <human> (of the input asset) or --percent <n> of the native balance (native inputs only; leaves headroom for gas). --max-slippage caps tolerated value loss and defaults to 3% — the script aborts if the quote's USD-measured loss exceeds it, or if the route has no USD pricing to check against.
Tokens are native, a 0x… address, or a symbol (resolved via the LI.FI token list; an ambiguous symbol aborts — pass the address).
send moves the true native asset (a plain value transfer). On chains where gas is paid in an ERC-20 rather than a spendable native coin — a gas-token predeploy (arc, where gas is USDC) or the "no native currency" model (tempo, gas via a feeTokenAddress) — send refuses rather than broadcasting the wrong thing (or nothing). bridge/swap still route those through LI.FI normally; a direct send there is a follow-up.
Routing goes through the LI.FI API only. Before quoting, the script checks both chains against the API's supported-chain list. A chain that is still being added is not indexed yet, so the script stops and says to move those funds manually rather than hang. This is expected for brand-new networks.
swap / send confirm synchronously — the script waits for the receipt and reports theexplorer link and resulting balance.
bridge delivers to the destination asynchronously — the source tx confirms quickly,then the script polls the LI.FI status endpoint until the destination funds land (or reports where to track it if it is still pending). Do not expect the destination balance to update the instant the source tx confirms.
interact-tron — the Tron analog; route here when the chain is Tron.request-dev-funds — fund a wallet from the automate-wallet via a PR, when there isno source wallet to move from.
sweep-wallet-funds — drain a rotated-out wallet's native gas across every chain duringa rotation.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→fail | 8,767 | 7,188 | -18% | 1 | 1 | 0% | 1,393 | 2,064 | +48% | 0 | 0 | — |
case-01 | fail→pass | 11,084 | 2,426 | -78% | 1 | 1 | 0% | 1,747 | 2,071 | +19% | 0 | 0 | — |
case-03 | fail→fail | 11,109 | 7,280 | -34% | 1 | 1 | 0% | 692 | 2,140 | +209% | 0 | 0 | — |
case-04 | fail→pass | 12,156 | 4,649 | -62% | 1 | 1 | 0% | 1,978 | 2,414 | +22% | 0 | 0 | — |
case-05 | fail→pass | 9,328 | 1,996 | -79% | 1 | 1 | 0% | 1,545 | 1,945 | +26% | 0 | 0 | — |
case-06 | pass→pass | 18,835 | 2,619 | -86% | 1 | 1 | 0% | 3,230 | 2,050 | -37% | 0 | 0 | — |
case-07 | pass→pass | 11,629 | 4,097 | -65% | 1 | 1 | 0% | 1,886 | 2,351 | +25% | 0 | 0 | — |
case-08 | fail→pass | 10,288 | 1,608 | -84% | 1 | 1 | 0% | 1,494 | 1,845 | +23% | 0 | 0 | — |
case-09 | fail→pass | 7,659 | 2,526 | -67% | 1 | 1 | 0% | 1,333 | 1,998 | +50% | 0 | 0 | — |
case-10 | pass→pass | 12,238 | 2,376 | -81% | 1 | 1 | 0% | 2,112 | 1,973 | -7% | 0 | 0 | — |
case-11 | pass→pass | 8,870 | 1,764 | -80% | 1 | 1 | 0% | 1,298 | 1,922 | +48% | 0 | 0 | — |
case-12 | pass→pass | 8,150 | 1,929 | -76% | 1 | 1 | 0% | 1,244 | 1,953 | +57% | 0 | 0 | — |
case-13 | fail→pass | 10,396 | 3,290 | -68% | 1 | 1 | 0% | 1,662 | 2,098 | +26% | 0 | 0 | — |
case-14 | fail→pass | 7,663 | 2,622 | -66% | 1 | 1 | 0% | 1,321 | 2,014 | +52% | 0 | 0 | — |
case-19 | pass→pass | 13,516 | 3,018 | -78% | 1 | 1 | 0% | 1,963 | 2,111 | +8% | 0 | 0 | — |
case-15 | fail→pass | 13,800 | 5,900 | -57% | 1 | 1 | 0% | 2,061 | 2,572 | +25% | 0 | 0 | — |
case-16 | pass→pass | 10,078 | 3,448 | -66% | 1 | 1 | 0% | 1,581 | 2,247 | +42% | 0 | 0 | — |
case-17 | pass→pass | 11,245 | 2,488 | -78% | 1 | 1 | 0% | 1,721 | 1,928 | +12% | 0 | 0 | — |
case-18 | pass→pass | 11,566 | 4,154 | -64% | 1 | 1 | 0% | 1,634 | 2,311 | +41% | 0 | 0 | — |
case-20 | fail→pass | 15,002 | 1,499 | -90% | 1 | 1 | 0% | 2,277 | 1,858 | -18% | 0 | 0 | — |
case-21 | pass→pass | 10,347 | 3,133 | -70% | 1 | 1 | 0% | 1,514 | 2,071 | +37% | 0 | 0 | — |
case-22 | fail→pass | 10,575 | 2,789 | -74% | 1 | 1 | 0% | 1,618 | 2,045 | +26% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +45 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.