0x68575b07…67c7·#25,913,803·view on Etherscan
k="false" aria-describedby="ens">
<p class="note" id="ens" aria-live="polite"></p>
</div>
<div class="field locked" id="fAmount">
<span class="flabel">Amount <em id="balHint"></em></span>
<div class="amt">
<input type="text" class="input" id="amountInput" inputmode="decimal" placeholder="0" autocomplete="off" aria-label="Amount" aria-describedby="amountNote">
<button class="opt" id="maxBtn">Max</button>
</div>
<div class="row" id="amountRow" role="group" aria-label="Quick amounts">
<button class="opt" data-amount="1">1</button>
<button class="opt" data-amount="10">10</button>
<button class="opt" data-amount="100">100</button>
</div>
<p class="note" id="amountNote" aria-live="polite"></p>
</div>
<div class="field" id="fReview" hidden>
<span class="flabel">What happens</span>
<p class="summary" id="summary"></p>
<p class="recipFull" id="recipFull"></p>
<ol class="tl" id="timeline"></ol>
<label class="check" for="autoClaimChk"><input type="checkbox" id="autoClaimChk"> Pay a keeper to auto-claim it</label>
<p class="note" id="tipPre"></p>
<p class="note" id="planNote" aria-live="polite"></p>
<div class="alts">
<button class="btn alt" id="shareBtn">Copy request link</button>
<button class="btn alt" id="recipeBtn">Copy the call</button>
</div>
</div>
</div>
<div class="col" id="colB">
<div class="field">
<span class="flabel">Asset <em id="assetHint"></em></span>
<div class="grid" id="cryptoGrid" role="group" aria-label="Asset"></div>
<button class="link" id="customTokenOpt">+ Custom token</button>
</div>
<div class="field" id="fDest" hidden>
<span class="flabel">Deliver on <em id="destHint"></em></span>
<div class="row" id="destRow" role="group" aria-label="Destination chain"></div>
</div>
<div class="field locked" id="fTime">
<span class="flabel">Unlocks after <em id="timeHint"></em></span>
<div class="row" id="timeRow" role="group" aria-label="Timelock">
<button class="opt" data-time="600">10 MIN</button>
<button class="opt" data-time="3600">1 HR</button>
<button class="opt" data-time="86400">1 DAY</button>
<button class="opt" id="customTimeOpt">Custom</button>
</div>
</div>
<div class="field" id="fPreview" hidden>
<span class="flabel">The position <em id="previewHint">updates as you choose</em></span>
<div class="nftbox" id="nftBox"></div>
</div>
</div>
</div>
<div class="sendFoot">
<p class="foothint" id="footHint" aria-live="polite"></p>
<button class="btn" id="confirmBtn">Send</button>
</div>
<div class="guardPane">
<p class="warn" id="gNotDeployed" hidden></p>
<div class="field">
<span class="flabel">Your guardian <em id="gHint"></em></span>
<div class="gcard" id="gCurrent">—</div>
<div class="row2">
<button class="opt" id="gSet">Set</button>
<button class="opt" id="gRemove">Remove</button>
</div>
</div>
<div class="field" id="gPendingField" hidden>
<span class="flabel">Pending change</span>
<div class="gcard" id="gPending">—</div>
<div class="row2">
<button class="opt" id="gCommit">Commit</button>
<button class="opt" id="gCancel">Cancel</button>
</div>
</div>
<div class="field">
<span class="flabel">Accounts you guard <em id="gWardHint"></em></span>
<div class="list" id="gWards"></div>
<div class="row2">
<button class="link" id="gAddWard">+ Add an account</button>
<button class="link" id="gScan">Scan for mine</button>
</div>
</div>
</div>
<div class="takePane">
<div class="tabs" role="tablist" aria-label="Transfers">
<button class="tab" id="tabOut" role="tab" aria-selected="true" data-tab="outbound">Outbound</button>
<button class="tab" id="tabIn" role="tab" aria-selected="false" data-tab="inbound">Inbound</button>
<button class="tab" id="tabUnlocked" role="tab" aria-selected="false" data-tab="unlocked" hidden>Unlocked</button>
</div>
<div class="list" id="list" role="tabpanel" tabindex="0"></div>
</div>
</div>
</main>
<div id="tipLayer"></div>
<div class="modal" id="themeModal" role="dialog" aria-modal="true" aria-labelledby="themeTitle"><div class="card">
<h3 id="themeTitle">Appearance</h3>
<div class="picks" id="themeList"></div>
<button class="btn alt" id="themeCancel">Cancel</button>
</div></div>
<div class="modal" id="chainModal" role="dialog" aria-modal="true" aria-labelledby="chainTitle"><div class="card">
<h3 id="chainTitle">Network</h3>
<div class="picks" id="chainList"></div>
<p class="note">SLOW is at the same address on each. Names always resolve on Ethereum.</p>
<button class="btn alt" id="chainCancel">Cancel</button>
</div></div>
<div class="modal" id="walletModal" role="dialog" aria-modal="true" aria-labelledby="walletTitle"><div class="card">
<h3 id="walletTitle">Wallet</h3>
<div class="picks" id="walletList"></div>
<button class="btn alt" id="walletCancel">Cancel</button>
</div></div>
<div class="modal" id="timeModal" role="dialog" aria-modal="true" aria-labelledby="timeTitle"><div class="card">
<h3 id="timeTitle">Timelock</h3>
<div class="tgrid">
<div><input type="number" id="dInput" min="0" placeholder="0" inputmode="numeric"><label for="dInput">Days</label></div>
<div><input type="number" id="hInput" min="0" placeholder="0" inputmode="numeric"><label for="hInput">Hrs</label></div>
<div><input type="number" id="mInput" min="0" placeholder="0" inputmode="numeric"><label for="mInput">Min</label></div>
<div><input type="number" id="sInput" min="0" placeholder="0" inputmode="numeric"><label for="sInput">Sec</label></div>
</div>
<button class="btn" id="timeApply">Apply</button>
</div></div>
<div class="modal" id="tokenModal" role="dialog" aria-modal="true" aria-labelledby="tokenTitle"><div class="card">
<h3 id="tokenTitle">Custom token</h3>
<input type="text" class="input" id="tokenInput" placeholder="0x\u2026 contract address" autocomplete="off" spellcheck="false">
<p class="note" id="tokenStatus"></p>
<p class="note">Fee-on-transfer or rebasing tokens may strand funds.</p>
<button class="btn" id="tokenApply">Apply</button>
</div></div>
<div class="modal" id="guardModal" role="dialog" aria-modal="true" aria-labelledby="guardTitle"><div class="card">
<h3 id="guardTitle">Guardian</h3>
<input type="text" class="input" id="guardInput" placeholder="Address, .eth, .wei, or .gwei" autocomplete="off" spellcheck="false">
<p class="note" id="guardNote" aria-live="polite"></p>
<p class="note" id="guardWarn"></p>
<button class="btn" id="guardApply">Apply</button>
<button class="btn alt" id="guardCancel">Cancel</button>
</div></div>
<div class="modal" id="gaModal" role="dialog" aria-modal="true" aria-labelledby="gaTitle"><div class="card">
<h3 id="gaTitle">Approve one outflow</h3>
<p class="note">Pre-authorises a single operation for <b id="gaWard"></b> — <span id="gaNonce"></span>. It is consumed when they run it, and voided if their guardian changes.</p>
<select class="input" id="gaKind" aria-label="Operation">
<option value="withdraw">Withdraw the underlying</option>
<option value="transfer">Transfer the position</option>
</select>
<input type="text" class="input" id="gaTo" placeholder="Recipient address" autocomplete="off" spellcheck="false" aria-label="Recipient">
<input type="text" class="input" id="gaId" placeholder="Position id" inputmode="numeric" autocomplete="off" aria-label="Position id">
<input type="text" class="input" id="gaAmt" placeholder="Amount, in base units" inputmode="numeric" autocomplete="off" aria-label="Amount">
<p class="note" id="gaNote" aria-live="polite"></p>
<button class="btn" id="gaApply">Approve</button>
<button class="btn alt" id="gaCancel">Cancel</button>
</div></div>
<div class="modal" id="detailModal" role="dialog" aria-modal="true" aria-labelledby="detailTitle"><div class="card" tabindex="-1">
<h3 id="detailTitle">Transfer</h3>
<dl class="rows" id="detailRows"></dl>
<button class="btn" id="detailAction"></button>
<button class="btn alt" id="detailShare">Copy link to this transfer</button>
<button class="btn alt" id="detailForget" hidden>Dismiss from my list</button>
<button class="btn alt" id="detailClose">Close</button>
</div></div>
<div class="modal" id="exitModal" role="dialog" aria-modal="true" aria-labelledby="exitTitle"><div class="card">
<h3 id="exitTitle">Withdraw</h3>
<p class="note" id="exitAmt"></p>
<input type="text" class="input" id="exitTo" placeholder="Destination \u2014 blank means yourself" autocomplete="off" spellcheck="false" aria-label="Destination">
<input type="text" class="input" id="exitData" placeholder="Then call it with this data (optional, 0x\u2026)" autocomplete="off" spellcheck="false" aria-label="Call data">
<p class="note" id="exitNote" aria-live="polite"></p>
<button class="btn" id="exitSend">Withdraw</button>
<button class="btn alt" id="exitCopy">Copy the calls</button>
<button class="btn alt" id="exitClose">Close</button>
</div></div>
<div class="modal" id="helpModal" role="dialog" aria-modal="true" aria-labelledby="helpTitle"><div class="card">
<h3 id="helpTitle">How SLOW works</h3>
<dl class="rows">
<div class="kv"><dt>Wrap</dt><dd>Your token becomes a SLOW position with a timelock you pick.</dd></div>
<div class="kv"><dt>Reverse</dt><dd>Until the lock expires, you can pull it back. Wrong address, changed mind, stolen key.</dd></div>
<div class="kv"><dt>Claim</dt><dd>After it expires, the recipient takes the underlying. A keeper can do it for them if you tip.</dd></div>
<div class="kv"><dt>Recover</dt><dd>If nobody ever claims, you can take it back 30 days after expiry.</dd></div>
<div class="kv"><dt>Guardian</dt><dd>Optional cosigner who must approve every outflow from your account.</dd></div>
</dl>
<p class="note">Every transfer is an ERC-1155 position that draws its own picture on chain.</p>
<button class="btn alt" id="helpClose">Close</button>
</div></div>
<div class="txbar" id="txbar" role="status" aria-live="polite" hidden>
<span class="spinner sm" id="txSpin"></span>
<span class="txmsg"><b id="txMsg"></b><em id="txStep"></em></span>
<a id="txLink" target="_blank" rel="noopener" hidden>View</a>
<button id="txDismiss" aria-label="Dismiss" hidden>×</button>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script>
(()=>{
'use strict';
const SLOW = '0x000000006513B7821171C8447ec7ECdfa3b956Fd';
const ZERO = '0x0000000000000000000000000000000000000000';
const ENS_REG = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
const WNS = '0x0000000000696760E15f265e828DB644A0c242EB';
const GNS = '0x9D51D507BC7264d4fE8Ad1cf7Fe191933A0a81d6';
const MC3 = '0xcA11bde05977b3631167028862bE2a173976CA11';
const MAINNET = 1;
const GRACE = 2592000;
const GUARD_DELAY = 86400;
const TOPIC_GUARDIAN_SET = '0xc3ce29e3ab42e524b6f6f1b4d3674898d503ee3577a64ac87b555904ebc14138';
const MAX_DELAY = 3155760000;
const CHAINS = {
1: {
id:1, hex:'0x1', name:'Ethereum', short:'Mainnet',
explorer:'https://etherscan.io',
deployBlock:24986598,
minGasPrice:50_000_000n, fallbackGasPrice:2_000_000_000n, minTip:20_000_000_000_000n,
rpcs:[
'https://ethereum-rpc.publicnode.com',
'https://eth.llamarpc.com',
'https://1rpc.io/eth',
'https://eth-pokt.nodies.app',
'https://gateway.tenderly.co/public/mainnet',
],
tokens:[
{symbol:'ETH', address:'0x0000000000000000000000000000000000000000', decimals:18},
{symbol:'USDC', address:'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', decimals:6},
{symbol:'USDe', address:'0x4c9edd5852cd905f086c759e8383e09bff1e68b3', decimals:18},
{symbol:'cbBTC', address:'0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf', decimals:8},
{symbol:'wstETH',address:'0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', decimals:18},
{symbol:'WBTC', address:'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', decimals:8},
{symbol:'USDT', address:'0xdac17f958d2ee523a2206206994597c13d831ec7', decimals:6},
{symbol:'BOLD', address:'0x6440f144b7e50d6a8439336510312d2f54beb01d', decimals:18},
],
},
8453: {
id:8453, hex:'0x2105', name:'Base', short:'Base',
explorer:'https://basescan.org',
deployBlock:0,
minGasPrice:1_000_000n, fallbackGasPrice:50_000_000n, minTip:2_000_000_000_000n,
rpcs:[
'https://base-rpc.publicnode.com',
'https://mainnet.base.org',
'https://base.drpc.org',
'https://1rpc.io/base',
],
tokens:[
{symbol:'ETH', address:'0x0000000000000000000000000000000000000000', decimals:18},
{symbol:'USDC', address:'0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', decimals:6},
{symbol:'USDe', address:'0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34', decimals:18},
{symbol:'cbBTC', address:'0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf', decimals:8},
{symbol:'wstETH',address:'0xc1cba3fcea344f92d9239c08c0568f6f2f0ee452', decimals:18},
{symbol:'cbETH', address:'0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', decimals:18},
{symbol:'USDT', address:'0xfde4c96c8593536e31f229ea8f37b2ada2699bb2', decimals:6},
{symbol:'AERO', address:'0x940181a94a35a4569e4529a3cdfb74e38fd98631', decimals:18},
],
addChain:{
chainId:'0x2105', chainName:'Base',
nativeCurrency:{name:'Ether', symbol:'ETH', decimals:18},
rpcUrls:['https://mainnet.base.org'],
blockExplorerUrls:['https://basescan.org'],
},
},
4663: {
id:4663, hex:'0x1237', name:'Robinhood Chain', short:'Robinhood',
explorer:'https://robinscan.io',
deployBlock:0,
minGasPrice:10_000_000n, fallbackGasPrice:500_000_000n, minTip:5_000_000_000_000n,
rpcs:['https://rpc.mainnet.chain.robinhood.com'],
tokens:[
{symbol:'ETH', address:'0x0000000000000000000000000000000000000000', decimals:18},
{symbol:'USDG', address:'0x5fc5360d0400a0fd4f2af552add042d716f1d168', decimals:6},
{symbol:'USDe', address:'0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34', decimals:18},
{symbol:'cbBTC',address:'0xcec185eb182c47d1ba1efc84e6959e18cd620be4', decimals:8},
{symbol:'NVDA', address:'0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec', decimals:18},
{symbol:'SPY', address:'0x117cc2133c37b721f49de2a7a74833232b3b4c0c', decimals:18},
{symbol:'SPCX', address:'0x4a0e65a3eccec6dbe60ae065f2e7bb85fae35eea', decimals:18},
{symbol:'GME', address:'0x1b0e319c6a659f002271b69db8a7df2f911c153e', decimals:18},
],
addChain:{
chainId:'0x1237', chainName:'Robinhood Chain',
nativeCurrency:{name:'Ether', symbol:'ETH', decimals:18},
rpcUrls:['https://rpc.mainnet.chain.robinhood.com'],
blockExplorerUrls:['https://robinscan.io'],
},
},
};
const CHAIN_IDS = [1, 8453, 4663];
const L1_ALIAS = 0x1111000000000000000000000000000000001111n;
const ADDR_MASK = (1n<<160n)-1n;
const aliasOf = a => '0x'+(((BigInt(a)+L1_ALIAS)&ADDR_MASK).toString(16).padStart(40,'0'));
const unaliasOf = a => '0x'+(((BigInt(a)-L1_ALIAS)&ADDR_MASK).toString(16).padStart(40,'0'));
const BRIDGES = {
8453: {
kind:'op', from:1,
entry:'0x49048044D57e1C92A77f79988d21Fa8fAF74E97e',
l2GasLimit:600_000n,
l2GasLimitContract:2_500_000n,
},
4663: {
kind:'arb', from:1,
entry:'0x1A07cc4BD17E0118BdB54D70990D2158AbAD7a2D',
l2GasLimit:800_000n,
l2GasLimitContract:2_500_000n,
nodeInterface:'0x00000000000000000000000000000000000000C8',
},
};
const bridgeTo = id => BRIDGES[id];
const BRIDGE_REGISTRY = null;
const SLOW_ARRIVAL = '0x9F8D89D298caBDC0D64cbA3888D0DA85Dc95097f';
const KIND_BY_ID = {1:'op', 2:'arb'};
async function loadBridgeRoutes(){
if(!BRIDGE_REGISTRY || S.routesLoaded) return;
S.routesLoaded = true;
try {
const [r] = await mc([{to:BRIDGE_REGISTRY, data:SEL.allRoutes}], 0, MAINNET);
if(!r) return;
const d=strip(r);
const idsOff=parseInt(d.slice(0,64),16)*2, n=parseInt(d.slice(idsOff,idsOff+64),16);
const rtOff=parseInt(d.slice(64,128),16)*2;
for(let i=0;i<n;i++){
const id=Number(BigInt('0x'+d.slice(idsOff+64+i*64, idsOff+128+i*64)));
const base=rtOff+64+i*4*64;
const entry='0x'+d.slice(base+24, base+64);
const kind=KIND_BY_ID[parseInt(d.slice(base+64, base+128),16)];
const gas=BigInt('0x'+d.slice(base+128, base+192));
if(!kind || BRIDGES[id] || !CHAINS[id]) continue;
BRIDGES[id]={kind, from:MAINNET, entry, l2GasLimit:gas, registry:true};
}
} catch(e){ }
}
function depositRecipe(){
if(!ready()) return null;
const isETH = S.token===ZERO;
let wei;
try { wei = parseUnits(S.amount, S.decimals); } catch(e){ return null; }
const chain = S.dest || S.chain;
const via = S.dest ? bridgeVia(S.dest) : null;
return {
chainId: chain,
chainName: cfg(chain).name,
to: isETH && via ? via : SLOW,
data: isETH
? innerDepositCalldata(S.resolved, S.delay, S.dest || undefined)
: cd(SEL.depositTo, ['address','address','uint256','uint96','bytes'],
[S.token, S.resolved, wei, BigInt(S.delay), '0x']),
value: isETH ? wei : 0n,
note: isETH ? null : `Requires an allowance of ${S.amount} ${S.symbol} to ${SLOW} first.`,
via: isETH ? via : null,
origin: isETH && via ? (S.account || ZERO) : null,
};
}
function recipeText(r){
return [
`# SLOW deposit — ${r.chainName} (chain ${r.chainId})`,
`to: ${r.to}`,
`value: ${r.value} wei`,
`data: ${r.data}`,
r.note ? `note: ${r.note}` : null,
r.via ? `note: Through SlowArrival ${r.via}, so the reverse survives the crossing.`
: null,
r.via ? ` Held for ${r.origin} — the originHint in the calldata, and the only`
: null,
r.via ? ` address SlowArrival.reverse/.clawback answer to. Send via a bridge.`
: null,
].filter(Boolean).join('\n');
}
function innerDepositCalldata(recipient, delay, destChain){
if(bridgeVia(destChain)){
return cd(SEL.arrive, ['address','uint96','address','uint256'],
[recipient, BigInt(delay), S.account || ZERO, 0n]);
}
return cd(SEL.depositTo, ['address','address','uint256','uint96','bytes'],
[ZERO, recipient, 0n, BigInt(delay), '0x']);
}
const bookArrival = destChain =>
(BRIDGES[destChain] && BRIDGES[destChain].registry && S.book[destChain])
? S.book[destChain] : SLOW_ARRIVAL;
const bridgeVia = destChain =>
(SLOW_ARRIVAL && S.arrivalDeployed[destChain] === true) ? bookArrival(destChain) : null;
const bridgeTarget = destChain => bridgeVia(destChain) || SLOW;
const ARRIVAL_NAME = '0x536c6f774172726976616c000000000000000000000000000000000000000000';
async function loadArrivalAddress(id){
if(!BRIDGE_REGISTRY || !BRIDGES[id] || !BRIDGES[id].registry) return;
if(S.book[id] !== undefined) return;
S.book[id] = null;
try {
const [r] = await mc([{to:BRIDGE_REGISTRY,
data: cd(SEL.deployments, ['bytes32','uint256'], [ARRIVAL_NAME, BigInt(id)])}], 0, MAINNET);
if(!r) return;
const at = '0x' + strip(r).slice(24, 64);
if(at !== ZERO) S.book[id] = at;
} catch(e){ }
}
async function destGasLimit(destChain, recipient){
const b = BRIDGES[destChain];
const big = b.l2GasLimitContract || b.l2GasLimit;
try {
const code = await rpc('eth_getCode', [recipient, 'latest'], destChain);
if(typeof code !== 'string') return big;
return code.length > 4 ? big : b.l2GasLimit;
} catch(e){
return big;
}
}
async function bridgeCosts(destChain, recipient, delay){
const b = BRIDGES[destChain];
const inner = innerDepositCalldata(recipient, delay, destChain);
const l2Gas = await destGasLimit(destChain, recipient);
if(b.kind!=='arb') return {inner, l2Gas, submission:0n, maxFee:0n, prepaid:0n, extra:0n};
const l1Base = await l1BaseFee();
const bytesLen = BigInt(strip(inner).length/2);
let submission;
try {
const [f] = await mc([{to:b.entry,
data: cd(SEL.calcSubmissionFee, ['uint256','uint256'], [bytesLen, l1Base])}], 0, MAINNET);
submission = f ? decode(['uint256'], f)[0] : 0n;
} catch(e){ submission = 0n; }
if(!submission) submission = 100_000_000_000_000n;
submission = submission * 3n / 2n;
let maxFee;
try { maxFee = BigInt(await rpc('eth_gasPrice', [], destChain)) * 2n; }
catch(e){ maxFee = cfg(destChain).fallbackGasPrice * 2n; }
if(maxFee < cfg(destChain).minGasPrice) maxFee = cfg(destChain).minGasPrice;
const prepaid = l2Gas * maxFee;
return {inner, l2Gas, submission, maxFee, prepaid, extra: submission + prepaid};
}
async function bridgePlan(destChain, recipient, delay, weiAmount){
const b = BRIDGES[destChain];
if(!b) throw new Error(`No bridge route to ${cfg(destChain).name}`);
const target = bridgeTarget(destChain);
const {inner, l2Gas, submission, maxFee, prepaid} = await bridgeCosts(destChain, recipient, delay);
if(b.kind==='op'){
return {
to:b.entry,
data: cd(SEL.depositTransaction, ['address','uint256','uint256','bool','bytes'],
[target, weiAmount, l2Gas, false, inner]),
value: weiAmount,
parts: [['Bridged', weiAmount]],
};
}
return {
to:b.entry,
data: cd(SEL.createRetryableTicket,
['address','uint256','uint256','address','address','uint256','uint256','bytes'],
[target, weiAmount, submission, S.account, S.account, l2Gas, maxFee, inner]),
value: weiAmount + submission + prepaid,
parts: [['Bridged', weiAmount], ['Ticket', submission], ['Destination gas', prepaid]],
};
}
async function l1BaseFee(){
try {
const b = await rpc('eth_getBlockByNumber', ['latest', false], MAINNET);
return BigInt(b.baseFeePerGas || '0x0');
} catch(e){ return 2_000_000_000n; }
}
const canBridge = (fromChain, toChain) => {
const b = BRIDGES[toChain];
if(!b || b.from !== fromChain || S.slowDeployed[toChain] !== true) return false;
const notProvenEOA = !!S.account && S.accountIsContract !== false;
if(S.arrivalDeployed[toChain] !== true
&& (b.kind === 'arb' || notProvenEOA)) return false;
if(b.kind === 'arb' && notProvenEOA) return false;
return true;
};
const cfg = id => CHAINS[id ?? S.chain] || CHAINS[MAINNET];
const SEL = {
depositTo:'0x94eeaec9', depositToWithTip:'0x75f92e42',
depositToWithPermit:'0x2f19167b', depositToWithTipAndPermit:'0x9cdec3f5',
reverse:'0x97d15425', claim:'0x379607f5', clawback:'0xfcc36bc9', unlock:'0x6198e339',
withdrawFrom:'0xd4fdc309', multicall:'0xac9650d8', pendingTransfers:'0x6577b86a',
getOut:'0xd40d4bc6', getIn:'0xe3993ee7',
outCount:'0x73bfdce5', inCount:'0xea712c4f', forgetInbound:'0x03ca0e44',
outAt:'0xb5f8348b', inAt:'0x8b40f4c5',
guardians:'0x0633b14a', isWithdrawalApprovalNeeded:'0xabe616b8',
setGuardian:'0x8a0dac4a', commitGuardian:'0xa952a15f', cancelGuardianChange:'0xdb6c927d',
pendingGuardian:'0x3b0a6875', approveTransfer:'0xfa02c4b7', revokeApproval:'0x47d07c4c',
guardianApproved:'0x8d4a1b58', isGuardianApprovalNeeded:'0xaade934f',
predictWithdrawalId:'0x2d0eae84', predictTransferId:'0xd8a29acf',
wardsOf:'0xb266b777',
arrive:'0x24eb6264',
depositTransaction:'0xe9e05c42',
createRetryableTicket:'0x679b6ded',
calcSubmissionFee:'0xa66b327d',
allRoutes:'0x71da4170',
deployments:'0x24495881',
unlockedBalances:'0x5b96484e', guardianNonces:'0xeac43b4a',
gateAddr:'0x7a0ebc88', tips:'0xa5c68c59', refundTip:'0xd27e1e72',
approve:'0x095ea7b3', allowance:'0xdd62ed3e', decimals:'0x313ce567',
symbol:'0x95d89b41', name:'0x06fdde03', balanceOf:'0x70a08231',
permit:'0xd505accf', nonces:'0x7ecebe00',
domainSeparator:'0x3644e515', permitTypehash:'0x30adf81f',
resolver:'0x0178b8bf', addr:'0x3b3b57de', ensName:'0x691f3431', wnsReverse:'0x9af8b7aa',
aggregate3:'0x82ad56cb',
};
const TYPEHASH_2612 = '6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9';
const TOKEN_COLORS = {
ETH:'#ff69b4', WETH:'#ff69b4', USDC:'#2775ca', USDT:'#26a17b', BOLD:'#c026d3',
USDe:'#6d28d9', USDG:'#ccff00', NVDA:'#4d7c0f',
wstETH:'#38bdf8', WBTC:'#a0522d', cbETH:'#71f26d', AERO:'#5d7222',
cbBTC:'#f7931a', SPY:'#0f766e', SPCX:'#b9bec7', GME:'#dc2626',
};
const PRESETS = {
ETH:['0.01','0.1','1'], WETH:['0.01','0.1','1'],
cbBTC:['0.001','0.01','0.1'], WBTC:['0.001','0.01','0.1'],
wstETH:['0.01','0.1','1'], cbETH:['0.01','0.1','1'],
AERO:['1','10','100'],
NVDA:['0.1','1','10'], SPY:['0.1','1','10'], SPCX:['0.1','1','10'], GME:['0.1','1','10'],
default:['10','100','1000'],
};
const M64 = (1n<<64n)-1n;
const RC = [1n,32898n,9223372036854808714n,9223372039002292224n,32907n,2147483649n,9223372039002292353n,9223372036854808585n,138n,136n,2147516425n,2147483658n,2147516555n,9223372036854775947n,9223372036854808713n,9223372036854808579n,9223372036854808578n,9223372036854775936n,32778n,9223372039002259466n,9223372039002292353n,92233