@0x/0x-parser
Version:
🧾 Designed for 0x integrators: This library parses 0x transactions on EVM blockchains into a format that is both user-friendly and easy to understand.
2 lines (1 loc) • 8.3 kB
JavaScript
import{formatUnits as se,formatEther as _e,multicall3Abi as ve,decodeFunctionData as I}from"viem";import{bsc as R,base as x,mode as N,blast as D,linea as k,scroll as O,mantle as M,plasma as K,mainnet as U,polygon as F,arbitrum as B,unichain as P,optimism as H,avalanche as W,berachain as Y,worldchain as V,monad as G,abstract as X}from"viem/chains";var j=[{"type":"receive","stateMutability":"payable"},{"type":"function","name":"multicall","inputs":[{"name":"calls","type":"tuple[]","internalType":"struct IMultiCall.Call[]","components":[{"name":"target","type":"address","internalType":"address"},{"name":"revertPolicy","type":"uint8","internalType":"enum IMultiCall.RevertPolicy"},{"name":"value","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"contextdepth","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple[]","internalType":"struct IMultiCall.Result[]","components":[{"name":"success","type":"bool","internalType":"bool"},{"name":"data","type":"bytes","internalType":"bytes"}]}],"stateMutability":"payable"}];var _=[{inputs:[{components:[{internalType:"address",name:"recipient",type:"address"},{internalType:"contract IERC20",name:"buyToken",type:"address"},{internalType:"uint256",name:"minAmountOut",type:"uint256"}],internalType:"struct SettlerBase.AllowedSlippage",name:"slippage",type:"tuple"},{internalType:"bytes[]",name:"actions",type:"bytes[]"},{internalType:"bytes32",name:"",type:"bytes32"},{internalType:"address",name:"msgSender",type:"address"},{internalType:"bytes",name:"sig",type:"bytes"}],name:"executeMetaTxn",outputs:[{internalType:"bool",name:"",type:"bool"}],stateMutability:"nonpayable",type:"function"}];var q={EXECUTE_META_TXN:"0xfd3ad6d4"};var z=[R,x,N,D,k,O,M,U,F,B,P,H,W,Y,V,G,X];var T={[R.id]:R.nativeCurrency.symbol,[x.id]:x.nativeCurrency.symbol,[N.id]:N.nativeCurrency.symbol,[D.id]:D.nativeCurrency.symbol,[k.id]:k.nativeCurrency.symbol,[O.id]:O.nativeCurrency.symbol,[M.id]:M.nativeCurrency.symbol,[G.id]:G.nativeCurrency.symbol,[K.id]:K.nativeCurrency.symbol,[U.id]:U.nativeCurrency.symbol,[F.id]:F.nativeCurrency.symbol,[P.id]:P.nativeCurrency.symbol,[H.id]:H.nativeCurrency.symbol,[B.id]:B.nativeCurrency.symbol,[W.id]:W.nativeCurrency.symbol,[Y.id]:Y.nativeCurrency.symbol,[V.id]:V.nativeCurrency.symbol,[X.id]:X.nativeCurrency.symbol};var C=`0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`;var J=`0x00000000000000cf9e3c5a26621af382fa17f24f`;var Q=`0xcA11bde05977b3631167028862bE2a173976CA11`;var Z=`0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789`;import{fromHex as oe,erc20Abi as ee,getAddress as $,formatUnits as ie,formatEther as le}from"viem";import{bsc as de,base as ce,mode as me,blast as ue,linea as pe,scroll as ye,mantle as be,plasma as fe,mainnet as Te,polygon as Ce,arbitrum as Ae,optimism as Ee,unichain as Le,avalanche as he,berachain as ge,worldchain as Ie,monad as we,abstract as Se}from"viem/chains";function ne(i){const c=[de.id,ce.id,me.id,we.id,ue.id,pe.id,ye.id,be.id,fe.id,Ce.id,Te.id,Ae.id,Ee.id,Le.id,he.id,ge.id,Ie.id,Se.id];return c.includes(i)}function g(i,c){const{recipient:b,direction:r="to"}=c;let A=0n;const a=b.toLowerCase();function s(e){if(!e.value)return;const o=r==="from"?e.from:e.to;if(o.toLowerCase()===a){A+=oe(e.value,"bigint")}}function f(e){for(const o of e){s(o);if(o.calls&&o.calls.length>0){f(o.calls)}}}f(i.calls);return le(A)}async function ae({publicClient:i,transactionReceipt:c}){const b={Transfer:`0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`};const r=c.logs.filter(e=>e.topics[0]===b.Transfer).map(e=>({...e,address:$(e.address)}));const A=[...r.map(e=>({abi:ee,address:e.address,functionName:"symbol"})),...r.map(e=>({abi:ee,address:e.address,functionName:"decimals"}))];const a=await i.multicall({contracts:A});const s=Math.floor(a.length/2);const f=r.map((e,o)=>{const l=a[o].result;const E=a[s+o].result;if(l==null||E==null||typeof E!=="number"){return null}const w=e.data==="0x"?"0":ie(BigInt(e.data),E);const v=e.data==="0x"?0n:BigInt(e.data);const{address:d,topics:S}=e;const{1:L,2:m}=S;const t=$(te(L));const n=$(te(m));return{to:n,from:t,symbol:l,amount:w,amountRaw:v,address:d,decimals:E}}).filter(e=>e!=null&&e.amount!=="0");return f}function te(i){return`0x${i.slice(-40)}`}function re({logs:i,trace:c,chainId:b,smartContractWallet:r}){const A=i.reduce((o,l)=>{if(l.to===r)return{...o,output:l};if(l.from===r)return{...o,input:l};return o},{});let{input:a,output:s}=A;const f=g(c,{recipient:r});const e=g(c,{recipient:r,direction:"from"});if(!s&&f!=="0"){if(a){return{tokenIn:{address:a.address,amount:a.amount,symbol:a.symbol},tokenOut:{address:C,amount:f,symbol:T[b]}}}else{return null}}if(!a&&e!=="0"){const o=b===56?"WBNB":b===137?"WPOL":"WETH";const l=i.find(E=>E.symbol===o);if(l&&s){return{tokenIn:{address:C,amount:l.amount,symbol:T[b]},tokenOut:{address:s.address,amount:s.amount,symbol:s.symbol}}}else{return null}}if(a&&s){return{tokenIn:{address:a.address,amount:a.amount,symbol:a.symbol},tokenOut:{address:s.address,amount:s.amount,symbol:s.symbol}}}return null}async function Pe({publicClient:i,transactionHash:c,smartContractWallet:b}){const r=i.chain.id;if(!ne(r)){throw new Error(`chainId ${r} is unsupported\u2026`)}const A=i.extend(t=>({async traceCall(n){return t.request({method:"debug_traceTransaction",params:[n.hash,{tracer:"callTracer"}]})}}));const[a,s,f]=await Promise.all([A.traceCall({hash:c}),i.getTransaction({hash:c}),i.getTransactionReceipt({hash:c})]);const{from:e,value:o,to:l}=s;const E=l===Z.toLowerCase();const w=g(a,{recipient:e});if(f.status==="reverted"){const t=z.find(u=>u.id===r);const n=`Unable to parse. Transaction ${c} on ${t?.name} has reverted.`;console.warn(n);return null}const v=o>0n;const d=await ae({publicClient:i,transactionReceipt:f});if(E){if(!b){throw new Error("This is an ERC-4337 transaction. You must provide a smart contract wallet address to 0x-parser.")}return re({logs:d,trace:a,chainId:r,smartContractWallet:b})}const S=d.filter(t=>t.from.toLowerCase()===e.toLowerCase());let L=S.length?S.reduce((t,n)=>({...t,amount:se(t.amountRaw+n.amountRaw,n.decimals),amountRaw:t.amountRaw+n.amountRaw})):d[0];let m=w==="0"?d.find(t=>{return t.to.toLowerCase()===e.toLowerCase()}):{symbol:T[r],amount:w,address:C};if(l?.toLowerCase()===J.toLowerCase()){const{args:t}=I({abi:j,data:s.input});if(t&&Array.isArray(t)&&t[0]&&Array.isArray(t[0])){const{args:n}=I({abi:_,data:t[0][1]?.data});const u=n[0].recipient.toLowerCase();const p=n[3];const y=g(a,{recipient:u});if(y==="0"){[m]=d.filter(h=>h.to.toLowerCase()===p.toLowerCase())}else{m={symbol:T[r],amount:y,address:C}}}}if(l?.toLowerCase()===Q.toLowerCase()){const{args:t}=I({abi:ve,data:s.input});if(t[0]){const{args:n}=I({abi:_,data:t[0][1]?.callData});const u=n[0].recipient.toLowerCase();const p=n[3];const y=g(a,{recipient:u});if(y==="0"){[m]=d.filter(h=>h.to.toLowerCase()===p.toLowerCase())}else{m={symbol:T[r],amount:y,address:C}}}}if(s.input.startsWith(q.EXECUTE_META_TXN)){const{args:t}=I({abi:_,data:s.input});const{3:n}=t;const u=d.filter(y=>y.from===n);const p=g(a,{recipient:n});if(u.length){L=u[0]}if(p==="0"){m=d[d.length-1];const y=d.filter(h=>h.to.toLowerCase()===n.toLowerCase());if(y.length===1){m={symbol:y[0].symbol,amount:y[0].amount,address:y[0].address}}else{console.error("File a bug report here, including the expected results (URL to a block explorer) and the unexpected results: https://github.com/0xProject/0x-parser/issues/new/choose.")}L=d.filter(h=>h.from.toLowerCase()===n.toLowerCase())[0]}else{m={symbol:T[r],amount:p,address:C}}}if(v){const t=_e(o);const n=d.filter(u=>u.to.toLowerCase()===e).reduce((u,p)=>({symbol:p.symbol,amount:se(u.amountRaw+p.amountRaw,p.decimals),amountRaw:u.amountRaw+p.amountRaw,address:p.address}),{symbol:"",amount:"",amountRaw:0n,address:""});return{tokenIn:{symbol:T[r],address:C,amount:t},tokenOut:{symbol:n.symbol,amount:n.amount,address:n.address}}}if(!m){console.error("File a bug report here, including the expected results (URL to a block explorer) and the unexpected results: https://github.com/0xProject/0x-parser/issues/new/choose.");return null}return{tokenIn:{symbol:L.symbol,amount:L.amount,address:L.address},tokenOut:{symbol:m.symbol,amount:m.amount,address:m.address}}}export{Pe as parseSwap};