@latticexyz/common 2.0.0-next.1 → 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 +1 -1
- package/dist/chains.js.map +1 -1
- package/dist/codegen.js +60 -18
- package/dist/codegen.js.map +1 -1
- package/dist/foundry.js +2 -2
- package/dist/foundry.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils.js +1 -1
- package/dist/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/chains/latticeTestnet.ts +0 -4
- package/src/chains/mudFoundry.ts +4 -1
- package/src/codegen/render-solidity/common.ts +38 -9
- package/src/codegen/render-solidity/renderTypeHelpers.ts +34 -3
- package/src/codegen/render-solidity/types.ts +1 -1
- package/src/codegen/utils/extractUserTypes.ts +57 -0
- package/src/codegen/utils/index.ts +2 -0
- package/src/codegen/utils/loadUserTypesFile.ts +71 -0
- package/src/common.ts +7 -0
- package/src/createContract.ts +3 -151
- package/src/createNonceManager.ts +28 -18
- package/src/foundry/index.ts +12 -0
- package/src/getBurnerPrivateKey.ts +26 -0
- package/src/getContract.ts +101 -0
- package/src/getNonceManager.ts +21 -0
- package/src/getNonceManagerId.ts +15 -0
- package/src/hexToResourceId.test.ts +11 -0
- package/src/hexToResourceId.ts +30 -0
- package/src/index.ts +14 -3
- package/src/readHex.test.ts +15 -0
- package/src/readHex.ts +15 -0
- package/src/resourceIdToHex.test.ts +69 -0
- package/src/resourceIdToHex.ts +23 -0
- package/src/resourceTypes.ts +3 -0
- package/src/spliceHex.ts +6 -0
- package/src/type-utils/common.ts +7 -0
- package/src/utils/identity.ts +3 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/iteratorToArray.ts +7 -0
- package/src/utils/wait.ts +1 -1
- package/src/utils/waitForIdle.ts +5 -0
- package/src/writeContract.ts +120 -0
- package/src/hexToTableId.test.ts +0 -10
- package/src/hexToTableId.ts +0 -7
- package/src/tableIdToHex.test.ts +0 -24
- package/src/tableIdToHex.ts +0 -8
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/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/dist/utils.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function
|
|
1
|
+
function n(r,e){throw new Error(e??`Unexpected value: ${r}`)}function i(...r){return r.reduce((e,t)=>t>e?t:e)}function u(...r){return r.reduce((e,t)=>t<e?t:e)}function m(r,e){return r<e?-1:r>e?1:0}function*x(r,e){for(let t=0;t<r.length;t+=e)yield r.slice(t,t+e)}function c(r,...e){return(...t)=>r(...e,...t)}function l(r){return r}function T(r){return r!==void 0}function g(r){return r!==null}async function v(r){let e=[];for await(let t of r)e.push(t);return e}function F(r){return new Promise(e=>setTimeout(()=>e(),r))}function h(){return new Promise(r=>{requestIdleCallback(()=>r())})}export{n as assertExhaustive,i as bigIntMax,u as bigIntMin,m as bigIntSort,x as chunk,c as curry,l as identity,T as isDefined,g as isNotNull,v as iteratorToArray,F as wait,h as waitForIdle};
|
|
2
2
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/assertExhaustive.ts","../src/utils/bigIntMax.ts","../src/utils/bigIntMin.ts","../src/utils/bigIntSort.ts","../src/utils/chunk.ts","../src/utils/curry.ts","../src/utils/isDefined.ts","../src/utils/isNotNull.ts","../src/utils/wait.ts"],"sourcesContent":["export function assertExhaustive(value: never, message?: string): never {\n throw new Error(message ?? `Unexpected value: ${value}`);\n}\n","export function bigIntMax(...args: bigint[]): bigint {\n return args.reduce((m, e) => (e > m ? e : m));\n}\n","export function bigIntMin(...args: bigint[]): bigint {\n return args.reduce((m, e) => (e < m ? e : m));\n}\n","export function bigIntSort(a: bigint, b: bigint): -1 | 0 | 1 {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n","export function* chunk<T>(arr: T[], n: number): Generator<T[], void> {\n for (let i = 0; i < arr.length; i += n) {\n yield arr.slice(i, i + n);\n }\n}\n","export function curry<F extends (...params: [...P, ...any[]]) => any, P extends any[]>(\n func: F,\n ...partialParams: P\n): CurryParams<F, P> {\n return ((...args: any[]) => func(...partialParams, ...args)) as CurryParams<F, P>;\n}\n\ntype CurryParams<F extends (...params: [...PartialParams, ...any[]]) => any, PartialParams extends any[]> = F extends (\n ...params: [...PartialParams, ...infer RemainingParams]\n) => infer Result\n ? (...params: RemainingParams) => Result\n : never;\n","export function isDefined<T>(argument: T | undefined): argument is T {\n return argument !== undefined;\n}\n","export function isNotNull<T>(argument: T | null): argument is T {\n return argument !== null;\n}\n","export function wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"mappings":"AAAO,SAASA,EAAiBC,EAAcC,EAAyB,CACtE,MAAM,IAAI,MAAMA,GAAW,qBAAqBD,GAAO,CACzD,CCFO,SAASE,KAAaC,EAAwB,CACnD,OAAOA,EAAK,OAAO,CAACC,EAAGC,IAAOA,EAAID,EAAIC,EAAID,CAAE,CAC9C,CCFO,SAASE,KAAaC,EAAwB,CACnD,OAAOA,EAAK,OAAO,CAACC,EAAGC,IAAOA,EAAID,EAAIC,EAAID,CAAE,CAC9C,CCFO,SAASE,EAAWC,EAAWC,EAAuB,CAC3D,OAAOD,EAAIC,EAAI,GAAKD,EAAIC,EAAI,EAAI,CAClC,CCFO,SAAUC,EAASC,EAAUC,EAAiC,CACnE,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,GAAKD,EACnC,MAAMD,EAAI,MAAME,EAAGA,EAAID,CAAC,CAE5B,CCJO,SAASE,EACdC,KACGC,EACgB,CACnB,MAAQ,IAAIC,IAAgBF,EAAK,GAAGC,EAAe,GAAGC,CAAI,CAC5D,CCLO,SAASC,EAAaC,EAAwC,CACnE,OAAOA,IAAa,MACtB,CCFO,SAASC,EAAaC,EAAmC,CAC9D,OAAOA,IAAa,IACtB,
|
|
1
|
+
{"version":3,"sources":["../src/utils/assertExhaustive.ts","../src/utils/bigIntMax.ts","../src/utils/bigIntMin.ts","../src/utils/bigIntSort.ts","../src/utils/chunk.ts","../src/utils/curry.ts","../src/utils/identity.ts","../src/utils/isDefined.ts","../src/utils/isNotNull.ts","../src/utils/iteratorToArray.ts","../src/utils/wait.ts","../src/utils/waitForIdle.ts"],"sourcesContent":["export function assertExhaustive(value: never, message?: string): never {\n throw new Error(message ?? `Unexpected value: ${value}`);\n}\n","export function bigIntMax(...args: bigint[]): bigint {\n return args.reduce((m, e) => (e > m ? e : m));\n}\n","export function bigIntMin(...args: bigint[]): bigint {\n return args.reduce((m, e) => (e < m ? e : m));\n}\n","export function bigIntSort(a: bigint, b: bigint): -1 | 0 | 1 {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n","export function* chunk<T>(arr: T[], n: number): Generator<T[], void> {\n for (let i = 0; i < arr.length; i += n) {\n yield arr.slice(i, i + n);\n }\n}\n","export function curry<F extends (...params: [...P, ...any[]]) => any, P extends any[]>(\n func: F,\n ...partialParams: P\n): CurryParams<F, P> {\n return ((...args: any[]) => func(...partialParams, ...args)) as CurryParams<F, P>;\n}\n\ntype CurryParams<F extends (...params: [...PartialParams, ...any[]]) => any, PartialParams extends any[]> = F extends (\n ...params: [...PartialParams, ...infer RemainingParams]\n) => infer Result\n ? (...params: RemainingParams) => Result\n : never;\n","export function identity<T>(value: T): T {\n return value;\n}\n","export function isDefined<T>(argument: T | undefined): argument is T {\n return argument !== undefined;\n}\n","export function isNotNull<T>(argument: T | null): argument is T {\n return argument !== null;\n}\n","export async function iteratorToArray<T>(iterator: AsyncIterable<T>): Promise<T[]> {\n const items: T[] = [];\n for await (const item of iterator) {\n items.push(item);\n }\n return items;\n}\n","export function wait(ms: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(() => resolve(), ms));\n}\n","export function waitForIdle(): Promise<void> {\n return new Promise<void>((resolve) => {\n requestIdleCallback(() => resolve());\n });\n}\n"],"mappings":"AAAO,SAASA,EAAiBC,EAAcC,EAAyB,CACtE,MAAM,IAAI,MAAMA,GAAW,qBAAqBD,GAAO,CACzD,CCFO,SAASE,KAAaC,EAAwB,CACnD,OAAOA,EAAK,OAAO,CAACC,EAAGC,IAAOA,EAAID,EAAIC,EAAID,CAAE,CAC9C,CCFO,SAASE,KAAaC,EAAwB,CACnD,OAAOA,EAAK,OAAO,CAACC,EAAGC,IAAOA,EAAID,EAAIC,EAAID,CAAE,CAC9C,CCFO,SAASE,EAAWC,EAAWC,EAAuB,CAC3D,OAAOD,EAAIC,EAAI,GAAKD,EAAIC,EAAI,EAAI,CAClC,CCFO,SAAUC,EAASC,EAAUC,EAAiC,CACnE,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,GAAKD,EACnC,MAAMD,EAAI,MAAME,EAAGA,EAAID,CAAC,CAE5B,CCJO,SAASE,EACdC,KACGC,EACgB,CACnB,MAAQ,IAAIC,IAAgBF,EAAK,GAAGC,EAAe,GAAGC,CAAI,CAC5D,CCLO,SAASC,EAAYC,EAAa,CACvC,OAAOA,CACT,CCFO,SAASC,EAAaC,EAAwC,CACnE,OAAOA,IAAa,MACtB,CCFO,SAASC,EAAaC,EAAmC,CAC9D,OAAOA,IAAa,IACtB,CCFA,eAAsBC,EAAmBC,EAA0C,CACjF,IAAMC,EAAa,CAAC,EACpB,cAAiBC,KAAQF,EACvBC,EAAM,KAAKC,CAAI,EAEjB,OAAOD,CACT,CCNO,SAASE,EAAKC,EAA2B,CAC9C,OAAO,IAAI,QAAeC,GAAY,WAAW,IAAMA,EAAQ,EAAGD,CAAE,CAAC,CACvE,CCFO,SAASE,GAA6B,CAC3C,OAAO,IAAI,QAAeC,GAAY,CACpC,oBAAoB,IAAMA,EAAQ,CAAC,CACrC,CAAC,CACH","names":["assertExhaustive","value","message","bigIntMax","args","m","e","bigIntMin","args","m","e","bigIntSort","a","b","chunk","arr","n","i","curry","func","partialParams","args","identity","value","isDefined","argument","isNotNull","argument","iteratorToArray","iterator","items","item","wait","ms","resolve","waitForIdle","resolve"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@latticexyz/common",
|
|
3
|
-
"version": "2.0.0-next.
|
|
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.
|
|
60
|
-
"@latticexyz/schema-type": "2.0.0-next.
|
|
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",
|
|
@@ -72,6 +71,7 @@
|
|
|
72
71
|
"clean": "pnpm run clean:js",
|
|
73
72
|
"clean:js": "rimraf dist",
|
|
74
73
|
"dev": "tsup --watch",
|
|
75
|
-
"test": "vitest typecheck --run --passWithNoTests && vitest --run"
|
|
74
|
+
"test": "vitest typecheck --run --passWithNoTests && vitest --run",
|
|
75
|
+
"test:ci": "pnpm run test"
|
|
76
76
|
}
|
|
77
77
|
}
|
package/src/chains/mudFoundry.ts
CHANGED
|
@@ -3,5 +3,8 @@ import { MUDChain } from "./types";
|
|
|
3
3
|
|
|
4
4
|
export const mudFoundry = {
|
|
5
5
|
...foundry,
|
|
6
|
-
|
|
6
|
+
fees: {
|
|
7
|
+
// This is intentionally defined as a function as a workaround for https://github.com/wagmi-dev/viem/pull/1280
|
|
8
|
+
defaultPriorityFee: () => 0n,
|
|
9
|
+
},
|
|
7
10
|
} as const satisfies MUDChain;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { posixPath } from "../utils";
|
|
11
11
|
|
|
12
12
|
export const renderedSolidityHeader = `// SPDX-License-Identifier: MIT
|
|
13
|
-
pragma solidity >=0.8.
|
|
13
|
+
pragma solidity >=0.8.21;
|
|
14
14
|
|
|
15
15
|
/* Autogenerated file. Do not edit manually. */`;
|
|
16
16
|
|
|
@@ -44,7 +44,7 @@ export function renderCommonData({
|
|
|
44
44
|
} {
|
|
45
45
|
// static resource means static tableId as well, and no tableId arguments
|
|
46
46
|
const _tableId = staticResourceData ? "" : "_tableId";
|
|
47
|
-
const _typedTableId = staticResourceData ? "" : "
|
|
47
|
+
const _typedTableId = staticResourceData ? "" : "ResourceId _tableId";
|
|
48
48
|
|
|
49
49
|
const _keyArgs = renderArguments(keyTuple.map(({ name }) => name));
|
|
50
50
|
const _typedKeyArgs = renderArguments(keyTuple.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
|
|
@@ -131,28 +131,57 @@ export function renderWithStore(
|
|
|
131
131
|
_typedStore: string | undefined,
|
|
132
132
|
_store: string,
|
|
133
133
|
_commentSuffix: string,
|
|
134
|
-
_untypedStore: string | undefined
|
|
134
|
+
_untypedStore: string | undefined,
|
|
135
|
+
_methodPrefix: string,
|
|
136
|
+
_internal?: boolean
|
|
135
137
|
) => string
|
|
136
138
|
): string {
|
|
137
139
|
let result = "";
|
|
138
|
-
result += callback(undefined, "StoreSwitch", "", undefined);
|
|
140
|
+
result += callback(undefined, "StoreSwitch", "", undefined, "");
|
|
141
|
+
result += callback(undefined, "StoreCore", "", undefined, "_", true);
|
|
139
142
|
|
|
140
143
|
if (storeArgument) {
|
|
141
|
-
result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store");
|
|
144
|
+
result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store", "");
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
return result;
|
|
145
148
|
}
|
|
146
149
|
|
|
147
|
-
export function
|
|
150
|
+
export function renderWithFieldSuffix(
|
|
151
|
+
withSuffixlessFieldMethods: boolean,
|
|
152
|
+
fieldName: string,
|
|
153
|
+
callback: (_methodNameSuffix: string) => string
|
|
154
|
+
): string {
|
|
155
|
+
const methodNameSuffix = `${fieldName[0].toUpperCase()}${fieldName.slice(1)}`;
|
|
156
|
+
let result = "";
|
|
157
|
+
result += callback(methodNameSuffix);
|
|
158
|
+
|
|
159
|
+
if (withSuffixlessFieldMethods) {
|
|
160
|
+
result += "\n" + callback("");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function renderTableId({ namespace, name, offchainOnly, tableIdName }: StaticResourceData): {
|
|
148
167
|
hardcodedTableId: string;
|
|
149
168
|
tableIdDefinition: string;
|
|
150
169
|
} {
|
|
151
|
-
const hardcodedTableId = `
|
|
170
|
+
const hardcodedTableId = `
|
|
171
|
+
ResourceId.wrap(
|
|
172
|
+
bytes32(
|
|
173
|
+
abi.encodePacked(
|
|
174
|
+
${offchainOnly ? "RESOURCE_OFFCHAIN_TABLE" : "RESOURCE_TABLE"},
|
|
175
|
+
bytes14("${namespace}"),
|
|
176
|
+
bytes16("${name}")
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
`;
|
|
152
181
|
|
|
153
182
|
const tableIdDefinition = `
|
|
154
|
-
|
|
155
|
-
|
|
183
|
+
ResourceId constant _tableId = ${hardcodedTableId};
|
|
184
|
+
ResourceId constant ${tableIdName} = _tableId;
|
|
156
185
|
`;
|
|
157
186
|
return {
|
|
158
187
|
hardcodedTableId,
|
|
@@ -12,6 +12,12 @@ export function renderTypeHelpers(options: { fields: RenderField[]; keyTuple: Re
|
|
|
12
12
|
// bool is special - it's the only primitive value type that can't be typecasted to/from
|
|
13
13
|
if (fields.some(({ internalTypeId }) => internalTypeId.match("bool"))) {
|
|
14
14
|
result += `
|
|
15
|
+
/**
|
|
16
|
+
* @notice Cast a value to a bool.
|
|
17
|
+
* @dev Boolean values are encoded as uint8 (1 = true, 0 = false), but Solidity doesn't allow casting between uint8 and bool.
|
|
18
|
+
* @param value The uint8 value to convert.
|
|
19
|
+
* @return result The boolean value.
|
|
20
|
+
*/
|
|
15
21
|
function _toBool(uint8 value) pure returns (bool result) {
|
|
16
22
|
assembly {
|
|
17
23
|
result := value
|
|
@@ -21,6 +27,10 @@ export function renderTypeHelpers(options: { fields: RenderField[]; keyTuple: Re
|
|
|
21
27
|
}
|
|
22
28
|
if (keyTuple.some(({ internalTypeId }) => internalTypeId.match("bool"))) {
|
|
23
29
|
result += `
|
|
30
|
+
/**
|
|
31
|
+
* @notice Cast a bool to a bytes32.
|
|
32
|
+
* @dev The boolean value is casted to a bytes32 value with 0 or 1 at the least significant bit.
|
|
33
|
+
*/
|
|
24
34
|
function _boolToBytes32(bool value) pure returns (bytes32 result) {
|
|
25
35
|
assembly {
|
|
26
36
|
result := value
|
|
@@ -58,14 +68,29 @@ function renderWrapperStaticArray(
|
|
|
58
68
|
// WARNING: ensure this still works if changing major solidity versions!
|
|
59
69
|
// (the memory layout for static arrays may change)
|
|
60
70
|
return `
|
|
71
|
+
/**
|
|
72
|
+
* @notice Cast a dynamic array to a static array.
|
|
73
|
+
* @dev In memory static arrays are just dynamic arrays without the 32 length bytes,
|
|
74
|
+
* so this function moves the pointer to the first element of the dynamic array.
|
|
75
|
+
* If the length of the dynamic array is smaller than the static length,
|
|
76
|
+
* the function returns an uninitialized array to avoid memory corruption.
|
|
77
|
+
* @param _value The dynamic array to cast.
|
|
78
|
+
* @return _result The static array.
|
|
79
|
+
*/
|
|
61
80
|
function ${functionName}(
|
|
62
81
|
${internalTypeId} memory _value
|
|
63
82
|
) pure returns (
|
|
64
83
|
${elementType}[${staticLength}] memory _result
|
|
65
84
|
) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
_result
|
|
85
|
+
if (_value.length < ${staticLength}) {
|
|
86
|
+
// return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption
|
|
87
|
+
return _result;
|
|
88
|
+
} else {
|
|
89
|
+
// in memory static arrays are just dynamic arrays without the 32 length bytes
|
|
90
|
+
// (without the length check this could lead to memory corruption)
|
|
91
|
+
assembly {
|
|
92
|
+
_result := add(_value, 0x20)
|
|
93
|
+
}
|
|
69
94
|
}
|
|
70
95
|
}
|
|
71
96
|
`;
|
|
@@ -81,6 +106,12 @@ function renderUnwrapperStaticArray(
|
|
|
81
106
|
const byteLength = staticLength * 32;
|
|
82
107
|
// TODO to optimize memory usage consider generalizing TightEncoder to a render-time utility
|
|
83
108
|
return `
|
|
109
|
+
/**
|
|
110
|
+
* @notice Copy a static array to a dynamic array.
|
|
111
|
+
* @dev Static arrays don't have a length prefix, so this function copies the memory from the static array to a new dynamic array.
|
|
112
|
+
* @param _value The static array to copy.
|
|
113
|
+
* @return _result The dynamic array.
|
|
114
|
+
*/
|
|
84
115
|
function ${functionName}(
|
|
85
116
|
${elementType}[${staticLength}] memory _value
|
|
86
117
|
) pure returns (
|
|
@@ -16,6 +16,7 @@ export interface StaticResourceData {
|
|
|
16
16
|
tableIdName: string;
|
|
17
17
|
namespace: string;
|
|
18
18
|
name: string;
|
|
19
|
+
offchainOnly: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export interface RenderType {
|
|
@@ -43,7 +44,6 @@ export interface RenderKeyTuple extends RenderType {
|
|
|
43
44
|
export interface RenderField extends RenderType {
|
|
44
45
|
arrayElement: RenderType | undefined;
|
|
45
46
|
name: string;
|
|
46
|
-
methodNameSuffix: string;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export interface RenderStaticField extends RenderField {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { parse, visit } from "@solidity-parser/parser";
|
|
2
|
+
import { MUDError } from "../../errors";
|
|
3
|
+
|
|
4
|
+
export interface SolidityUserDefinedType {
|
|
5
|
+
typeId: string;
|
|
6
|
+
internalTypeId: string;
|
|
7
|
+
importSymbol: string;
|
|
8
|
+
fromPath: string;
|
|
9
|
+
isRelativePath: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse the solidity data to extract user-defined type information.
|
|
14
|
+
* @param data contents of a solidity file with the user types declarations
|
|
15
|
+
* @param userTypeNames names of the user types to extract
|
|
16
|
+
*/
|
|
17
|
+
export function extractUserTypes(
|
|
18
|
+
data: string,
|
|
19
|
+
userTypeNames: string[],
|
|
20
|
+
fromPath: string
|
|
21
|
+
): Record<string, SolidityUserDefinedType> {
|
|
22
|
+
const ast = parse(data);
|
|
23
|
+
|
|
24
|
+
const isRelativePath = fromPath.at(0) === ".";
|
|
25
|
+
const userDefinedTypes: Record<string, SolidityUserDefinedType> = {};
|
|
26
|
+
|
|
27
|
+
visit(ast, {
|
|
28
|
+
TypeDefinition({ name, definition }, parent) {
|
|
29
|
+
if (definition.name.includes("fixed")) throw new MUDError(`Fixed point numbers are not supported by MUD`);
|
|
30
|
+
if (userTypeNames.includes(name)) {
|
|
31
|
+
if (name in userDefinedTypes) {
|
|
32
|
+
throw new MUDError(`File has multiple user types with the same name: ${name}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (parent?.type === "ContractDefinition") {
|
|
36
|
+
userDefinedTypes[name] = {
|
|
37
|
+
typeId: `${parent.name}.${name}`,
|
|
38
|
+
internalTypeId: definition.name,
|
|
39
|
+
importSymbol: parent.name,
|
|
40
|
+
fromPath,
|
|
41
|
+
isRelativePath,
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
userDefinedTypes[name] = {
|
|
45
|
+
typeId: name,
|
|
46
|
+
internalTypeId: definition.name,
|
|
47
|
+
importSymbol: name,
|
|
48
|
+
fromPath,
|
|
49
|
+
isRelativePath,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return userDefinedTypes;
|
|
57
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { SolidityUserDefinedType, extractUserTypes } from "./extractUserTypes";
|
|
4
|
+
import { MUDError } from "../../errors";
|
|
5
|
+
|
|
6
|
+
export type UserType = {
|
|
7
|
+
filePath: string;
|
|
8
|
+
internalType: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function loadAndExtractUserTypes(
|
|
12
|
+
userTypes: Record<string, UserType>,
|
|
13
|
+
outputBaseDirectory: string,
|
|
14
|
+
remappings: [string, string][]
|
|
15
|
+
): Record<string, SolidityUserDefinedType> {
|
|
16
|
+
const userTypesPerFile: Record<string, string[]> = {};
|
|
17
|
+
for (const [userTypeName, { filePath: unresolvedFilePath }] of Object.entries(userTypes)) {
|
|
18
|
+
if (!(unresolvedFilePath in userTypesPerFile)) {
|
|
19
|
+
userTypesPerFile[unresolvedFilePath] = [];
|
|
20
|
+
}
|
|
21
|
+
userTypesPerFile[unresolvedFilePath].push(userTypeName);
|
|
22
|
+
}
|
|
23
|
+
let extractedUserTypes: Record<string, SolidityUserDefinedType> = {};
|
|
24
|
+
for (const [unresolvedFilePath, userTypeNames] of Object.entries(userTypesPerFile)) {
|
|
25
|
+
const { filePath, data } = loadUserTypesFile(outputBaseDirectory, unresolvedFilePath, remappings);
|
|
26
|
+
const userTypesInFile = extractUserTypes(data, userTypeNames, filePath);
|
|
27
|
+
|
|
28
|
+
// Verify the actual user type matches the internalType specified in the config
|
|
29
|
+
for (const [userTypeName, userType] of Object.entries(userTypesInFile)) {
|
|
30
|
+
if (userType.internalTypeId !== userTypes[userTypeName].internalType) {
|
|
31
|
+
throw new MUDError(
|
|
32
|
+
`User type "${userTypeName}" has internal type "${userType.internalTypeId}" but config specifies "${userTypes[userTypeName].internalType}"`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
extractedUserTypes = Object.assign(extractedUserTypes, userTypesInFile);
|
|
38
|
+
}
|
|
39
|
+
return extractedUserTypes;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadUserTypesFile(
|
|
43
|
+
outputBaseDirectory: string,
|
|
44
|
+
unresolvedFilePath: string,
|
|
45
|
+
remappings: [string, string][]
|
|
46
|
+
): {
|
|
47
|
+
filePath: string;
|
|
48
|
+
data: string;
|
|
49
|
+
} {
|
|
50
|
+
if (unresolvedFilePath.at(0) === ".") {
|
|
51
|
+
const relativePath = path.relative(outputBaseDirectory, unresolvedFilePath);
|
|
52
|
+
return {
|
|
53
|
+
filePath: "./" + relativePath, // solc doesn't like relative paths without "./"
|
|
54
|
+
data: readFileSync(unresolvedFilePath, "utf8"),
|
|
55
|
+
};
|
|
56
|
+
} else {
|
|
57
|
+
// apply remappings to read the file via node
|
|
58
|
+
let remappedFilePath = unresolvedFilePath;
|
|
59
|
+
for (const [from, to] of remappings) {
|
|
60
|
+
if (remappedFilePath.includes(from)) {
|
|
61
|
+
remappedFilePath = remappedFilePath.replace(from, to);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
filePath: unresolvedFilePath,
|
|
68
|
+
data: readFileSync(remappedFilePath, "utf8"),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/common.ts
ADDED
package/src/createContract.ts
CHANGED
|
@@ -1,152 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Abi,
|
|
3
|
-
Account,
|
|
4
|
-
Address,
|
|
5
|
-
Chain,
|
|
6
|
-
GetContractParameters,
|
|
7
|
-
GetContractReturnType,
|
|
8
|
-
PublicClient,
|
|
9
|
-
SimulateContractParameters,
|
|
10
|
-
Transport,
|
|
11
|
-
WalletClient,
|
|
12
|
-
WriteContractParameters,
|
|
13
|
-
getContract,
|
|
14
|
-
} from "viem";
|
|
15
|
-
import pRetry from "p-retry";
|
|
16
|
-
import { createNonceManager } from "./createNonceManager";
|
|
17
|
-
import { debug as parentDebug } from "./debug";
|
|
18
|
-
import { UnionOmit } from "./type-utils/common";
|
|
1
|
+
import { getContract } from "./getContract";
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// copied from viem because this isn't exported
|
|
23
|
-
// TODO: import from viem?
|
|
24
|
-
function getFunctionParameters(values: [args?: readonly unknown[], options?: object]): {
|
|
25
|
-
args: readonly unknown[];
|
|
26
|
-
options: object;
|
|
27
|
-
} {
|
|
28
|
-
const hasArgs = values.length && Array.isArray(values[0]);
|
|
29
|
-
const args = hasArgs ? values[0]! : [];
|
|
30
|
-
const options = (hasArgs ? values[1] : values[0]) ?? {};
|
|
31
|
-
return { args, options };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function createContract<
|
|
35
|
-
TTransport extends Transport,
|
|
36
|
-
TAddress extends Address,
|
|
37
|
-
TAbi extends Abi,
|
|
38
|
-
TChain extends Chain,
|
|
39
|
-
TAccount extends Account,
|
|
40
|
-
TPublicClient extends PublicClient<TTransport, TChain>,
|
|
41
|
-
TWalletClient extends WalletClient<TTransport, TChain, TAccount>
|
|
42
|
-
>({
|
|
43
|
-
abi,
|
|
44
|
-
address,
|
|
45
|
-
publicClient,
|
|
46
|
-
walletClient,
|
|
47
|
-
}: Required<
|
|
48
|
-
GetContractParameters<TTransport, TChain, TAccount, TAbi, TPublicClient, TWalletClient, TAddress>
|
|
49
|
-
>): GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress> {
|
|
50
|
-
const contract = getContract<TTransport, TAddress, TAbi, TChain, TAccount, TPublicClient, TWalletClient>({
|
|
51
|
-
abi,
|
|
52
|
-
address,
|
|
53
|
-
publicClient,
|
|
54
|
-
walletClient,
|
|
55
|
-
}) as unknown as GetContractReturnType<Abi, PublicClient, WalletClient>;
|
|
56
|
-
|
|
57
|
-
if (contract.write) {
|
|
58
|
-
const nonceManager = createNonceManager({
|
|
59
|
-
publicClient: publicClient as PublicClient,
|
|
60
|
-
address: walletClient.account.address,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Replace write calls with our own proxy. Implemented ~the same as viem, but adds better handling of nonces (via queue + retries).
|
|
64
|
-
contract.write = new Proxy(
|
|
65
|
-
{},
|
|
66
|
-
{
|
|
67
|
-
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;
|
|
87
|
-
}
|
|
88
|
-
|
|
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
|
-
}
|
|
102
|
-
|
|
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
|
-
}
|
|
115
|
-
|
|
116
|
-
const preparedWrite = await prepareWrite();
|
|
117
|
-
|
|
118
|
-
return await pRetry(
|
|
119
|
-
async () => {
|
|
120
|
-
if (!nonceManager.hasNonce()) {
|
|
121
|
-
await nonceManager.resetNonce();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const nonce = nonceManager.nextNonce();
|
|
125
|
-
debug("calling write function with nonce", nonce, preparedWrite);
|
|
126
|
-
return await walletClient.writeContract({
|
|
127
|
-
nonce,
|
|
128
|
-
...preparedWrite,
|
|
129
|
-
});
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
retries: 3,
|
|
133
|
-
onFailedAttempt: async (error) => {
|
|
134
|
-
// On nonce errors, reset the nonce and retry
|
|
135
|
-
if (nonceManager.shouldResetNonce(error)) {
|
|
136
|
-
debug("got nonce error, retrying", error);
|
|
137
|
-
await nonceManager.resetNonce();
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// TODO: prepareWrite again if there are gas errors?
|
|
141
|
-
throw error;
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
};
|
|
146
|
-
},
|
|
147
|
-
}
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return contract as unknown as GetContractReturnType<TAbi, TPublicClient, TWalletClient, TAddress>;
|
|
152
|
-
}
|
|
3
|
+
/** @deprecated use `getContract` instead */
|
|
4
|
+
export const createContract = getContract;
|