@latticexyz/common 2.0.0-next.10 → 2.0.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/chains.js CHANGED
@@ -1,2 +1,2 @@
1
- var t={name:"Lattice Testnet",id:4242,network:"lattice-testnet",nativeCurrency:{decimals:18,name:"Ether",symbol:"ETH"},rpcUrls:{default:{http:["https://follower.testnet-chain.linfra.xyz"],webSocket:["wss://follower.testnet-chain.linfra.xyz"]},public:{http:["https://follower.testnet-chain.linfra.xyz"],webSocket:["wss://follower.testnet-chain.linfra.xyz"]}},blockExplorers:{otterscan:{name:"Otterscan",url:"https://explorer.testnet-chain.linfra.xyz"},default:{name:"Otterscan",url:"https://explorer.testnet-chain.linfra.xyz"}},faucetUrl:"https://faucet.testnet-mud-services.linfra.xyz"};import{foundry as e}from"viem/chains";var r={...e,fees:{defaultPriorityFee:0n}};export{t as latticeTestnet,r as mudFoundry};
1
+ var t={name:"Lattice Testnet",id:4242,network:"lattice-testnet",nativeCurrency:{decimals:18,name:"Ether",symbol:"ETH"},rpcUrls:{default:{http:["https://follower.testnet-chain.linfra.xyz"],webSocket:["wss://follower.testnet-chain.linfra.xyz"]},public:{http:["https://follower.testnet-chain.linfra.xyz"],webSocket:["wss://follower.testnet-chain.linfra.xyz"]}},blockExplorers:{default:{name:"Otterscan",url:"https://explorer.testnet-chain.linfra.xyz"}},faucetUrl:"https://faucet.testnet-mud-services.linfra.xyz"};import{foundry as e}from"viem/chains";var r={...e,fees:{defaultPriorityFee:()=>0n}};export{t as latticeTestnet,r as mudFoundry};
2
2
  //# sourceMappingURL=chains.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chains/latticeTestnet.ts","../src/chains/mudFoundry.ts"],"sourcesContent":["import type { MUDChain } from \"./types\";\n\nexport const latticeTestnet = {\n name: \"Lattice Testnet\",\n id: 4242,\n network: \"lattice-testnet\",\n nativeCurrency: { decimals: 18, name: \"Ether\", symbol: \"ETH\" },\n rpcUrls: {\n default: {\n http: [\"https://follower.testnet-chain.linfra.xyz\"],\n webSocket: [\"wss://follower.testnet-chain.linfra.xyz\"],\n },\n public: {\n http: [\"https://follower.testnet-chain.linfra.xyz\"],\n webSocket: [\"wss://follower.testnet-chain.linfra.xyz\"],\n },\n },\n blockExplorers: {\n otterscan: {\n name: \"Otterscan\",\n url: \"https://explorer.testnet-chain.linfra.xyz\",\n },\n default: {\n name: \"Otterscan\",\n url: \"https://explorer.testnet-chain.linfra.xyz\",\n },\n },\n faucetUrl: \"https://faucet.testnet-mud-services.linfra.xyz\",\n} as const satisfies MUDChain;\n","import { foundry } from \"viem/chains\";\nimport { MUDChain } from \"./types\";\n\nexport const mudFoundry = {\n ...foundry,\n fees: {\n defaultPriorityFee: 0n,\n },\n} as const satisfies MUDChain;\n"],"mappings":"AAEO,IAAMA,EAAiB,CAC5B,KAAM,kBACN,GAAI,KACJ,QAAS,kBACT,eAAgB,CAAE,SAAU,GAAI,KAAM,QAAS,OAAQ,KAAM,EAC7D,QAAS,CACP,QAAS,CACP,KAAM,CAAC,2CAA2C,EAClD,UAAW,CAAC,yCAAyC,CACvD,EACA,OAAQ,CACN,KAAM,CAAC,2CAA2C,EAClD,UAAW,CAAC,yCAAyC,CACvD,CACF,EACA,eAAgB,CACd,UAAW,CACT,KAAM,YACN,IAAK,2CACP,EACA,QAAS,CACP,KAAM,YACN,IAAK,2CACP,CACF,EACA,UAAW,gDACb,EC5BA,OAAS,WAAAC,MAAe,cAGjB,IAAMC,EAAa,CACxB,GAAGD,EACH,KAAM,CACJ,mBAAoB,EACtB,CACF","names":["latticeTestnet","foundry","mudFoundry"]}
1
+ {"version":3,"sources":["../src/chains/latticeTestnet.ts","../src/chains/mudFoundry.ts"],"sourcesContent":["import type { MUDChain } from \"./types\";\n\nexport const latticeTestnet = {\n name: \"Lattice Testnet\",\n id: 4242,\n network: \"lattice-testnet\",\n nativeCurrency: { decimals: 18, name: \"Ether\", symbol: \"ETH\" },\n rpcUrls: {\n default: {\n http: [\"https://follower.testnet-chain.linfra.xyz\"],\n webSocket: [\"wss://follower.testnet-chain.linfra.xyz\"],\n },\n public: {\n http: [\"https://follower.testnet-chain.linfra.xyz\"],\n webSocket: [\"wss://follower.testnet-chain.linfra.xyz\"],\n },\n },\n blockExplorers: {\n default: {\n name: \"Otterscan\",\n url: \"https://explorer.testnet-chain.linfra.xyz\",\n },\n },\n faucetUrl: \"https://faucet.testnet-mud-services.linfra.xyz\",\n} as const satisfies MUDChain;\n","import { foundry } from \"viem/chains\";\nimport { MUDChain } from \"./types\";\n\nexport const mudFoundry = {\n ...foundry,\n fees: {\n // This is intentionally defined as a function as a workaround for https://github.com/wagmi-dev/viem/pull/1280\n defaultPriorityFee: () => 0n,\n },\n} as const satisfies MUDChain;\n"],"mappings":"AAEO,IAAMA,EAAiB,CAC5B,KAAM,kBACN,GAAI,KACJ,QAAS,kBACT,eAAgB,CAAE,SAAU,GAAI,KAAM,QAAS,OAAQ,KAAM,EAC7D,QAAS,CACP,QAAS,CACP,KAAM,CAAC,2CAA2C,EAClD,UAAW,CAAC,yCAAyC,CACvD,EACA,OAAQ,CACN,KAAM,CAAC,2CAA2C,EAClD,UAAW,CAAC,yCAAyC,CACvD,CACF,EACA,eAAgB,CACd,QAAS,CACP,KAAM,YACN,IAAK,2CACP,CACF,EACA,UAAW,gDACb,ECxBA,OAAS,WAAAC,MAAe,cAGjB,IAAMC,EAAa,CACxB,GAAGD,EACH,KAAM,CAEJ,mBAAoB,IAAM,EAC5B,CACF","names":["latticeTestnet","foundry","mudFoundry"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{privateKeyToAccount as k}from"viem/accounts";function L(e){return{...k(e)}}import{getContract as E}from"viem";import $ from"p-retry";import{BaseError as I,NonceTooHighError as M,NonceTooLowError as O}from"viem";import v from"debug";var m=v("mud:common");var P=m.extend("createNonceManager");function w({publicClient:e,address:t,blockTag:r}){let n={current:-1},o=typeof BroadcastChannel<"u"?new BroadcastChannel(`mud:createNonceManager:${e.chain?.id}:${t}`):null;o&&o.addEventListener("message",a=>{let p=JSON.parse(a.data);P("got nonce from broadcast channel",p),n.current=p});function c(){return n.current>=0}function l(){if(!c())throw new Error("call resetNonce before using nextNonce");let a=n.current++;return o?.postMessage(JSON.stringify(n.current)),a}async function u(){let a=await e.getTransactionCount({address:t,blockTag:r});n.current=a,o?.postMessage(JSON.stringify(n.current)),P("reset nonce to",n.current)}function y(a){return a instanceof I&&a.walk(p=>p instanceof O||p instanceof M)!=null}return{hasNonce:c,nextNonce:l,resetNonce:u,shouldResetNonce:y}}var d=m.extend("createContract");function S(e){let t=e.length&&Array.isArray(e[0]),r=t?e[0]:[],n=(t?e[1]:e[0])??{};return{args:r,options:n}}function ye({abi:e,address:t,publicClient:r,walletClient:n,onWrite:o}){let c=E({abi:e,address:t,publicClient:r,walletClient:n});if(c.write){let l=0,u=w({publicClient:r,address:n.account.address});c.write=new Proxy({},{get(y,a){async function p(s){if(s.gas)return d("gas provided, skipping simulate",a,s),s;d("simulating write",a,s);let{request:T}=await r.simulateContract({...s,account:s.account??n.account});return T}async function R(s){let T=await p(s);return await $(async()=>{u.hasNonce()||await u.resetNonce();let i=u.nextNonce();return d("calling write function with nonce",i,T),await n.writeContract({nonce:i,...T})},{retries:3,onFailedAttempt:async i=>{if(u.shouldResetNonce(i)){d("got nonce error, retrying",i),await u.resetNonce();return}throw i}})}return(...s)=>{let T=`${n.chain.id}:${n.account.address}:${l++}`,{args:i,options:W}=S(s),A={address:t,abi:e,functionName:a,args:i,...W},h=R(A);return o?.({id:T,request:A,result:h}),h}}})}return c}import{generatePrivateKey as B,privateKeyToAccount as H}from"viem/accounts";import{isHex as G}from"viem";function q(e,t){if(!G(e))throw console.error("Private key found in cache is not valid hex",{privateKey:e,cacheKey:t}),new Error(`Private key found in cache (${t}) is not valid hex`);H(e)}function He(e="mud:burnerWallet"){let t=localStorage.getItem(e);if(t!=null)return q(t,e),t;let r=B();return console.log("New burner wallet created:",H(r)),localStorage.setItem(e,r),r}import{hexToString as C,sliceHex as b}from"viem";var N=["table","offchainTable","namespace","module","system"];import{stringToHex as f,concatHex as j}from"viem";var x={table:"tb",offchainTable:"ot",namespace:"ns",module:"md",system:"sy"};function ve(e){let t=x[e.type];return j([f(t,{size:2}),f(e.namespace.slice(0,14),{size:14}),f(e.name.slice(0,16),{size:16})])}var D=Object.fromEntries(Object.entries(x).map(([e,t])=>[t,e]));function z(e){let t=D[e];if(N.includes(t))return t}function Be(e){let t=C(b(e,0,2)).replace(/\0+$/,""),r=z(t),n=C(b(e,2,16)).replace(/\0+$/,""),o=C(b(e,16,32)).replace(/\0+$/,"");if(!r)throw new Error(`Unknown resource type: ${t}`);return{type:r,namespace:n,name:o}}function g(e,t,r){return`0x${e.replace(/^0x/,"").slice(t*2,r!=null?r*2:void 0).padEnd(((r??t)-t)*2,"0")}`}import{concatHex as J}from"viem";function Je(e,t,r=0,n="0x"){return J([g(e,0,t),n,g(e,t+r)])}import{keccak256 as K}from"viem";var U=m.extend("transportObserver");function Qe(e){return t=>{let r=e(t);return{...r,request:async o=>{if(o.method==="eth_sendRawTransaction"&&o.params instanceof Array){let c=o.params.map(l=>K(l));U("saw txs",c)}return r.request(o)}}}}export{L as createBurnerAccount,ye as createContract,w as createNonceManager,He as getBurnerPrivateKey,Be as hexToResourceId,g as readHex,ve as resourceIdToHex,x as resourceTypeIds,N as resourceTypes,Je as spliceHex,Qe as transportObserver};
1
+ import{privateKeyToAccount as v}from"viem/accounts";function te(e){return{...v(e)}}import{BaseError as F,NonceTooHighError as B,NonceTooLowError as E}from"viem";import M from"debug";var p=M("mud:common");import{getAddress as k}from"viem";import{getChainId as I}from"viem/actions";async function m({client:e,address:n,blockTag:t}){return`mud:createNonceManager:${e.chain?.id??await I(e)}:${k(n)}:${t}`}import{getTransactionCount as $}from"viem/actions";var b=p.extend("createNonceManager");function y({client:e,address:n,blockTag:t="latest",broadcastChannelName:r}){let o={current:-1},a=null;typeof BroadcastChannel<"u"&&(r?Promise.resolve(r):m({client:e,address:n,blockTag:t})).then(s=>{a=new BroadcastChannel(s),a.addEventListener("message",O=>{let A=JSON.parse(O.data);b("got nonce from broadcast channel",A),o.current=A})});function c(){return o.current>=0}function T(){if(!c())throw new Error("call resetNonce before using nextNonce");let i=o.current++;return a?.postMessage(JSON.stringify(o.current)),i}async function d(){let i=await $(e,{address:n,blockTag:t});o.current=i,a?.postMessage(JSON.stringify(o.current)),b("reset nonce to",o.current)}function u(i){return i instanceof F&&i.walk(s=>s instanceof E||s instanceof B)!=null}return{hasNonce:c,nextNonce:T,resetNonce:d,shouldResetNonce:u}}import{getContract as D}from"viem";import{simulateContract as G,writeContract as S}from"viem/actions";import q from"p-retry";var N=new Map;async function w({client:e,address:n,blockTag:t="latest"}){let r=await m({client:e,address:n,blockTag:t}),o=N.get(r);if(o)return o;let a=y({client:e,address:n,blockTag:t});return N.set(r,a),a}import{parseAccount as _}from"viem/accounts";var l=p.extend("writeContract"),j=0;async function P(e,{onWrite:n,...t}){let r=t,o=r.account??e.account;if(!o)throw new Error("No account provided");let a=_(o),c=await w({client:e,address:a.address});async function T(){return r.gas?(l("gas provided, skipping simulate",r),r):(l("simulating write",r),(await G(e,{...r,account:a})).request)}async function d(){let i=await T();return await q(async()=>{c.hasNonce()||await c.resetNonce();let s=c.nextNonce();return l("calling write function with nonce",s,i),await S(e,{nonce:s,...i})},{retries:3,onFailedAttempt:async s=>{if(c.shouldResetNonce(s)){l("got nonce error, retrying",s),await c.resetNonce();return}throw s}})}let u=d();return n?.({id:`${j++}`,request:r,result:u}),u}function z(e){let n=e.length&&Array.isArray(e[0]),t=n?e[0]:[],r=(n?e[1]:e[0])??{};return{args:t,options:r}}function W({abi:e,address:n,publicClient:t,walletClient:r,onWrite:o}){let a=D({abi:e,address:n,publicClient:t,walletClient:r});return a.write&&(a.write=new Proxy({},{get(c,T){return(...d)=>{let{args:u,options:i}=z(d);return P(r,{abi:e,address:n,functionName:T,args:u,...i,onWrite:o})}}})),a}import{generatePrivateKey as J,privateKeyToAccount as H}from"viem/accounts";import{isHex as K}from"viem";function U(e,n){if(!K(e))throw console.error("Private key found in cache is not valid hex",{privateKey:e,cacheKey:n}),new Error(`Private key found in cache (${n}) is not valid hex`);H(e)}function Le(e="mud:burnerWallet"){let n=localStorage.getItem(e);if(n!=null)return U(n,e),n;let t=J();return console.log("New burner wallet created:",H(t)),localStorage.setItem(e,t),t}import{hexToString as x,sliceHex as g}from"viem";var R=["table","offchainTable","namespace","module","system"];import{stringToHex as C,concatHex as L}from"viem";var f={table:"tb",offchainTable:"ot",namespace:"ns",module:"md",system:"sy"};function Ze(e){let n=f[e.type];return L([C(n,{size:2}),C(e.namespace.slice(0,14),{size:14}),C(e.name.slice(0,16),{size:16})])}var Q=Object.fromEntries(Object.entries(f).map(([e,n])=>[n,e]));function V(e){let n=Q[e];if(R.includes(n))return n}function cn(e){let n=x(g(e,0,2)).replace(/\0+$/,""),t=V(n),r=x(g(e,2,16)).replace(/\0+$/,""),o=x(g(e,16,32)).replace(/\0+$/,"");if(!t)throw new Error(`Unknown resource type: ${n}`);return{type:t,namespace:r,name:o}}function h(e,n,t){return`0x${e.replace(/^0x/,"").slice(n*2,t!=null?t*2:void 0).padEnd(((t??n)-n)*2,"0")}`}import{concatHex as X}from"viem";function mn(e,n,t=0,r="0x"){return X([h(e,0,n),r,h(e,n+t)])}import{keccak256 as Y}from"viem";var Z=p.extend("transportObserver");function hn(e){return n=>{let t=e(n);return{...t,request:async o=>{if(o.method==="eth_sendRawTransaction"&&o.params instanceof Array){let a=o.params.map(c=>Y(c));Z("saw txs",a)}return t.request(o)}}}}var ee=W;export{te as createBurnerAccount,ee as createContract,y as createNonceManager,Le as getBurnerPrivateKey,W as getContract,w as getNonceManager,m as getNonceManagerId,cn as hexToResourceId,h as readHex,Ze as resourceIdToHex,f as resourceTypeIds,R as resourceTypes,mn as spliceHex,hn as transportObserver,P as writeContract};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/createBurnerAccount.ts","../src/createContract.ts","../src/createNonceManager.ts","../src/debug.ts","../src/getBurnerPrivateKey.ts","../src/hexToResourceId.ts","../src/resourceTypes.ts","../src/resourceIdToHex.ts","../src/readHex.ts","../src/spliceHex.ts","../src/transportObserver.ts"],"sourcesContent":["import { Account, Hex } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nexport function createBurnerAccount(privateKey: Hex): Account {\n const account = privateKeyToAccount(privateKey);\n // We may override account features here\n return {\n ...account,\n };\n}\n","import {\n Abi,\n Account,\n Address,\n Chain,\n GetContractParameters,\n GetContractReturnType,\n Hex,\n PublicClient,\n SimulateContractParameters,\n Transport,\n WalletClient,\n WriteContractParameters,\n getContract,\n} from \"viem\";\nimport pRetry from \"p-retry\";\nimport { createNonceManager } from \"./createNonceManager\";\nimport { debug as parentDebug } from \"./debug\";\nimport { UnionOmit } from \"./type-utils/common\";\n\nconst debug = parentDebug.extend(\"createContract\");\n\n// copied from viem because this isn't exported\n// TODO: import from viem?\nfunction getFunctionParameters(values: [args?: readonly unknown[], options?: object]): {\n args: readonly unknown[];\n options: object;\n} {\n const hasArgs = values.length && Array.isArray(values[0]);\n const args = hasArgs ? values[0]! : [];\n const options = (hasArgs ? values[1] : values[0]) ?? {};\n return { args, options };\n}\n\nexport type ContractWrite = {\n id: string;\n request: WriteContractParameters;\n result: Promise<Hex>;\n};\n\nexport type CreateContractOptions<\n TTransport extends Transport,\n TAddress extends Address,\n TAbi extends Abi,\n TChain extends Chain,\n TAccount extends Account,\n TPublicClient extends PublicClient<TTransport, TChain>,\n TWalletClient extends WalletClient<TTransport, TChain, TAccount>\n> = Required<GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>> & {\n onWrite?: (write: ContractWrite) => void;\n};\n\nexport function createContract<\n TTransport extends Transport,\n TAddress extends Address,\n TAbi extends Abi,\n TChain extends Chain,\n TAccount extends Account,\n TPublicClient extends PublicClient<TTransport, TChain>,\n TWalletClient extends WalletClient<TTransport, TChain, TAccount>\n>({\n abi,\n address,\n publicClient,\n walletClient,\n onWrite,\n}: CreateContractOptions<\n TTransport,\n TAddress,\n TAbi,\n TChain,\n TAccount,\n TPublicClient,\n TWalletClient\n>): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {\n const contract = getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({\n abi,\n address,\n publicClient,\n walletClient,\n }) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;\n\n if (contract.write) {\n let nextWriteId = 0;\n const nonceManager = createNonceManager({\n publicClient: publicClient as PublicClient,\n address: walletClient.account.address,\n });\n\n // Replace write calls with our own proxy. Implemented ~the same as viem, but adds better handling of nonces (via queue + retries).\n contract.write = new Proxy(\n {},\n {\n get(_, functionName: string): GetContractReturnType<Abi, PublicClient, WalletClient>[\"write\"][string] {\n async function prepareWrite(\n options: WriteContractParameters\n ): Promise<WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>> {\n if (options.gas) {\n debug(\"gas provided, skipping simulate\", functionName, options);\n return options as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;\n }\n\n debug(\"simulating write\", functionName, options);\n const { request } = await publicClient.simulateContract({\n ...options,\n account: options.account ?? walletClient.account,\n } as unknown as SimulateContractParameters<TAbi, typeof functionName, TChain>);\n\n return request as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;\n }\n\n async function write(options: WriteContractParameters): Promise<Hex> {\n const preparedWrite = await prepareWrite(options);\n\n return await pRetry(\n async () => {\n if (!nonceManager.hasNonce()) {\n await nonceManager.resetNonce();\n }\n\n const nonce = nonceManager.nextNonce();\n debug(\"calling write function with nonce\", nonce, preparedWrite);\n return await walletClient.writeContract({\n nonce,\n ...preparedWrite,\n });\n },\n {\n retries: 3,\n onFailedAttempt: async (error) => {\n // On nonce errors, reset the nonce and retry\n if (nonceManager.shouldResetNonce(error)) {\n debug(\"got nonce error, retrying\", error);\n await nonceManager.resetNonce();\n return;\n }\n // TODO: prepareWrite again if there are gas errors?\n throw error;\n },\n }\n );\n }\n\n return (...parameters) => {\n const id = `${walletClient.chain.id}:${walletClient.account.address}:${nextWriteId++}`;\n const { args, options } = <\n {\n args: unknown[];\n options: UnionOmit<WriteContractParameters, \"address\" | \"abi\" | \"functionName\" | \"args\">;\n }\n >getFunctionParameters(parameters as any);\n\n const request = {\n address,\n abi,\n functionName,\n args,\n ...options,\n };\n\n const result = write(request);\n\n onWrite?.({ id, request, result });\n\n return result;\n };\n },\n }\n );\n }\n\n return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;\n}\n","import {\n BaseError,\n BlockTag,\n Hex,\n NonceTooHighError,\n NonceTooLowError,\n PublicClient,\n TransactionExecutionError,\n} from \"viem\";\nimport { debug as parentDebug } from \"./debug\";\n\nconst debug = parentDebug.extend(\"createNonceManager\");\n\ntype CreateNonceManagerOptions = {\n publicClient: PublicClient;\n address: Hex;\n blockTag?: BlockTag;\n};\n\ntype CreateNonceManagerResult = {\n hasNonce: () => boolean;\n nextNonce: () => number;\n resetNonce: () => Promise<void>;\n shouldResetNonce: (error: unknown) => boolean;\n};\n\nexport function createNonceManager({\n publicClient,\n address,\n blockTag,\n}: CreateNonceManagerOptions): CreateNonceManagerResult {\n const nonceRef = { current: -1 };\n const channel =\n typeof BroadcastChannel !== \"undefined\"\n ? // TODO: fetch chain ID or require it via types?\n new BroadcastChannel(`mud:createNonceManager:${publicClient.chain?.id}:${address}`)\n : null;\n\n if (channel) {\n channel.addEventListener(\"message\", (event) => {\n const nonce = JSON.parse(event.data);\n debug(\"got nonce from broadcast channel\", nonce);\n nonceRef.current = nonce;\n });\n }\n\n function hasNonce(): boolean {\n return nonceRef.current >= 0;\n }\n\n function nextNonce(): number {\n if (!hasNonce()) throw new Error(\"call resetNonce before using nextNonce\");\n const nonce = nonceRef.current++;\n channel?.postMessage(JSON.stringify(nonceRef.current));\n return nonce;\n }\n\n async function resetNonce(): Promise<void> {\n const nonce = await publicClient.getTransactionCount({ address, blockTag });\n nonceRef.current = nonce;\n channel?.postMessage(JSON.stringify(nonceRef.current));\n debug(\"reset nonce to\", nonceRef.current);\n }\n\n function shouldResetNonce(error: unknown): boolean {\n return (\n error instanceof BaseError &&\n error.walk((e) => e instanceof NonceTooLowError || e instanceof NonceTooHighError) != null\n );\n }\n\n return {\n hasNonce,\n nextNonce,\n resetNonce,\n shouldResetNonce,\n };\n}\n","import createDebug from \"debug\";\n\nexport const debug = createDebug(\"mud:common\");\n","import { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport { isHex, Hex } from \"viem\";\n\nfunction assertPrivateKey(privateKey: string, cacheKey: string): asserts privateKey is Hex {\n if (!isHex(privateKey)) {\n console.error(\"Private key found in cache is not valid hex\", { privateKey, cacheKey });\n throw new Error(`Private key found in cache (${cacheKey}) is not valid hex`);\n }\n // ensure we can extract address from private key\n // this should throw on bad private keys\n privateKeyToAccount(privateKey);\n}\n\nexport function getBurnerPrivateKey(cacheKey = \"mud:burnerWallet\"): Hex {\n const cachedPrivateKey = localStorage.getItem(cacheKey);\n\n if (cachedPrivateKey != null) {\n assertPrivateKey(cachedPrivateKey, cacheKey);\n return cachedPrivateKey;\n }\n\n const privateKey = generatePrivateKey();\n console.log(\"New burner wallet created:\", privateKeyToAccount(privateKey));\n localStorage.setItem(cacheKey, privateKey);\n return privateKey;\n}\n","import { Hex, hexToString, sliceHex } from \"viem\";\nimport { ResourceId } from \"./common\";\nimport { ResourceType, resourceTypes } from \"./resourceTypes\";\nimport { resourceTypeIds } from \"./resourceIdToHex\";\nimport { ReverseMap } from \"./type-utils/common\";\n\nconst resourceTypeIdToType = Object.fromEntries(\n Object.entries(resourceTypeIds).map(([key, value]) => [value, key])\n) as ReverseMap<typeof resourceTypeIds>;\n\nfunction getResourceType(resourceTypeId: string): ResourceType | undefined {\n // TODO: replace Partial with `noUncheckedIndexedAccess`\n const type = (resourceTypeIdToType as Partial<Record<string, ResourceType>>)[resourceTypeId];\n if (resourceTypes.includes(type as ResourceType)) {\n return type;\n }\n}\n\nexport function hexToResourceId(hex: Hex): ResourceId {\n const resourceTypeId = hexToString(sliceHex(hex, 0, 2)).replace(/\\0+$/, \"\");\n const type = getResourceType(resourceTypeId);\n const namespace = hexToString(sliceHex(hex, 2, 16)).replace(/\\0+$/, \"\");\n const name = hexToString(sliceHex(hex, 16, 32)).replace(/\\0+$/, \"\");\n\n if (!type) {\n throw new Error(`Unknown resource type: ${resourceTypeId}`);\n }\n\n return { type, namespace, name };\n}\n","export const resourceTypes = [\"table\", \"offchainTable\", \"namespace\", \"module\", \"system\"] as const;\n\nexport type ResourceType = (typeof resourceTypes)[number];\n","import { Hex, stringToHex, concatHex } from \"viem\";\nimport { ResourceId } from \"./common\";\nimport { ResourceType } from \"./resourceTypes\";\n\n/** @internal */\nexport const resourceTypeIds = {\n // keep these in sync with storeResourceTypes.sol\n table: \"tb\",\n offchainTable: \"ot\",\n // keep these in sync with worldResourceTypes.sol\n namespace: \"ns\",\n module: \"md\",\n system: \"sy\",\n} as const satisfies Record<ResourceType, string>;\n\nexport function resourceIdToHex(resourceId: ResourceId): Hex {\n const typeId = resourceTypeIds[resourceId.type];\n return concatHex([\n stringToHex(typeId, { size: 2 }),\n stringToHex(resourceId.namespace.slice(0, 14), { size: 14 }),\n stringToHex(resourceId.name.slice(0, 16), { size: 16 }),\n ]);\n}\n","import { Hex } from \"viem\";\n\n/**\n * Get the hex value at start/end positions. This will always return a valid hex string.\n *\n * If `start` is out of range, this returns `\"0x\"`.\n *\n * If `end` is specified and out of range, the result is right zero-padded to the desired length (`end - start`).\n */\nexport function readHex(data: Hex, start: number, end?: number): Hex {\n return `0x${data\n .replace(/^0x/, \"\")\n .slice(start * 2, end != null ? end * 2 : undefined)\n .padEnd(((end ?? start) - start) * 2, \"0\")}`;\n}\n","import { Hex, concatHex } from \"viem\";\nimport { readHex } from \"./readHex\";\n\nexport function spliceHex(data: Hex, start: number, deleteCount = 0, newData: Hex = \"0x\"): Hex {\n return concatHex([readHex(data, 0, start), newData, readHex(data, start + deleteCount)]);\n}\n","import { Hex, Transport, keccak256 } from \"viem\";\nimport { debug as parentDebug } from \"./debug\";\n\nconst debug = parentDebug.extend(\"transportObserver\");\n\nexport function transportObserver<TTransport extends Transport>(transport: TTransport): TTransport {\n return ((opts) => {\n const result = transport(opts);\n const request: typeof result.request = async (req) => {\n if (req.method === \"eth_sendRawTransaction\" && req.params instanceof Array) {\n const txs = req.params.map((data: Hex) => keccak256(data));\n debug(\"saw txs\", txs);\n // TODO: pass these tx hashes into dev tools\n }\n // TODO: add support for `eth_sendTransaction`\n return result.request(req);\n };\n return {\n ...result,\n request,\n };\n }) as TTransport;\n}\n"],"mappings":"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","names":["privateKeyToAccount","createBurnerAccount","privateKey","getContract","pRetry","BaseError","NonceTooHighError","NonceTooLowError","createDebug","debug","debug","createNonceManager","publicClient","address","blockTag","nonceRef","channel","event","nonce","hasNonce","nextNonce","resetNonce","shouldResetNonce","error","BaseError","e","NonceTooLowError","NonceTooHighError","debug","getFunctionParameters","values","hasArgs","args","options","createContract","abi","address","publicClient","walletClient","onWrite","contract","getContract","nextWriteId","nonceManager","createNonceManager","_","functionName","prepareWrite","request","write","preparedWrite","pRetry","nonce","error","parameters","id","result","generatePrivateKey","privateKeyToAccount","isHex","assertPrivateKey","privateKey","cacheKey","getBurnerPrivateKey","cachedPrivateKey","hexToString","sliceHex","resourceTypes","stringToHex","concatHex","resourceTypeIds","resourceIdToHex","resourceId","typeId","resourceTypeIdToType","resourceTypeIds","key","value","getResourceType","resourceTypeId","type","resourceTypes","hexToResourceId","hex","hexToString","sliceHex","namespace","name","readHex","data","start","end","concatHex","spliceHex","data","start","deleteCount","newData","concatHex","readHex","keccak256","debug","transportObserver","transport","opts","result","req","txs","data","keccak256"]}
1
+ {"version":3,"sources":["../src/createBurnerAccount.ts","../src/createNonceManager.ts","../src/debug.ts","../src/getNonceManagerId.ts","../src/getContract.ts","../src/writeContract.ts","../src/getNonceManager.ts","../src/getBurnerPrivateKey.ts","../src/hexToResourceId.ts","../src/resourceTypes.ts","../src/resourceIdToHex.ts","../src/readHex.ts","../src/spliceHex.ts","../src/transportObserver.ts","../src/createContract.ts"],"sourcesContent":["import { Account, Hex } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nexport function createBurnerAccount(privateKey: Hex): Account {\n const account = privateKeyToAccount(privateKey);\n // We may override account features here\n return {\n ...account,\n };\n}\n","import { BaseError, BlockTag, Client, Hex, NonceTooHighError, NonceTooLowError } from \"viem\";\nimport { debug as parentDebug } from \"./debug\";\nimport { getNonceManagerId } from \"./getNonceManagerId\";\nimport { getTransactionCount } from \"viem/actions\";\n\nconst debug = parentDebug.extend(\"createNonceManager\");\n\nexport type CreateNonceManagerOptions = {\n client: Client;\n address: Hex;\n blockTag?: BlockTag;\n broadcastChannelName?: string;\n};\n\nexport type CreateNonceManagerResult = {\n hasNonce: () => boolean;\n nextNonce: () => number;\n resetNonce: () => Promise<void>;\n shouldResetNonce: (error: unknown) => boolean;\n};\n\nexport function createNonceManager({\n client,\n address,\n blockTag = \"latest\",\n broadcastChannelName,\n}: CreateNonceManagerOptions): CreateNonceManagerResult {\n const nonceRef = { current: -1 };\n let channel: BroadcastChannel | null = null;\n\n if (typeof BroadcastChannel !== \"undefined\") {\n const channelName = broadcastChannelName\n ? Promise.resolve(broadcastChannelName)\n : getNonceManagerId({ client, address, blockTag });\n channelName.then((name) => {\n channel = new BroadcastChannel(name);\n // TODO: emit some sort of \"connected\" event so other channels can broadcast current nonce\n channel.addEventListener(\"message\", (event) => {\n const nonce = JSON.parse(event.data);\n debug(\"got nonce from broadcast channel\", nonce);\n nonceRef.current = nonce;\n });\n });\n }\n\n function hasNonce(): boolean {\n return nonceRef.current >= 0;\n }\n\n function nextNonce(): number {\n if (!hasNonce()) throw new Error(\"call resetNonce before using nextNonce\");\n const nonce = nonceRef.current++;\n channel?.postMessage(JSON.stringify(nonceRef.current));\n return nonce;\n }\n\n async function resetNonce(): Promise<void> {\n const nonce = await getTransactionCount(client, { address, blockTag });\n nonceRef.current = nonce;\n channel?.postMessage(JSON.stringify(nonceRef.current));\n debug(\"reset nonce to\", nonceRef.current);\n }\n\n function shouldResetNonce(error: unknown): boolean {\n return (\n error instanceof BaseError &&\n error.walk((e) => e instanceof NonceTooLowError || e instanceof NonceTooHighError) != null\n );\n }\n\n return {\n hasNonce,\n nextNonce,\n resetNonce,\n shouldResetNonce,\n };\n}\n","import createDebug from \"debug\";\n\nexport const debug = createDebug(\"mud:common\");\n","import { BlockTag, Client, Hex, getAddress } from \"viem\";\nimport { getChainId } from \"viem/actions\";\n\nexport async function getNonceManagerId({\n client,\n address,\n blockTag,\n}: {\n client: Client;\n address: Hex;\n blockTag: BlockTag;\n}): Promise<string> {\n const chainId = client.chain?.id ?? (await getChainId(client));\n return `mud:createNonceManager:${chainId}:${getAddress(address)}:${blockTag}`;\n}\n","import {\n Abi,\n Account,\n Address,\n Chain,\n GetContractParameters,\n GetContractReturnType,\n PublicClient,\n Transport,\n WalletClient,\n WriteContractParameters,\n getContract as viem_getContract,\n} from \"viem\";\nimport { UnionOmit } from \"./type-utils/common\";\nimport { WriteContractOptions, writeContract } from \"./writeContract\";\n\n// copied from viem because this isn't exported\n// TODO: import from viem?\nfunction getFunctionParameters(values: [args?: readonly unknown[], options?: object]): {\n args: readonly unknown[];\n options: object;\n} {\n const hasArgs = values.length && Array.isArray(values[0]);\n const args = hasArgs ? values[0]! : [];\n const options = (hasArgs ? values[1] : values[0]) ?? {};\n return { args, options };\n}\n\nexport type GetContractOptions<\n TTransport extends Transport,\n TAddress extends Address,\n TAbi extends Abi,\n TChain extends Chain,\n TAccount extends Account,\n TPublicClient extends PublicClient<TTransport, TChain>,\n TWalletClient extends WalletClient<TTransport, TChain, TAccount>\n> = Required<GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>> & {\n onWrite?: WriteContractOptions[\"onWrite\"];\n};\n\n// TODO: migrate away from this approach once we can hook into viem: https://github.com/wagmi-dev/viem/discussions/1230\n\nexport function getContract<\n TTransport extends Transport,\n TAddress extends Address,\n TAbi extends Abi,\n TChain extends Chain,\n TAccount extends Account,\n TPublicClient extends PublicClient<TTransport, TChain>,\n TWalletClient extends WalletClient<TTransport, TChain, TAccount>\n>({\n abi,\n address,\n publicClient,\n walletClient,\n onWrite,\n}: GetContractOptions<\n TTransport,\n TAddress,\n TAbi,\n TChain,\n TAccount,\n TPublicClient,\n TWalletClient\n>): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {\n const contract = viem_getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({\n abi,\n address,\n publicClient,\n walletClient,\n }) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;\n\n if (contract.write) {\n // Replace write calls with our own. Implemented ~the same as viem, but adds better handling of nonces (via queue + retries).\n contract.write = new Proxy(\n {},\n {\n get(_, functionName: string) {\n return (\n ...parameters: [\n args?: readonly unknown[],\n options?: UnionOmit<WriteContractParameters, \"abi\" | \"address\" | \"functionName\" | \"args\">\n ]\n ) => {\n const { args, options } = getFunctionParameters(parameters);\n return writeContract(walletClient, {\n abi,\n address,\n functionName,\n args,\n ...options,\n onWrite,\n } as unknown as WriteContractOptions<TAbi, typeof functionName, TChain, TAccount>);\n };\n },\n }\n );\n }\n\n return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;\n}\n","import {\n Abi,\n Account,\n Chain,\n Client,\n Hex,\n SimulateContractParameters,\n Transport,\n WriteContractParameters,\n WriteContractReturnType,\n} from \"viem\";\nimport { simulateContract, writeContract as viem_writeContract } from \"viem/actions\";\nimport pRetry from \"p-retry\";\nimport { debug as parentDebug } from \"./debug\";\nimport { getNonceManager } from \"./getNonceManager\";\nimport { parseAccount } from \"viem/accounts\";\n\nconst debug = parentDebug.extend(\"writeContract\");\nlet nextWriteId = 0;\n\nexport type ContractWrite<\n TAbi extends Abi | readonly unknown[] = Abi,\n TFunctionName extends string = string,\n TChain extends Chain | undefined = Chain,\n TAccount extends Account | undefined = Account | undefined,\n TChainOverride extends Chain | undefined = Chain | undefined\n> = {\n id: string;\n request: WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;\n result: Promise<Hex>;\n};\n\nexport type WriteContractOptions<\n TAbi extends Abi | readonly unknown[] = Abi,\n TFunctionName extends string = string,\n TChain extends Chain | undefined = Chain,\n TAccount extends Account | undefined = Account | undefined,\n TChainOverride extends Chain | undefined = Chain | undefined\n> = WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride> & {\n onWrite?: (write: ContractWrite<TAbi, TFunctionName, TChain, TAccount, TChainOverride>) => void;\n};\n\n// TODO: migrate away from this approach once we can hook into viem's nonce management: https://github.com/wagmi-dev/viem/discussions/1230\n\nexport async function writeContract<\n TChain extends Chain | undefined,\n TAccount extends Account | undefined,\n TAbi extends Abi | readonly unknown[],\n TFunctionName extends string,\n TChainOverride extends Chain | undefined\n>(\n client: Client<Transport, TChain, TAccount>,\n { onWrite, ...request_ }: WriteContractOptions<TAbi, TFunctionName, TChain, TAccount, TChainOverride>\n): Promise<WriteContractReturnType> {\n const request = request_ as WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;\n\n const account_ = request.account ?? client.account;\n if (!account_) {\n // TODO: replace with viem AccountNotFoundError once its exported\n throw new Error(\"No account provided\");\n }\n const account = parseAccount(account_);\n\n const nonceManager = await getNonceManager({\n client,\n address: account.address,\n });\n\n async function prepareWrite(): Promise<\n WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>\n > {\n if (request.gas) {\n debug(\"gas provided, skipping simulate\", request);\n return request;\n }\n\n debug(\"simulating write\", request);\n const result = await simulateContract<TChain, TAbi, TFunctionName, TChainOverride>(client, {\n ...request,\n account,\n } as unknown as SimulateContractParameters<TAbi, TFunctionName, TChain, TChainOverride>);\n\n return result.request as unknown as WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;\n }\n\n async function write(): Promise<Hex> {\n const preparedWrite = await prepareWrite();\n\n return await pRetry(\n async () => {\n if (!nonceManager.hasNonce()) {\n await nonceManager.resetNonce();\n }\n\n const nonce = nonceManager.nextNonce();\n debug(\"calling write function with nonce\", nonce, preparedWrite);\n return await viem_writeContract(client, { nonce, ...preparedWrite } as typeof preparedWrite);\n },\n {\n retries: 3,\n onFailedAttempt: async (error) => {\n // On nonce errors, reset the nonce and retry\n if (nonceManager.shouldResetNonce(error)) {\n debug(\"got nonce error, retrying\", error);\n await nonceManager.resetNonce();\n return;\n }\n // TODO: prepareWrite again if there are gas errors?\n throw error;\n },\n }\n );\n }\n\n const result = write();\n\n onWrite?.({ id: `${nextWriteId++}`, request, result });\n\n return result;\n}\n","import { CreateNonceManagerOptions, CreateNonceManagerResult, createNonceManager } from \"./createNonceManager\";\nimport { getNonceManagerId } from \"./getNonceManagerId\";\n\nconst nonceManagers = new Map<string, CreateNonceManagerResult>();\n\nexport async function getNonceManager({\n client,\n address,\n blockTag = \"latest\",\n}: CreateNonceManagerOptions): Promise<CreateNonceManagerResult> {\n const id = await getNonceManagerId({ client, address, blockTag });\n\n const existingNonceManager = nonceManagers.get(id);\n if (existingNonceManager) {\n return existingNonceManager;\n }\n\n const nonceManager = createNonceManager({ client, address, blockTag });\n nonceManagers.set(id, nonceManager);\n return nonceManager;\n}\n","import { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport { isHex, Hex } from \"viem\";\n\nfunction assertPrivateKey(privateKey: string, cacheKey: string): asserts privateKey is Hex {\n if (!isHex(privateKey)) {\n console.error(\"Private key found in cache is not valid hex\", { privateKey, cacheKey });\n throw new Error(`Private key found in cache (${cacheKey}) is not valid hex`);\n }\n // ensure we can extract address from private key\n // this should throw on bad private keys\n privateKeyToAccount(privateKey);\n}\n\nexport function getBurnerPrivateKey(cacheKey = \"mud:burnerWallet\"): Hex {\n const cachedPrivateKey = localStorage.getItem(cacheKey);\n\n if (cachedPrivateKey != null) {\n assertPrivateKey(cachedPrivateKey, cacheKey);\n return cachedPrivateKey;\n }\n\n const privateKey = generatePrivateKey();\n console.log(\"New burner wallet created:\", privateKeyToAccount(privateKey));\n localStorage.setItem(cacheKey, privateKey);\n return privateKey;\n}\n","import { Hex, hexToString, sliceHex } from \"viem\";\nimport { ResourceId } from \"./common\";\nimport { ResourceType, resourceTypes } from \"./resourceTypes\";\nimport { resourceTypeIds } from \"./resourceIdToHex\";\nimport { ReverseMap } from \"./type-utils/common\";\n\nconst resourceTypeIdToType = Object.fromEntries(\n Object.entries(resourceTypeIds).map(([key, value]) => [value, key])\n) as ReverseMap<typeof resourceTypeIds>;\n\nfunction getResourceType(resourceTypeId: string): ResourceType | undefined {\n // TODO: replace Partial with `noUncheckedIndexedAccess`\n const type = (resourceTypeIdToType as Partial<Record<string, ResourceType>>)[resourceTypeId];\n if (resourceTypes.includes(type as ResourceType)) {\n return type;\n }\n}\n\nexport function hexToResourceId(hex: Hex): ResourceId {\n const resourceTypeId = hexToString(sliceHex(hex, 0, 2)).replace(/\\0+$/, \"\");\n const type = getResourceType(resourceTypeId);\n const namespace = hexToString(sliceHex(hex, 2, 16)).replace(/\\0+$/, \"\");\n const name = hexToString(sliceHex(hex, 16, 32)).replace(/\\0+$/, \"\");\n\n if (!type) {\n throw new Error(`Unknown resource type: ${resourceTypeId}`);\n }\n\n return { type, namespace, name };\n}\n","export const resourceTypes = [\"table\", \"offchainTable\", \"namespace\", \"module\", \"system\"] as const;\n\nexport type ResourceType = (typeof resourceTypes)[number];\n","import { Hex, stringToHex, concatHex } from \"viem\";\nimport { ResourceId } from \"./common\";\nimport { ResourceType } from \"./resourceTypes\";\n\n/** @internal */\nexport const resourceTypeIds = {\n // keep these in sync with storeResourceTypes.sol\n table: \"tb\",\n offchainTable: \"ot\",\n // keep these in sync with worldResourceTypes.sol\n namespace: \"ns\",\n module: \"md\",\n system: \"sy\",\n} as const satisfies Record<ResourceType, string>;\n\nexport function resourceIdToHex(resourceId: ResourceId): Hex {\n const typeId = resourceTypeIds[resourceId.type];\n return concatHex([\n stringToHex(typeId, { size: 2 }),\n stringToHex(resourceId.namespace.slice(0, 14), { size: 14 }),\n stringToHex(resourceId.name.slice(0, 16), { size: 16 }),\n ]);\n}\n","import { Hex } from \"viem\";\n\n/**\n * Get the hex value at start/end positions. This will always return a valid hex string.\n *\n * If `start` is out of range, this returns `\"0x\"`.\n *\n * If `end` is specified and out of range, the result is right zero-padded to the desired length (`end - start`).\n */\nexport function readHex(data: Hex, start: number, end?: number): Hex {\n return `0x${data\n .replace(/^0x/, \"\")\n .slice(start * 2, end != null ? end * 2 : undefined)\n .padEnd(((end ?? start) - start) * 2, \"0\")}`;\n}\n","import { Hex, concatHex } from \"viem\";\nimport { readHex } from \"./readHex\";\n\nexport function spliceHex(data: Hex, start: number, deleteCount = 0, newData: Hex = \"0x\"): Hex {\n return concatHex([readHex(data, 0, start), newData, readHex(data, start + deleteCount)]);\n}\n","import { Hex, Transport, keccak256 } from \"viem\";\nimport { debug as parentDebug } from \"./debug\";\n\nconst debug = parentDebug.extend(\"transportObserver\");\n\nexport function transportObserver<TTransport extends Transport>(transport: TTransport): TTransport {\n return ((opts) => {\n const result = transport(opts);\n const request: typeof result.request = async (req) => {\n if (req.method === \"eth_sendRawTransaction\" && req.params instanceof Array) {\n const txs = req.params.map((data: Hex) => keccak256(data));\n debug(\"saw txs\", txs);\n // TODO: pass these tx hashes into dev tools\n }\n // TODO: add support for `eth_sendTransaction`\n return result.request(req);\n };\n return {\n ...result,\n request,\n };\n }) as TTransport;\n}\n","import { getContract } from \"./getContract\";\n\n/** @deprecated use `getContract` instead */\nexport const createContract = getContract;\n"],"mappings":"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","names":["privateKeyToAccount","createBurnerAccount","privateKey","BaseError","NonceTooHighError","NonceTooLowError","createDebug","debug","getAddress","getChainId","getNonceManagerId","client","address","blockTag","getTransactionCount","debug","createNonceManager","client","address","blockTag","broadcastChannelName","nonceRef","channel","getNonceManagerId","name","event","nonce","hasNonce","nextNonce","resetNonce","shouldResetNonce","error","BaseError","e","NonceTooLowError","NonceTooHighError","viem_getContract","simulateContract","viem_writeContract","pRetry","nonceManagers","getNonceManager","client","address","blockTag","id","getNonceManagerId","existingNonceManager","nonceManager","createNonceManager","parseAccount","debug","nextWriteId","writeContract","client","onWrite","request_","request","account_","account","nonceManager","getNonceManager","prepareWrite","simulateContract","write","preparedWrite","pRetry","nonce","viem_writeContract","error","result","getFunctionParameters","values","hasArgs","args","options","getContract","abi","address","publicClient","walletClient","onWrite","contract","viem_getContract","_","functionName","parameters","writeContract","generatePrivateKey","privateKeyToAccount","isHex","assertPrivateKey","privateKey","cacheKey","getBurnerPrivateKey","cachedPrivateKey","hexToString","sliceHex","resourceTypes","stringToHex","concatHex","resourceTypeIds","resourceIdToHex","resourceId","typeId","resourceTypeIdToType","resourceTypeIds","key","value","getResourceType","resourceTypeId","type","resourceTypes","hexToResourceId","hex","hexToString","sliceHex","namespace","name","readHex","data","start","end","concatHex","spliceHex","data","start","deleteCount","newData","concatHex","readHex","keccak256","debug","transportObserver","transport","opts","result","req","txs","data","keccak256","createContract","getContract"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/common",
3
- "version": "2.0.0-next.10",
3
+ "version": "2.0.0-next.11",
4
4
  "description": "Common low level logic shared between packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,15 +49,14 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@solidity-parser/parser": "^0.16.0",
52
- "abitype": "0.9.3",
53
52
  "chalk": "^5.2.0",
54
53
  "debug": "^4.3.4",
55
54
  "execa": "^7.0.0",
56
55
  "p-retry": "^5.1.2",
57
56
  "prettier": "^2.8.4",
58
57
  "prettier-plugin-solidity": "^1.1.2",
59
- "viem": "1.6.0",
60
- "@latticexyz/schema-type": "2.0.0-next.10"
58
+ "viem": "1.14.0",
59
+ "@latticexyz/schema-type": "2.0.0-next.11"
61
60
  },
62
61
  "devDependencies": {
63
62
  "@types/debug": "^4.1.7",
@@ -16,10 +16,6 @@ export const latticeTestnet = {
16
16
  },
17
17
  },
18
18
  blockExplorers: {
19
- otterscan: {
20
- name: "Otterscan",
21
- url: "https://explorer.testnet-chain.linfra.xyz",
22
- },
23
19
  default: {
24
20
  name: "Otterscan",
25
21
  url: "https://explorer.testnet-chain.linfra.xyz",
@@ -4,6 +4,7 @@ import { MUDChain } from "./types";
4
4
  export const mudFoundry = {
5
5
  ...foundry,
6
6
  fees: {
7
- defaultPriorityFee: 0n,
7
+ // This is intentionally defined as a function as a workaround for https://github.com/wagmi-dev/viem/pull/1280
8
+ defaultPriorityFee: () => 0n,
8
9
  },
9
10
  } as const satisfies MUDChain;
@@ -1,173 +1,4 @@
1
- import {
2
- Abi,
3
- Account,
4
- Address,
5
- Chain,
6
- GetContractParameters,
7
- GetContractReturnType,
8
- Hex,
9
- PublicClient,
10
- SimulateContractParameters,
11
- Transport,
12
- WalletClient,
13
- WriteContractParameters,
14
- getContract,
15
- } from "viem";
16
- import pRetry from "p-retry";
17
- import { createNonceManager } from "./createNonceManager";
18
- import { debug as parentDebug } from "./debug";
19
- import { UnionOmit } from "./type-utils/common";
1
+ import { getContract } from "./getContract";
20
2
 
21
- const debug = parentDebug.extend("createContract");
22
-
23
- // copied from viem because this isn't exported
24
- // TODO: import from viem?
25
- function getFunctionParameters(values: [args?: readonly unknown[], options?: object]): {
26
- args: readonly unknown[];
27
- options: object;
28
- } {
29
- const hasArgs = values.length && Array.isArray(values[0]);
30
- const args = hasArgs ? values[0]! : [];
31
- const options = (hasArgs ? values[1] : values[0]) ?? {};
32
- return { args, options };
33
- }
34
-
35
- export type ContractWrite = {
36
- id: string;
37
- request: WriteContractParameters;
38
- result: Promise<Hex>;
39
- };
40
-
41
- export type CreateContractOptions<
42
- TTransport extends Transport,
43
- TAddress extends Address,
44
- TAbi extends Abi,
45
- TChain extends Chain,
46
- TAccount extends Account,
47
- TPublicClient extends PublicClient<TTransport, TChain>,
48
- TWalletClient extends WalletClient<TTransport, TChain, TAccount>
49
- > = Required<GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>> & {
50
- onWrite?: (write: ContractWrite) => void;
51
- };
52
-
53
- export function createContract<
54
- TTransport extends Transport,
55
- TAddress extends Address,
56
- TAbi extends Abi,
57
- TChain extends Chain,
58
- TAccount extends Account,
59
- TPublicClient extends PublicClient<TTransport, TChain>,
60
- TWalletClient extends WalletClient<TTransport, TChain, TAccount>
61
- >({
62
- abi,
63
- address,
64
- publicClient,
65
- walletClient,
66
- onWrite,
67
- }: CreateContractOptions<
68
- TTransport,
69
- TAddress,
70
- TAbi,
71
- TChain,
72
- TAccount,
73
- TPublicClient,
74
- TWalletClient
75
- >): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {
76
- const contract = getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({
77
- abi,
78
- address,
79
- publicClient,
80
- walletClient,
81
- }) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;
82
-
83
- if (contract.write) {
84
- let nextWriteId = 0;
85
- const nonceManager = createNonceManager({
86
- publicClient: publicClient as PublicClient,
87
- address: walletClient.account.address,
88
- });
89
-
90
- // Replace write calls with our own proxy. Implemented ~the same as viem, but adds better handling of nonces (via queue + retries).
91
- contract.write = new Proxy(
92
- {},
93
- {
94
- get(_, functionName: string): GetContractReturnType<Abi, PublicClient, WalletClient>["write"][string] {
95
- async function prepareWrite(
96
- options: WriteContractParameters
97
- ): Promise<WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>> {
98
- if (options.gas) {
99
- debug("gas provided, skipping simulate", functionName, options);
100
- return options as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;
101
- }
102
-
103
- debug("simulating write", functionName, options);
104
- const { request } = await publicClient.simulateContract({
105
- ...options,
106
- account: options.account ?? walletClient.account,
107
- } as unknown as SimulateContractParameters<TAbi, typeof functionName, TChain>);
108
-
109
- return request as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;
110
- }
111
-
112
- async function write(options: WriteContractParameters): Promise<Hex> {
113
- const preparedWrite = await prepareWrite(options);
114
-
115
- return await pRetry(
116
- async () => {
117
- if (!nonceManager.hasNonce()) {
118
- await nonceManager.resetNonce();
119
- }
120
-
121
- const nonce = nonceManager.nextNonce();
122
- debug("calling write function with nonce", nonce, preparedWrite);
123
- return await walletClient.writeContract({
124
- nonce,
125
- ...preparedWrite,
126
- });
127
- },
128
- {
129
- retries: 3,
130
- onFailedAttempt: async (error) => {
131
- // On nonce errors, reset the nonce and retry
132
- if (nonceManager.shouldResetNonce(error)) {
133
- debug("got nonce error, retrying", error);
134
- await nonceManager.resetNonce();
135
- return;
136
- }
137
- // TODO: prepareWrite again if there are gas errors?
138
- throw error;
139
- },
140
- }
141
- );
142
- }
143
-
144
- return (...parameters) => {
145
- const id = `${walletClient.chain.id}:${walletClient.account.address}:${nextWriteId++}`;
146
- const { args, options } = <
147
- {
148
- args: unknown[];
149
- options: UnionOmit<WriteContractParameters, "address" | "abi" | "functionName" | "args">;
150
- }
151
- >getFunctionParameters(parameters as any);
152
-
153
- const request = {
154
- address,
155
- abi,
156
- functionName,
157
- args,
158
- ...options,
159
- };
160
-
161
- const result = write(request);
162
-
163
- onWrite?.({ id, request, result });
164
-
165
- return result;
166
- };
167
- },
168
- }
169
- );
170
- }
171
-
172
- return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;
173
- }
3
+ /** @deprecated use `getContract` instead */
4
+ export const createContract = getContract;
@@ -1,23 +1,18 @@
1
- import {
2
- BaseError,
3
- BlockTag,
4
- Hex,
5
- NonceTooHighError,
6
- NonceTooLowError,
7
- PublicClient,
8
- TransactionExecutionError,
9
- } from "viem";
1
+ import { BaseError, BlockTag, Client, Hex, NonceTooHighError, NonceTooLowError } from "viem";
10
2
  import { debug as parentDebug } from "./debug";
3
+ import { getNonceManagerId } from "./getNonceManagerId";
4
+ import { getTransactionCount } from "viem/actions";
11
5
 
12
6
  const debug = parentDebug.extend("createNonceManager");
13
7
 
14
- type CreateNonceManagerOptions = {
15
- publicClient: PublicClient;
8
+ export type CreateNonceManagerOptions = {
9
+ client: Client;
16
10
  address: Hex;
17
11
  blockTag?: BlockTag;
12
+ broadcastChannelName?: string;
18
13
  };
19
14
 
20
- type CreateNonceManagerResult = {
15
+ export type CreateNonceManagerResult = {
21
16
  hasNonce: () => boolean;
22
17
  nextNonce: () => number;
23
18
  resetNonce: () => Promise<void>;
@@ -25,22 +20,26 @@ type CreateNonceManagerResult = {
25
20
  };
26
21
 
27
22
  export function createNonceManager({
28
- publicClient,
23
+ client,
29
24
  address,
30
- blockTag,
25
+ blockTag = "latest",
26
+ broadcastChannelName,
31
27
  }: CreateNonceManagerOptions): CreateNonceManagerResult {
32
28
  const nonceRef = { current: -1 };
33
- const channel =
34
- typeof BroadcastChannel !== "undefined"
35
- ? // TODO: fetch chain ID or require it via types?
36
- new BroadcastChannel(`mud:createNonceManager:${publicClient.chain?.id}:${address}`)
37
- : null;
29
+ let channel: BroadcastChannel | null = null;
38
30
 
39
- if (channel) {
40
- channel.addEventListener("message", (event) => {
41
- const nonce = JSON.parse(event.data);
42
- debug("got nonce from broadcast channel", nonce);
43
- nonceRef.current = nonce;
31
+ if (typeof BroadcastChannel !== "undefined") {
32
+ const channelName = broadcastChannelName
33
+ ? Promise.resolve(broadcastChannelName)
34
+ : getNonceManagerId({ client, address, blockTag });
35
+ channelName.then((name) => {
36
+ channel = new BroadcastChannel(name);
37
+ // TODO: emit some sort of "connected" event so other channels can broadcast current nonce
38
+ channel.addEventListener("message", (event) => {
39
+ const nonce = JSON.parse(event.data);
40
+ debug("got nonce from broadcast channel", nonce);
41
+ nonceRef.current = nonce;
42
+ });
44
43
  });
45
44
  }
46
45
 
@@ -56,7 +55,7 @@ export function createNonceManager({
56
55
  }
57
56
 
58
57
  async function resetNonce(): Promise<void> {
59
- const nonce = await publicClient.getTransactionCount({ address, blockTag });
58
+ const nonce = await getTransactionCount(client, { address, blockTag });
60
59
  nonceRef.current = nonce;
61
60
  channel?.postMessage(JSON.stringify(nonceRef.current));
62
61
  debug("reset nonce to", nonceRef.current);
@@ -0,0 +1,101 @@
1
+ import {
2
+ Abi,
3
+ Account,
4
+ Address,
5
+ Chain,
6
+ GetContractParameters,
7
+ GetContractReturnType,
8
+ PublicClient,
9
+ Transport,
10
+ WalletClient,
11
+ WriteContractParameters,
12
+ getContract as viem_getContract,
13
+ } from "viem";
14
+ import { UnionOmit } from "./type-utils/common";
15
+ import { WriteContractOptions, writeContract } from "./writeContract";
16
+
17
+ // copied from viem because this isn't exported
18
+ // TODO: import from viem?
19
+ function getFunctionParameters(values: [args?: readonly unknown[], options?: object]): {
20
+ args: readonly unknown[];
21
+ options: object;
22
+ } {
23
+ const hasArgs = values.length && Array.isArray(values[0]);
24
+ const args = hasArgs ? values[0]! : [];
25
+ const options = (hasArgs ? values[1] : values[0]) ?? {};
26
+ return { args, options };
27
+ }
28
+
29
+ export type GetContractOptions<
30
+ TTransport extends Transport,
31
+ TAddress extends Address,
32
+ TAbi extends Abi,
33
+ TChain extends Chain,
34
+ TAccount extends Account,
35
+ TPublicClient extends PublicClient<TTransport, TChain>,
36
+ TWalletClient extends WalletClient<TTransport, TChain, TAccount>
37
+ > = Required<GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>> & {
38
+ onWrite?: WriteContractOptions["onWrite"];
39
+ };
40
+
41
+ // TODO: migrate away from this approach once we can hook into viem: https://github.com/wagmi-dev/viem/discussions/1230
42
+
43
+ export function getContract<
44
+ TTransport extends Transport,
45
+ TAddress extends Address,
46
+ TAbi extends Abi,
47
+ TChain extends Chain,
48
+ TAccount extends Account,
49
+ TPublicClient extends PublicClient<TTransport, TChain>,
50
+ TWalletClient extends WalletClient<TTransport, TChain, TAccount>
51
+ >({
52
+ abi,
53
+ address,
54
+ publicClient,
55
+ walletClient,
56
+ onWrite,
57
+ }: GetContractOptions<
58
+ TTransport,
59
+ TAddress,
60
+ TAbi,
61
+ TChain,
62
+ TAccount,
63
+ TPublicClient,
64
+ TWalletClient
65
+ >): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {
66
+ const contract = viem_getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({
67
+ abi,
68
+ address,
69
+ publicClient,
70
+ walletClient,
71
+ }) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;
72
+
73
+ if (contract.write) {
74
+ // Replace write calls with our own. Implemented ~the same as viem, but adds better handling of nonces (via queue + retries).
75
+ contract.write = new Proxy(
76
+ {},
77
+ {
78
+ get(_, functionName: string) {
79
+ return (
80
+ ...parameters: [
81
+ args?: readonly unknown[],
82
+ options?: UnionOmit<WriteContractParameters, "abi" | "address" | "functionName" | "args">
83
+ ]
84
+ ) => {
85
+ const { args, options } = getFunctionParameters(parameters);
86
+ return writeContract(walletClient, {
87
+ abi,
88
+ address,
89
+ functionName,
90
+ args,
91
+ ...options,
92
+ onWrite,
93
+ } as unknown as WriteContractOptions<TAbi, typeof functionName, TChain, TAccount>);
94
+ };
95
+ },
96
+ }
97
+ );
98
+ }
99
+
100
+ return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;
101
+ }
@@ -0,0 +1,21 @@
1
+ import { CreateNonceManagerOptions, CreateNonceManagerResult, createNonceManager } from "./createNonceManager";
2
+ import { getNonceManagerId } from "./getNonceManagerId";
3
+
4
+ const nonceManagers = new Map<string, CreateNonceManagerResult>();
5
+
6
+ export async function getNonceManager({
7
+ client,
8
+ address,
9
+ blockTag = "latest",
10
+ }: CreateNonceManagerOptions): Promise<CreateNonceManagerResult> {
11
+ const id = await getNonceManagerId({ client, address, blockTag });
12
+
13
+ const existingNonceManager = nonceManagers.get(id);
14
+ if (existingNonceManager) {
15
+ return existingNonceManager;
16
+ }
17
+
18
+ const nonceManager = createNonceManager({ client, address, blockTag });
19
+ nonceManagers.set(id, nonceManager);
20
+ return nonceManager;
21
+ }
@@ -0,0 +1,15 @@
1
+ import { BlockTag, Client, Hex, getAddress } from "viem";
2
+ import { getChainId } from "viem/actions";
3
+
4
+ export async function getNonceManagerId({
5
+ client,
6
+ address,
7
+ blockTag,
8
+ }: {
9
+ client: Client;
10
+ address: Hex;
11
+ blockTag: BlockTag;
12
+ }): Promise<string> {
13
+ const chainId = client.chain?.id ?? (await getChainId(client));
14
+ return `mud:createNonceManager:${chainId}:${getAddress(address)}:${blockTag}`;
15
+ }
package/src/index.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  export * from "./common";
2
2
  export * from "./createBurnerAccount";
3
- export * from "./createContract";
4
3
  export * from "./createNonceManager";
4
+ export * from "./getContract";
5
5
  export * from "./getBurnerPrivateKey";
6
+ export * from "./getNonceManager";
7
+ export * from "./getNonceManagerId";
6
8
  export * from "./hexToResourceId";
7
9
  export * from "./readHex";
8
10
  export * from "./resourceIdToHex";
9
11
  export * from "./resourceTypes";
10
12
  export * from "./spliceHex";
11
13
  export * from "./transportObserver";
14
+ export * from "./writeContract";
15
+
16
+ /** @deprecated use `getContract` instead */
17
+ export { createContract } from "./createContract";
@@ -0,0 +1,120 @@
1
+ import {
2
+ Abi,
3
+ Account,
4
+ Chain,
5
+ Client,
6
+ Hex,
7
+ SimulateContractParameters,
8
+ Transport,
9
+ WriteContractParameters,
10
+ WriteContractReturnType,
11
+ } from "viem";
12
+ import { simulateContract, writeContract as viem_writeContract } from "viem/actions";
13
+ import pRetry from "p-retry";
14
+ import { debug as parentDebug } from "./debug";
15
+ import { getNonceManager } from "./getNonceManager";
16
+ import { parseAccount } from "viem/accounts";
17
+
18
+ const debug = parentDebug.extend("writeContract");
19
+ let nextWriteId = 0;
20
+
21
+ export type ContractWrite<
22
+ TAbi extends Abi | readonly unknown[] = Abi,
23
+ TFunctionName extends string = string,
24
+ TChain extends Chain | undefined = Chain,
25
+ TAccount extends Account | undefined = Account | undefined,
26
+ TChainOverride extends Chain | undefined = Chain | undefined
27
+ > = {
28
+ id: string;
29
+ request: WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;
30
+ result: Promise<Hex>;
31
+ };
32
+
33
+ export type WriteContractOptions<
34
+ TAbi extends Abi | readonly unknown[] = Abi,
35
+ TFunctionName extends string = string,
36
+ TChain extends Chain | undefined = Chain,
37
+ TAccount extends Account | undefined = Account | undefined,
38
+ TChainOverride extends Chain | undefined = Chain | undefined
39
+ > = WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride> & {
40
+ onWrite?: (write: ContractWrite<TAbi, TFunctionName, TChain, TAccount, TChainOverride>) => void;
41
+ };
42
+
43
+ // TODO: migrate away from this approach once we can hook into viem's nonce management: https://github.com/wagmi-dev/viem/discussions/1230
44
+
45
+ export async function writeContract<
46
+ TChain extends Chain | undefined,
47
+ TAccount extends Account | undefined,
48
+ TAbi extends Abi | readonly unknown[],
49
+ TFunctionName extends string,
50
+ TChainOverride extends Chain | undefined
51
+ >(
52
+ client: Client<Transport, TChain, TAccount>,
53
+ { onWrite, ...request_ }: WriteContractOptions<TAbi, TFunctionName, TChain, TAccount, TChainOverride>
54
+ ): Promise<WriteContractReturnType> {
55
+ const request = request_ as WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;
56
+
57
+ const account_ = request.account ?? client.account;
58
+ if (!account_) {
59
+ // TODO: replace with viem AccountNotFoundError once its exported
60
+ throw new Error("No account provided");
61
+ }
62
+ const account = parseAccount(account_);
63
+
64
+ const nonceManager = await getNonceManager({
65
+ client,
66
+ address: account.address,
67
+ });
68
+
69
+ async function prepareWrite(): Promise<
70
+ WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>
71
+ > {
72
+ if (request.gas) {
73
+ debug("gas provided, skipping simulate", request);
74
+ return request;
75
+ }
76
+
77
+ debug("simulating write", request);
78
+ const result = await simulateContract<TChain, TAbi, TFunctionName, TChainOverride>(client, {
79
+ ...request,
80
+ account,
81
+ } as unknown as SimulateContractParameters<TAbi, TFunctionName, TChain, TChainOverride>);
82
+
83
+ return result.request as unknown as WriteContractParameters<TAbi, TFunctionName, TChain, TAccount, TChainOverride>;
84
+ }
85
+
86
+ async function write(): Promise<Hex> {
87
+ const preparedWrite = await prepareWrite();
88
+
89
+ return await pRetry(
90
+ async () => {
91
+ if (!nonceManager.hasNonce()) {
92
+ await nonceManager.resetNonce();
93
+ }
94
+
95
+ const nonce = nonceManager.nextNonce();
96
+ debug("calling write function with nonce", nonce, preparedWrite);
97
+ return await viem_writeContract(client, { nonce, ...preparedWrite } as typeof preparedWrite);
98
+ },
99
+ {
100
+ retries: 3,
101
+ onFailedAttempt: async (error) => {
102
+ // On nonce errors, reset the nonce and retry
103
+ if (nonceManager.shouldResetNonce(error)) {
104
+ debug("got nonce error, retrying", error);
105
+ await nonceManager.resetNonce();
106
+ return;
107
+ }
108
+ // TODO: prepareWrite again if there are gas errors?
109
+ throw error;
110
+ },
111
+ }
112
+ );
113
+ }
114
+
115
+ const result = write();
116
+
117
+ onWrite?.({ id: `${nextWriteId++}`, request, result });
118
+
119
+ return result;
120
+ }