Smart Account Integration
Integrate the Goliath Bridge from ERC-4337 smart-account wallets (Safe, Coinbase Smart Wallet, Biconomy, Alchemy AA, ZeroDev, thirdweb) — ERC-1271 signatures, bundler tx hashes, and how to avoid the u
The native XCN withdrawal flow accepts EIP-712 intents signed by deployed ERC-1271 smart accounts — not just EOAs. Third-party apps built on Safe, Coinbase Smart Wallet, Biconomy, Alchemy AA, ZeroDev, thirdweb, or any AA stack that implements isValidSignature(bytes32,bytes) can drive the XCN withdraw flow end-to-end without the owner EOA ever touching the intent.
This page is for third-party integrators using smart-account wallets. The Goliath → Ethereum — Native XCN walkthrough still applies — the endpoints, typed-data fields, poll loop, and status lifecycle are unchanged. What's new is how senderAddress is resolved (smart-account contract address, not owner EOA), how the intent signature is verified (ERC-1271 on-chain call, not ECDSA recovery), and what the backend accepts as originTxHash (the final execution tx, not the userOpHash).
If you're using an EOA wallet, skip this page — the standard Native XCN flow is all you need.
Hard Rules
Read all six before wiring code. Missing any one of these stalls the withdrawal.
senderAddress= deployed smart-account contract address on Goliath.Not the owner EOA. Not an ERC-4337 session key. Not a factory address.
The bridge enforces that the observed value transfer originated from this exact address.
The smart account must already be deployed at
senderAddresson Goliath before signing the intent.Counterfactual (predicted-but-not-yet-deployed) accounts are rejected with
503 SIGNATURE_VERIFICATION_UNAVAILABLE.ERC-6492 pre-deploy signatures are not supported. Deploy first, then sign.
The smart account must implement
isValidSignature(bytes32,bytes) returns (bytes4)and return magic0x1626ba7efor a valid signature.Every modern AA stack uses this selector — you should not need to change anything wallet-side.
The legacy
isValidSignature(bytes,bytes)variant with magic0x20c13b0bis not accepted.
originTxHashis the final execution tx hash on Goliath — never theuserOpHash.userOpHashis a 32-byte hex string that's syntactically indistinguishable from a real tx hash, but it's not a transaction, so the bridge can never find it. Your intent will silently stall until it expires.Resolve with
eth_getUserOperationReceipt(userOpHash) → receipt.transactionHashbefore calling/bind-origin.
Direct child call only — the final execution tx must contain a direct internal
CALLfromsenderAddresstorelayerWalletAddresswithvalue = amountAtomic.EntryPoint.handleOps(...)wrapping that direct call is fine — the bridge walks the call tree.Multi-hop (
smartAccount → Router → relayer) is rejected.
Always read
relayerWalletAddressfrom the intent response. It rotates between networks and at operator discretion. Hardcoded relayer addresses silently strand funds after a rotation.
How the Bridge Verifies Smart-Account Withdrawals
Only two steps differ from the EOA path:
Intent signature
ecrecover(digest, signature) == senderAddress
On-chain eth_call to senderAddress.isValidSignature(digest, signature) — must return 0x1626ba7e
Origin-funds proof
Compare tx.from / tx.to / tx.value on the bound tx hash
Walk the call tree (Hedera mirror /api/v1/contracts/results/{txHash}/actions) for a CALL node matching (senderAddress → relayerWalletAddress, value = amountAtomic)
Everything else — typed-data shape, API endpoints, 1-hour security hold, fee schedule, polling, status lifecycle — is identical to the EOA flow.
Typed-Data Shape (unchanged)
Use the same EIP-712 domain, primary type, and field order as the EOA flow:
Signatures from a different domain are rejected with 400 SIGNATURE_DOMAIN_REJECTED.
End-to-End Flow
Steps 2–6 must complete inside the 30-minute intent window. Step 7 can run as long as needed (~1 hour because of the security hold).
Example A — viem + permissionless.js (Safe via bundler)
permissionless.js (Safe via bundler)For AA stacks that submit UserOperations through a bundler, the bundler tx hash returned by eth_getUserOperationReceipt is the execution tx hash.
Example B — ethers v6 + @safe-global/protocol-kit (direct on-chain)
@safe-global/protocol-kit (direct on-chain)For Safe accounts that execute on-chain through executeTransaction (no bundler), the receipt hash from the final executeTransaction is the execution tx hash — no eth_getUserOperationReceipt call is needed.
Failure Modes
400
SIGNATURE_INVALID
ERC-1271 eth_call reverted, or returned no data
Confirm the smart account exposes isValidSignature(bytes32,bytes) and the signature is ABI-encoded as the wallet SDK returned it
400
SIGNATURE_MISMATCH
ERC-1271 returned a non-magic bytes4 (e.g. 0xffffffff)
Re-sign; verify senderAddress equals the smart-account proxy, not the owner EOA
400
SIGNATURE_DOMAIN_REJECTED
Signed against a non-canonical domain
Use chainId: 327 (mainnet) or 8901 (testnet), name: "GoliathBridge", version: "1"
503
SIGNATURE_VERIFICATION_UNAVAILABLE
Transient RPC error or the smart account is not deployed (eth_getCode(senderAddress) == 0x)
Back off 1–5 s, deploy the smart account if it isn't yet, then retry
409
DUPLICATE_ORIGIN_TX
A different intent already bound this tx hash
Create a fresh intent
410
INTENT_EXPIRED
Missed the 30 min window
Start over from step 2
Two extra codes surface only via the operator-driven admin recovery path, listed here for completeness:
409
PROOF_UNAVAILABLE
Trace data not yet indexed — retry after a short backoff
422
PROOF_MISMATCH
Trace shows the wrong sender, recipient, or value — contact support
userOpHash vs. Execution Tx Hash — the #1 Gotcha
userOpHash vs. Execution Tx Hash — the #1 Gotcha/bridge/xcn-withdraw-intent/bind-origin expects a 32-byte hex string in originTxHash, and the bridge asks the Goliath relay and the Hedera mirror to find the matching transaction. A userOpHash is the same shape (0x…, 64 hex chars), but it's not a transaction — it's the hash of a UserOperation struct that the bundler inlined inside its own handleOps(...) call. No indexer will ever return a tx with that hash.
If you bind a userOpHash:
The intent sits in
PENDING_ORIGIN_TXand never progresses.After 30 minutes it flips to
INTENT_EXPIRED.The 5000 XCN you actually sent is now stuck in the relayer wallet — there's no intent to pair it with.
Always resolve to the execution tx hash first:
If you're executing via Safe's on-chain executeTransaction (no bundler), the ethers receipt hash is already the execution tx hash. If you're going through a bundler, you must call eth_getUserOperationReceipt.
Common Pitfalls
Owner-EOA address in the intent body, smart-account signature in
signature. IfsenderAddressis the owner EOA but the signature came from the Safe's ERC-1271 path, you'll get400 SIGNATURE_MISMATCH.senderAddressmust be the smart-account contract address on both the signed intent and the value transfer.Counterfactual Safes. If the Safe has never been used,
eth_getCode(safeAddress)returns0xand the bridge responds503 SIGNATURE_VERIFICATION_UNAVAILABLE. Send a cheap initialization op (or any deploy tx) before binding the intent. ERC-6492 pre-deploy signatures are not supported.Routers and meta-tx forwarders.
smartAccount → Router → relayeris rejected asSENDER_MISMATCH. The relayer transfer must be a direct child call of the smart account. If you need a router for business logic, build the composed call so the smart account still calls the relayer directly as a leaf.Value-unit mismatch.
amountAtomicis the 18-decimal wei string. Smart-account SDKs (especially thirdweb) sometimes assume tinybars on Hedera-family chains — do not apply the 8-decimal scale to XCN. Pass the same integer into the intentamountAtomicand into thevalueof the native transfer. See XCN Decimal Handling for background.Hardcoded relayer address. Every example above reads
relayerWalletAddressfrom the intent response. If you hardcode the relayer, a key rotation silently strands every withdrawal after the rotation until you redeploy.
Next
Goliath → Ethereum — Native XCN — the EOA flow this page extends.
REST API Reference — endpoint schemas for
/xcn-withdraw-intentand/bind-origin.XCN Decimal Handling — why
amountAtomicis always 18-decimal wei, never tinybars.Contracts & Events — Goliath and Ethereum bridge contract addresses.
Last updated