
Symbiosis
- 1 installs
- 1.2k repo stars
- Updated August 1, 2026
- bankrbot/moltbot-skills
Symbiosis is a Claude Code skill that lets an agent swap or bridge tokens across 54+ blockchains via the Symbiosis protocol, executing transactions through the Bankr Submit API.
About
Symbiosis is a Claude skill for swapping and bridging tokens between blockchains. An agent uses it to get a cross-chain quote or execute an any-to-any token swap across Base, Ethereum, Polygon, Arbitrum, Solana, Bitcoin and 40+ other chains. Transactions are submitted through the Bankr Submit API using the user's existing Bankr wallet, so no extra keys are needed.
- Cross-chain token swaps across 54+ blockchains via Symbiosis
- Executes swaps through the Bankr Submit API using the user's Bankr wallet
- Ships quote and swap Python scripts with chain/token address tables
Symbiosis by the numbers
- 1 all-time installs (skills.sh)
- Ranked #426 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
symbiosis capabilities & compatibility
- Capabilities
- cross chain swap · token bridge · defi quote
- Use cases
- trading
- Runs
- Runs locally
- Pricing
- Bring your own API key
What symbiosis says it does
Cross-chain token swaps across 54+ blockchains. Swap any token on any chain to any token on any other chain.
All transactions are submitted through the Bankr Submit API using the user's Bankr wallet. No additional wallets or keys needed.
npx skills add https://github.com/bankrbot/moltbot-skills --skill symbiosisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | August 1, 2026 |
| Repository | bankrbot/moltbot-skills ↗ |
What it does
Bridge or swap a token from one blockchain to another from inside an agent using the user's Bankr wallet.
Who is it for?
Bridging or swapping tokens between chains beyond Bankr's native 5, including to Bitcoin, TON, Tron or Solana.
Skip if: Same-chain-only swaps where a native Bankr swap already works.
When should I use this skill?
The user wants to bridge or swap tokens between different chains or get a cross-chain quote.
What you get
An executed cross-chain swap with a transaction hash and an Explorer tracking link.
- Executed cross-chain swap transaction
- Cross-chain quote
- Explorer tracking link
By the numbers
- Cross-chain swaps across 54+ blockchains
- Two Python scripts (quote and swap)
Files
Symbiosis
Cross-chain token swaps across 54+ blockchains. Swap any token on any chain to any token on any other chain.
When To Use
Use Symbiosis when the user wants to:
- Bridge or swap tokens between different chains (e.g., USDC from Base to Polygon, ETH from Ethereum to Arbitrum)
- Access chains beyond Bankr's native 5 (Arbitrum, Optimism, BNB Chain, Avalanche, zkSync, Linea, Scroll, Mantle, Blast, and 40+ more)
- Swap to/from Bitcoin, TON, or Tron
- Get a cross-chain quote without executing
Quick Start
Get a Quote
How much USDC will I get on Polygon if I bridge 10 USDC from Base?Run the quote script:
scripts/symbiosis-quote.py 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 10 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 6Execute a Swap
Bridge 2 USDC from Base to Polygon using SymbiosisRun the swap script:
scripts/symbiosis-swap.py 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 2 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 6Script Usage
symbiosis-swap.py
Executes a full cross-chain swap: gets quote from Symbiosis API, approves token if needed, submits swap transaction via Bankr Submit API.
scripts/symbiosis-swap.py <src_chain_id> <src_token_address> <src_decimals> <amount> <dst_chain_id> <dst_token_address> <dst_decimals> [slippage]amount— human-readable (e.g., "2" for 2 USDC, "0.1" for 0.1 ETH)slippage— optional, in basis points (default: 200 = 2%)- Reads Bankr API key from
~/.bankr/config.json - Automatically gets wallet address from Bankr
- Outputs transaction hash and Explorer tracking link
symbiosis-quote.py
Gets a quote without executing. Same arguments, no slippage parameter.
scripts/symbiosis-quote.py <src_chain_id> <src_token_address> <src_decimals> <amount> <dst_chain_id> <dst_token_address> <dst_decimals>Common Chains and Tokens
Bankr Wallet Chains
| Chain | ID | USDC Address | USDC Dec |
|---|---|---|---|
| Base | 8453 | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | 6 |
| Ethereum | 1 | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | 6 |
| Polygon | 137 | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 | 6 |
Additional Chains via Symbiosis
| Chain | ID | USDC Address | USDC Dec |
|---|---|---|---|
| Arbitrum | 42161 | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 | 6 |
| Optimism | 10 | 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85 | 6 |
| BNB Chain | 56 | 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d | 18 |
| Avalanche | 43114 | 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E | 6 |
Native Tokens
Use 0x0000000000000000000000000000000000000000 as address for native gas tokens (ETH, POL, BNB, AVAX, etc.).
Reference: references/chains-and-tokens.md for the full list.
Examples
EVM to EVM
# 5 USDC: Base -> Arbitrum
scripts/symbiosis-swap.py 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 5 42161 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 6
# 0.01 ETH: Ethereum -> Base
scripts/symbiosis-swap.py 1 0x0000000000000000000000000000000000000000 18 0.01 8453 0x0000000000000000000000000000000000000000 18
# 10 USDC: Polygon -> BNB Chain
scripts/symbiosis-swap.py 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 6 10 56 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d 18
# 0.5 ETH: Base -> Optimism
scripts/symbiosis-swap.py 8453 0x0000000000000000000000000000000000000000 18 0.5 10 0x0000000000000000000000000000000000000000 18Cross-ecosystem (Symbiosis-only routes)
# 10 USDC: Base -> Solana
# Note: Solana chain ID in Symbiosis is 5426
# Solana USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (but use Symbiosis synthetic address)
scripts/symbiosis-swap.py 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 10 5426 0x0000000000000000000000000000000000000000 9Prompt Examples
Users might say:
- "Bridge 5 USDC from Base to Arbitrum"
- "Swap 0.1 ETH from Ethereum to Polygon"
- "Move my USDC from Base to Optimism"
- "How much will I get if I bridge 100 USDC from Base to Avalanche?"
- "Cross-chain swap 50 USDC from Polygon to BNB Chain"
- "Bridge ETH from Base to Solana"
For each request: identify source chain + token, destination chain + token, look up chain IDs and token addresses from the tables above, and run the appropriate script.
How It Works
1. Quote: Script calls Symbiosis API (POST /crosschain/v1/swap) with token details and wallet address 2. Approve: If source token needs approval, script submits an ERC20 approve transaction via POST https://api.bankr.bot/agent/submit 3. Swap: Script submits the swap transaction via POST https://api.bankr.bot/agent/submit 4. Track: Returns an Explorer link for cross-chain status tracking
All transactions are submitted through the Bankr Submit API using the user's Bankr wallet. No additional wallets or keys needed.
Resources
- Explorer: https://explorer.symbiosis.finance
- Website: https://symbiosis.finance
- API Docs: references/api-reference.md
- Chains & Tokens: references/chains-and-tokens.md
Symbiosis API Reference
Base URL: https://api-v2.symbiosis.finance
POST /crosschain/v1/swap
Get a cross-chain swap quote with executable calldata.
Request
{
"tokenAmountIn": {
"chainId": 8453,
"address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"decimals": 6,
"amount": "2000000"
},
"tokenOut": {
"chainId": 137,
"address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"decimals": 6
},
"from": "0xUserAddress",
"to": "0xUserAddress",
"slippage": 200,
"partnerId": "bankr"
}Fields:
tokenAmountIn.amount— amount in smallest units (e.g., "2000000" for 2 USDC with 6 decimals)slippage— in basis points (200 = 2%, recommended default)partnerId— always use "bankr"from/to— user's wallet addresses (can be different for cross-chain)
Response
{
"tx": {
"to": "0x691df9C4561d95a4a726313089c8536dd682b946",
"data": "0x...",
"value": "0",
"chainId": 8453
},
"approveTo": "0x41Ae964d0F61Bb5F5e253141A462aD6F3b625B92",
"tokenAmountOut": {
"address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"amount": "1497245",
"chainId": 137,
"decimals": 6
},
"fee": {
"amount": "250000",
"decimals": 6,
"priceUsd": 1.0
},
"estimatedTime": 32
}Key fields:
tx— the swap transaction to submit on the source chainapproveTo— if present, you must approve this spender before the swaptokenAmountOut.amount— expected output in smallest unitsestimatedTime— seconds until destination chain receives funds
Amount Conversion
| Human Amount | Decimals | Smallest Units |
|---|---|---|
| 2 USDC | 6 | "2000000" |
| 0.1 ETH | 18 | "100000000000000000" |
| 100 USDT | 6 | "100000000" |
| 1.5 BNB | 18 | "1500000000000000000" |
Formula: amount_smallest = human_amount * 10^decimals
POST /crosschain/v2/swap
Bitcoin-specific endpoint. Returns a deposit address instead of calldata.
Response (Bitcoin)
{
"depositAddress": "bc1q...",
"depositAddressExpiry": 1234567890,
"tokenAmountOut": { ... }
}The user sends BTC to depositAddress before depositAddressExpiry.
GET /crosschain/v1/chains
Returns all supported chains.
Cross-Chain Status Tracking
After submitting a swap transaction, track status at: https://explorer.symbiosis.finance/transactions/<sourceChainId>/<txHash>
Typical completion: 15-60 seconds for most routes, up to 10 minutes for congested chains.
Supported Chains and Common Tokens
Chains Supported by Both Bankr and Symbiosis
| Chain | Chain ID | Native Token | Decimals |
|---|---|---|---|
| Base | 8453 | ETH | 18 |
| Ethereum | 1 | ETH | 18 |
| Polygon | 137 | POL | 18 |
| Unichain | 130 | ETH | 18 |
| Solana | 5426 | SOL | 9 |
Additional Chains (Symbiosis-only, not native to Bankr)
| Chain | Chain ID | Native Token | Decimals |
|---|---|---|---|
| Arbitrum One | 42161 | ETH | 18 |
| Optimism | 10 | ETH | 18 |
| BNB Chain | 56 | BNB | 18 |
| Avalanche C-Chain | 43114 | AVAX | 18 |
| Gnosis | 100 | xDAI | 18 |
| zkSync Era | 324 | ETH | 18 |
| Linea | 59144 | ETH | 18 |
| Scroll | 534352 | ETH | 18 |
| Mantle | 5000 | MNT | 18 |
| Blast | 81457 | ETH | 18 |
| Mode | 34443 | ETH | 18 |
| Sei | 1329 | SEI | 18 |
| Gravity | 1625 | G | 18 |
| ZetaChain | 7000 | ZETA | 18 |
| Cronos | 25 | CRO | 18 |
| Bitcoin | 3652501241 | BTC | 8 |
| TON | 85918 | TON | 9 |
| Tron | 728126428 | TRX | 6 |
For the full list of 54+ chains, query: GET https://api-v2.symbiosis.finance/crosschain/v1/chains
Common Token Addresses
USDC
| Chain | Address | Decimals |
|---|---|---|
| Base (8453) | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | 6 |
| Ethereum (1) | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 | 6 |
| Polygon (137) | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 | 6 |
| Arbitrum (42161) | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 | 6 |
| Optimism (10) | 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85 | 6 |
| BNB Chain (56) | 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d | 18 |
| Avalanche (43114) | 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E | 6 |
USDT
| Chain | Address | Decimals |
|---|---|---|
| Ethereum (1) | 0xdAC17F958D2ee523a2206206994597C13D831ec7 | 6 |
| BNB Chain (56) | 0x55d398326f99059fF775485246999027B3197955 | 18 |
| Polygon (137) | 0xc2132D05D31c914a87C6611C10748AEb04B58e8F | 6 |
| Arbitrum (42161) | 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 | 6 |
| Optimism (10) | 0x94b008aA00579c1307B0EF2c499aD98a8ce58e58 | 6 |
| Avalanche (43114) | 0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7 | 6 |
Native Gas Tokens
Use address 0x0000000000000000000000000000000000000000 with the appropriate decimals for the chain's native token (ETH=18, POL=18, BNB=18, SOL=9, BTC=8, etc.).
Bitcoin (Special)
Bitcoin uses the Symbiosis v2 API (/crosschain/v2/swap) and returns a deposit address instead of calldata. The user must send BTC to the deposit address manually. The deposit address has an expiration time.
Solana (Special)
Solana inbound swaps are limited to SOL and USDC as destination tokens. Outbound from Solana works for SOL and USDC as source.
#!/usr/bin/env python3
"""Symbiosis cross-chain quote (no execution).
Usage: ./symbiosis-quote.sh <src_chain> <src_token> <src_decimals> <amount> <dst_chain> <dst_token> <dst_decimals>
Example: ./symbiosis-quote.sh 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 100 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 6
"""
import json
import sys
import urllib.request
SYMBIOSIS_API = "https://api-v2.symbiosis.finance/crosschain/v1/swap"
PARTNER_ID = "bankr"
FAKE_ADDR = "0x1111111111111111111111111111111111111111"
def to_smallest_units(amount: str, decimals: int) -> str:
parts = amount.split(".")
integer = parts[0]
frac = parts[1] if len(parts) > 1 else ""
frac = (frac + "0" * decimals)[:decimals]
return str(int(integer + frac))
def format_units(amount_raw: str, decimals: int) -> str:
s = amount_raw.zfill(decimals + 1)
int_part = s[: len(s) - decimals] or "0"
frac_part = s[len(s) - decimals :].rstrip("0")
return f"{int_part}.{frac_part}" if frac_part else int_part
def api_post(url: str, payload: dict) -> dict:
req = urllib.request.Request(
url,
data=json.dumps(payload).encode(),
headers={
"Content-Type": "application/json",
"User-Agent": "symbiosis-bankr-skill/1.0",
},
)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def main():
if len(sys.argv) < 8:
print(__doc__.strip())
sys.exit(1)
src_chain = int(sys.argv[1])
src_token = sys.argv[2]
src_dec = int(sys.argv[3])
amount = sys.argv[4]
dst_chain = int(sys.argv[5])
dst_token = sys.argv[6]
dst_dec = int(sys.argv[7])
result = api_post(SYMBIOSIS_API, {
"tokenAmountIn": {
"chainId": src_chain,
"address": src_token,
"decimals": src_dec,
"amount": to_smallest_units(amount, src_dec),
},
"tokenOut": {
"chainId": dst_chain,
"address": dst_token,
"decimals": dst_dec,
},
"from": FAKE_ADDR,
"to": FAKE_ADDR,
"slippage": 200,
"partnerId": PARTNER_ID,
})
if "tx" not in result:
msg = result.get("message", result.get("error", json.dumps(result)))
print(f"ERROR: {msg}", file=sys.stderr)
sys.exit(1)
out = result.get("tokenAmountOut", {})
out_human = format_units(out.get("amount", "0"), out.get("decimals", dst_dec))
fee = result.get("fee", {})
fee_human = float(format_units(fee.get("amount", "0"), fee.get("decimals", 6)))
fee_usd = fee_human * fee.get("priceUsd", 1)
est = result.get("estimatedTime", "?")
print(f"{amount} -> {out_human} (chain {src_chain} -> {dst_chain})")
print(f"Fee: ~${fee_usd:.4f}")
print(f"Estimated time: {est}s")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Symbiosis cross-chain swap via Bankr Submit API.
Usage: ./symbiosis-swap.sh <src_chain> <src_token> <src_decimals> <amount> <dst_chain> <dst_token> <dst_decimals> [slippage]
Example: ./symbiosis-swap.sh 8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 6 2 137 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 6
(2 USDC from Base to Polygon)
"""
import json
import os
import sys
import urllib.request
SYMBIOSIS_API = "https://api-v2.symbiosis.finance/crosschain/v1/swap"
BANKR_API = "https://api.bankr.bot"
PARTNER_ID = "bankr"
ZERO_ADDR = "0x0000000000000000000000000000000000000000"
MAX_UINT256 = "f" * 64
def to_smallest_units(amount: str, decimals: int) -> str:
parts = amount.split(".")
integer = parts[0]
frac = parts[1] if len(parts) > 1 else ""
frac = (frac + "0" * decimals)[:decimals]
return str(int(integer + frac))
def format_units(amount_raw: str, decimals: int) -> str:
s = amount_raw.zfill(decimals + 1)
int_part = s[: len(s) - decimals] or "0"
frac_part = s[len(s) - decimals :].rstrip("0")
return f"{int_part}.{frac_part}" if frac_part else int_part
def api_post(url: str, payload: dict, headers: dict | None = None) -> dict:
hdrs = {"Content-Type": "application/json", "User-Agent": "symbiosis-bankr-skill/1.0"}
if headers:
hdrs.update(headers)
req = urllib.request.Request(url, data=json.dumps(payload).encode(), headers=hdrs)
with urllib.request.urlopen(req, timeout=60) as resp:
return json.loads(resp.read())
def api_get(url: str, headers: dict) -> dict:
hdrs = {"User-Agent": "symbiosis-bankr-skill/1.0"}
hdrs.update(headers)
req = urllib.request.Request(url, headers=hdrs)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def load_bankr_key() -> str:
config_path = os.environ.get("BANKR_CONFIG", os.path.expanduser("~/.bankr/config.json"))
if not os.path.exists(config_path):
print(f"ERROR: Bankr config not found at {config_path}", file=sys.stderr)
sys.exit(1)
with open(config_path) as f:
return json.load(f)["apiKey"]
def get_wallet(bankr_key: str) -> str:
result = api_get(
f"{BANKR_API}/agent/balances?chains=base",
{"X-API-Key": bankr_key},
)
return result["evmAddress"]
def bankr_submit(bankr_key: str, tx: dict, description: str) -> dict:
return api_post(
f"{BANKR_API}/agent/submit",
{
"transaction": tx,
"description": description,
"waitForConfirmation": True,
},
{"X-API-Key": bankr_key},
)
def main():
if len(sys.argv) < 8:
print(__doc__.strip())
sys.exit(1)
src_chain = int(sys.argv[1])
src_token = sys.argv[2]
src_dec = int(sys.argv[3])
amount = sys.argv[4]
dst_chain = int(sys.argv[5])
dst_token = sys.argv[6]
dst_dec = int(sys.argv[7])
slippage = int(sys.argv[8]) if len(sys.argv) > 8 else 200
# --- Setup ---
bankr_key = load_bankr_key()
wallet = get_wallet(bankr_key)
amount_wei = to_smallest_units(amount, src_dec)
print(f"Wallet: {wallet}")
print(f"Amount in smallest units: {amount_wei}")
# --- Step 1: Get quote + calldata from Symbiosis ---
print("\n=== Getting Symbiosis quote ===")
result = api_post(SYMBIOSIS_API, {
"tokenAmountIn": {
"chainId": src_chain,
"address": src_token,
"decimals": src_dec,
"amount": amount_wei,
},
"tokenOut": {
"chainId": dst_chain,
"address": dst_token,
"decimals": dst_dec,
},
"from": wallet,
"to": wallet,
"slippage": slippage,
"partnerId": PARTNER_ID,
})
if "tx" not in result:
msg = result.get("message", result.get("error", json.dumps(result)))
print(f"ERROR from Symbiosis API: {msg}", file=sys.stderr)
sys.exit(1)
tx = result["tx"]
approve_to = result.get("approveTo", "")
out = result.get("tokenAmountOut", {})
fee = result.get("fee", {})
out_human = format_units(out.get("amount", "0"), out.get("decimals", dst_dec))
fee_human = float(format_units(fee.get("amount", "0"), fee.get("decimals", 6)))
fee_usd = fee_human * fee.get("priceUsd", 1)
est_time = result.get("estimatedTime", "?")
print(f"Quote: {amount} -> {out_human}")
print(f"Fee: ~${fee_usd:.4f}")
print(f"Estimated time: {est_time}s")
print(f"Symbiosis router: {tx['to']}")
# --- Step 2: Approve (if needed) ---
if approve_to and src_token.lower() != ZERO_ADDR:
print("\n=== Approving token for Symbiosis ===")
padded = approve_to[2:].lower().zfill(64)
approve_data = f"0x095ea7b3{padded}{MAX_UINT256}"
approve_result = bankr_submit(bankr_key, {
"to": src_token,
"chainId": src_chain,
"value": "0",
"data": approve_data,
}, "Approve token for Symbiosis cross-chain swap")
if not approve_result.get("success"):
print(f"ERROR: Approve failed: {json.dumps(approve_result)}", file=sys.stderr)
sys.exit(1)
print(f"Approve tx: {approve_result['transactionHash']}")
# --- Step 3: Submit swap ---
print("\n=== Submitting Symbiosis swap ===")
swap_result = bankr_submit(bankr_key, {
"to": tx["to"],
"chainId": src_chain,
"value": tx.get("value", "0"),
"data": tx["data"],
}, "Symbiosis cross-chain swap")
if not swap_result.get("success"):
print(f"ERROR: Swap failed: {json.dumps(swap_result)}", file=sys.stderr)
sys.exit(1)
swap_hash = swap_result["transactionHash"]
print(f"Swap tx: {swap_hash}")
print(f"Status: {swap_result.get('status', 'unknown')}")
print(f"\n=== SUCCESS ===")
print(f"Swapped {amount} on chain {src_chain} -> ~{out_human} on chain {dst_chain}")
print(f"Fee: ~${fee_usd:.4f} | Estimated arrival: {est_time}s")
print(f"Track: https://explorer.symbiosis.finance/transactions/{src_chain}/{swap_hash}")
if __name__ == "__main__":
main()
Related skills
FAQ
Which chains does Symbiosis support?
Cross-chain swaps across 54+ blockchains including Base, Ethereum, Polygon, Arbitrum, Optimism, BNB Chain, Avalanche, Solana, Bitcoin, TON and Tron.
Do I need extra wallets or keys?
No. All transactions are submitted through the Bankr Submit API using the user's Bankr wallet.