@latticexyz/common 2.0.0-next.1 → 2.0.0-next.2

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};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:{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};
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 // We may override chain settings here\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,CAEL","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 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"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{privateKeyToAccount as y}from"viem/accounts";function G(e){return{...y(e)}}import{getContract as P}from"viem";import w from"p-retry";import h from"debug";var p=h("mud:common");var g=p.extend("createNonceManager");function f({publicClient:e,address:n,blockTag:a}){let t={current:-1},r=typeof BroadcastChannel<"u"?new BroadcastChannel(`mud:createNonceManager:${e.chain?.id}:${n}`):null;r&&r.addEventListener("message",c=>{let o=JSON.parse(c.data);g("got nonce from broadcast channel",o),t.current=o});function s(){return t.current>=0}function m(){if(!s())throw new Error("call resetNonce before using nextNonce");let c=t.current++;return r?.postMessage(JSON.stringify(t.current)),c}async function u(){let c=await e.getTransactionCount({address:n,blockTag:a});t.current=c,r?.postMessage(JSON.stringify(t.current)),g("reset nonce to",t.current)}function T(c){return/already known|nonce too low/.test(String(c))}return{hasNonce:s,nextNonce:m,resetNonce:u,shouldResetNonce:T}}var l=p.extend("createContract");function N(e){let n=e.length&&Array.isArray(e[0]),a=n?e[0]:[],t=(n?e[1]:e[0])??{};return{args:a,options:t}}function X({abi:e,address:n,publicClient:a,walletClient:t}){let r=P({abi:e,address:n,publicClient:a,walletClient:t});if(r.write){let s=f({publicClient:a,address:t.account.address});r.write=new Proxy({},{get(m,u){return async(...T)=>{let{args:c,options:o}=N(T);t.chain.id===31337&&o.maxFeePerGas==null&&o.maxPriorityFeePerGas==null&&(l("assuming zero base fee for anvil chain"),o.maxFeePerGas=0n,o.maxPriorityFeePerGas=0n);async function A(){if(o.gas)return l("gas provided, skipping simulate",u,c,o),{address:n,abi:e,functionName:u,args:c,...o};l("simulating write",u,c,o);let{request:i}=await a.simulateContract({address:n,abi:e,functionName:u,args:c,...o,account:o.account??t.account});return i}let d=await A();return await w(async()=>{s.hasNonce()||await s.resetNonce();let i=s.nextNonce();return l("calling write function with nonce",i,d),await t.writeContract({nonce:i,...d})},{retries:3,onFailedAttempt:async i=>{if(s.shouldResetNonce(i)){l("got nonce error, retrying",i),await s.resetNonce();return}throw i}})}}})}return r}import{hexToString as C,sliceHex as b}from"viem";function ne(e){let n=C(b(e,0,16)).replace(/\0+$/,""),a=C(b(e,16,32)).replace(/\0+$/,"");return{namespace:n,name:a}}import{stringToHex as x,concatHex as k}from"viem";function ae(e,n){return k([x(e.substring(0,16),{size:16}),x(n.substring(0,16),{size:16})])}import{keccak256 as W}from"viem";var H=p.extend("transportObserver");function le(e){return n=>{let a=e(n);return{...a,request:async r=>{if(r.method==="eth_sendRawTransaction"&&r.params instanceof Array){let s=r.params.map(m=>W(m));H("saw txs",s)}return a.request(r)}}}}export{G as createBurnerAccount,X as createContract,f as createNonceManager,ne as hexToTableId,ae as tableIdToHex,le as transportObserver};
1
+ import{privateKeyToAccount as w}from"viem/accounts";function q(e){return{...w(e)}}import{getContract as M}from"viem";import O from"p-retry";import{BaseError as H,NonceTooHighError as k,NonceTooLowError as R}from"viem";import W from"debug";var l=W("mud:common");var x=l.extend("createNonceManager");function b({publicClient:e,address:n,blockTag:r}){let t={current:-1},a=typeof BroadcastChannel<"u"?new BroadcastChannel(`mud:createNonceManager:${e.chain?.id}:${n}`):null;a&&a.addEventListener("message",o=>{let T=JSON.parse(o.data);x("got nonce from broadcast channel",T),t.current=T});function s(){return t.current>=0}function d(){if(!s())throw new Error("call resetNonce before using nextNonce");let o=t.current++;return a?.postMessage(JSON.stringify(t.current)),o}async function u(){let o=await e.getTransactionCount({address:n,blockTag:r});t.current=o,a?.postMessage(JSON.stringify(t.current)),x("reset nonce to",t.current)}function C(o){return o instanceof H&&o.walk(T=>T instanceof R||T instanceof k)!=null}return{hasNonce:s,nextNonce:d,resetNonce:u,shouldResetNonce:C}}var m=l.extend("createContract");function E(e){let n=e.length&&Array.isArray(e[0]),r=n?e[0]:[],t=(n?e[1]:e[0])??{};return{args:r,options:t}}function Te({abi:e,address:n,publicClient:r,walletClient:t,onWrite:a}){let s=M({abi:e,address:n,publicClient:r,walletClient:t});if(s.write){let d=0,u=b({publicClient:r,address:t.account.address});s.write=new Proxy({},{get(C,o){async function T(c){if(c.gas)return m("gas provided, skipping simulate",o,c),c;m("simulating write",o,c);let{request:p}=await r.simulateContract({...c,account:c.account??t.account});return p}async function y(c){let p=await T(c);return await O(async()=>{u.hasNonce()||await u.resetNonce();let i=u.nextNonce();return m("calling write function with nonce",i,p),await t.writeContract({nonce:i,...p})},{retries:3,onFailedAttempt:async i=>{if(u.shouldResetNonce(i)){m("got nonce error, retrying",i),await u.resetNonce();return}throw i}})}return(...c)=>{let p=`${t.chain.id}:${t.account.address}:${d++}`,{args:i,options:N}=E(c),g={address:n,abi:e,functionName:o,args:i,...N},f=y(g);return a?.({id:p,request:g,result:f}),f}}})}return s}import{hexToString as A,sliceHex as h}from"viem";function me(e){let n=A(h(e,0,16)).replace(/\0+$/,""),r=A(h(e,16,32)).replace(/\0+$/,"");return{namespace:n,name:r}}import{stringToHex as P,concatHex as G}from"viem";function xe(e,n){return G([P(e.substring(0,16),{size:16}),P(n.substring(0,16),{size:16})])}import{keccak256 as $}from"viem";var B=l.extend("transportObserver");function Ne(e){return n=>{let r=e(n);return{...r,request:async a=>{if(a.method==="eth_sendRawTransaction"&&a.params instanceof Array){let s=a.params.map(d=>$(d));B("saw txs",s)}return r.request(a)}}}}export{q as createBurnerAccount,Te as createContract,b as createNonceManager,me as hexToTableId,xe as tableIdToHex,Ne as transportObserver};
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/debug.ts","../src/createNonceManager.ts","../src/hexToTableId.ts","../src/tableIdToHex.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 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 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}: Required<\n GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>\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 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 return async (...parameters) => {\n const { args, options } = <\n {\n args: unknown[];\n options: UnionOmit<WriteContractParameters, \"abi\" | \"address\" | \"functionName\" | \"args\">;\n }\n >getFunctionParameters(parameters as any);\n\n // Temporarily override base fee for our default anvil config\n // TODO: replace with https://github.com/wagmi-dev/viem/pull/1006 once merged\n // TODO: more specific mud foundry check? or can we safely assume anvil+mud will be block fee zero for now?\n if (\n walletClient.chain.id === 31337 &&\n options.maxFeePerGas == null &&\n options.maxPriorityFeePerGas == null\n ) {\n debug(\"assuming zero base fee for anvil chain\");\n options.maxFeePerGas = 0n;\n options.maxPriorityFeePerGas = 0n;\n }\n\n async function prepareWrite(): Promise<\n WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>\n > {\n if (options.gas) {\n debug(\"gas provided, skipping simulate\", functionName, args, options);\n return {\n address,\n abi,\n functionName,\n args,\n ...options,\n } as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;\n }\n\n debug(\"simulating write\", functionName, args, options);\n const { request } = await publicClient.simulateContract({\n address,\n abi,\n functionName,\n args,\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 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 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 }\n );\n }\n\n return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;\n}\n","import createDebug from \"debug\";\n\nexport const debug = createDebug(\"mud:common\");\n","import { BlockTag, Hex, PublicClient } 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 /already known|nonce too low/.test(String(error));\n }\n\n return {\n hasNonce,\n nextNonce,\n resetNonce,\n shouldResetNonce,\n };\n}\n","import { Hex, hexToString, sliceHex } from \"viem\";\n\nexport function hexToTableId(hex: Hex): { namespace: string; name: string } {\n const namespace = hexToString(sliceHex(hex, 0, 16)).replace(/\\0+$/, \"\");\n const name = hexToString(sliceHex(hex, 16, 32)).replace(/\\0+$/, \"\");\n return { namespace, name };\n}\n","import { Hex, stringToHex, concatHex } from \"viem\";\n\nexport function tableIdToHex(namespace: string, name: string): Hex {\n return concatHex([\n stringToHex(namespace.substring(0, 16), { size: 16 }),\n stringToHex(name.substring(0, 16), { size: 16 }),\n ]);\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","createDebug","debug","debug","createNonceManager","publicClient","address","blockTag","nonceRef","channel","event","nonce","hasNonce","nextNonce","resetNonce","shouldResetNonce","error","debug","getFunctionParameters","values","hasArgs","args","options","createContract","abi","address","publicClient","walletClient","contract","getContract","nonceManager","createNonceManager","_","functionName","parameters","prepareWrite","request","preparedWrite","pRetry","nonce","error","hexToString","sliceHex","hexToTableId","hex","namespace","name","stringToHex","concatHex","tableIdToHex","namespace","name","keccak256","debug","transportObserver","transport","opts","result","req","txs","data","keccak256"]}
1
+ {"version":3,"sources":["../src/createBurnerAccount.ts","../src/createContract.ts","../src/createNonceManager.ts","../src/debug.ts","../src/hexToTableId.ts","../src/tableIdToHex.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 { Hex, hexToString, sliceHex } from \"viem\";\n\nexport function hexToTableId(hex: Hex): { namespace: string; name: string } {\n const namespace = hexToString(sliceHex(hex, 0, 16)).replace(/\\0+$/, \"\");\n const name = hexToString(sliceHex(hex, 16, 32)).replace(/\\0+$/, \"\");\n return { namespace, name };\n}\n","import { Hex, stringToHex, concatHex } from \"viem\";\n\nexport function tableIdToHex(namespace: string, name: string): Hex {\n return concatHex([\n stringToHex(namespace.substring(0, 16), { size: 16 }),\n stringToHex(name.substring(0, 16), { size: 16 }),\n ]);\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","hexToString","sliceHex","hexToTableId","hex","namespace","name","stringToHex","concatHex","tableIdToHex","namespace","name","keccak256","debug","transportObserver","transport","opts","result","req","txs","data","keccak256"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/common",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.2",
4
4
  "description": "Common low level logic shared between packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -56,8 +56,8 @@
56
56
  "p-retry": "^5.1.2",
57
57
  "prettier": "^2.8.4",
58
58
  "prettier-plugin-solidity": "^1.1.2",
59
- "viem": "1.3.1",
60
- "@latticexyz/schema-type": "2.0.0-next.1"
59
+ "viem": "1.6.0",
60
+ "@latticexyz/schema-type": "2.0.0-next.2"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/debug": "^4.1.7",
@@ -3,5 +3,7 @@ import { MUDChain } from "./types";
3
3
 
4
4
  export const mudFoundry = {
5
5
  ...foundry,
6
- // We may override chain settings here
6
+ fees: {
7
+ defaultPriorityFee: 0n,
8
+ },
7
9
  } as const satisfies MUDChain;
@@ -5,6 +5,7 @@ import {
5
5
  Chain,
6
6
  GetContractParameters,
7
7
  GetContractReturnType,
8
+ Hex,
8
9
  PublicClient,
9
10
  SimulateContractParameters,
10
11
  Transport,
@@ -31,6 +32,24 @@ function getFunctionParameters(values: [args?: readonly unknown[], options?: obj
31
32
  return { args, options };
32
33
  }
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
+
34
53
  export function createContract<
35
54
  TTransport extends Transport,
36
55
  TAddress extends Address,
@@ -44,8 +63,15 @@ export function createContract<
44
63
  address,
45
64
  publicClient,
46
65
  walletClient,
47
- }: Required<
48
- GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>
66
+ onWrite,
67
+ }: CreateContractOptions<
68
+ TTransport,
69
+ TAddress,
70
+ TAbi,
71
+ TChain,
72
+ TAccount,
73
+ TPublicClient,
74
+ TWalletClient
49
75
  >): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {
50
76
  const contract = getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({
51
77
  abi,
@@ -55,6 +81,7 @@ export function createContract<
55
81
  }) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;
56
82
 
57
83
  if (contract.write) {
84
+ let nextWriteId = 0;
58
85
  const nonceManager = createNonceManager({
59
86
  publicClient: publicClient as PublicClient,
60
87
  address: walletClient.account.address,
@@ -65,55 +92,25 @@ export function createContract<
65
92
  {},
66
93
  {
67
94
  get(_, functionName: string): GetContractReturnType<Abi, PublicClient, WalletClient>["write"][string] {
68
- return async (...parameters) => {
69
- const { args, options } = <
70
- {
71
- args: unknown[];
72
- options: UnionOmit<WriteContractParameters, "abi" | "address" | "functionName" | "args">;
73
- }
74
- >getFunctionParameters(parameters as any);
75
-
76
- // Temporarily override base fee for our default anvil config
77
- // TODO: replace with https://github.com/wagmi-dev/viem/pull/1006 once merged
78
- // TODO: more specific mud foundry check? or can we safely assume anvil+mud will be block fee zero for now?
79
- if (
80
- walletClient.chain.id === 31337 &&
81
- options.maxFeePerGas == null &&
82
- options.maxPriorityFeePerGas == null
83
- ) {
84
- debug("assuming zero base fee for anvil chain");
85
- options.maxFeePerGas = 0n;
86
- options.maxPriorityFeePerGas = 0n;
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>;
87
101
  }
88
102
 
89
- async function prepareWrite(): Promise<
90
- WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>
91
- > {
92
- if (options.gas) {
93
- debug("gas provided, skipping simulate", functionName, args, options);
94
- return {
95
- address,
96
- abi,
97
- functionName,
98
- args,
99
- ...options,
100
- } as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;
101
- }
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>);
102
108
 
103
- debug("simulating write", functionName, args, options);
104
- const { request } = await publicClient.simulateContract({
105
- address,
106
- abi,
107
- functionName,
108
- args,
109
- ...options,
110
- account: options.account ?? walletClient.account,
111
- } as unknown as SimulateContractParameters<TAbi, typeof functionName, TChain>);
112
-
113
- return request as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;
114
- }
109
+ return request as unknown as WriteContractParameters<TAbi, typeof functionName, TChain, TAccount>;
110
+ }
115
111
 
116
- const preparedWrite = await prepareWrite();
112
+ async function write(options: WriteContractParameters): Promise<Hex> {
113
+ const preparedWrite = await prepareWrite(options);
117
114
 
118
115
  return await pRetry(
119
116
  async () => {
@@ -142,6 +139,30 @@ export function createContract<
142
139
  },
143
140
  }
144
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;
145
166
  };
146
167
  },
147
168
  }
@@ -1,4 +1,12 @@
1
- import { BlockTag, Hex, PublicClient } from "viem";
1
+ import {
2
+ BaseError,
3
+ BlockTag,
4
+ Hex,
5
+ NonceTooHighError,
6
+ NonceTooLowError,
7
+ PublicClient,
8
+ TransactionExecutionError,
9
+ } from "viem";
2
10
  import { debug as parentDebug } from "./debug";
3
11
 
4
12
  const debug = parentDebug.extend("createNonceManager");
@@ -55,7 +63,10 @@ export function createNonceManager({
55
63
  }
56
64
 
57
65
  function shouldResetNonce(error: unknown): boolean {
58
- return /already known|nonce too low/.test(String(error));
66
+ return (
67
+ error instanceof BaseError &&
68
+ error.walk((e) => e instanceof NonceTooLowError || e instanceof NonceTooHighError) != null
69
+ );
59
70
  }
60
71
 
61
72
  return {