-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(common,world): improvements for smart accounts #2578
Changes from 27 commits
460fdd1
88495c8
1709624
d37a14d
94121e1
7f628f1
95bed30
99f0930
44632c5
a8f2a37
1bfc017
4bc1630
660dee9
824ba9b
31272a1
4473d30
80222e3
eb3f978
53cc6ee
bc9f359
2636344
94705cd
ad194e2
769b695
d27f959
a513069
281dec8
26410cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
"@latticexyz/common": minor | ||
holic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
--- | ||
|
||
`transactionQueue` decorator now accepts an optional `publicClient` argument, which will be used in place of the extended viem client for making public action calls (`getChainId`, `getTransactionCount`, `simulateContract`, `call`). This helps in cases where the extended viem client is a smart account client, like in [permissionless.js](https://github.com/pimlicolabs/permissionless.js), where the transport is the bundler, not an RPC. | ||
|
||
`writeObserver` decorator now accepts any `Client`, not just a `WalletClient`. | ||
|
||
`createBurnerAccount` now returns a `PrivateKeyAccount`, the more specific `Account` type. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@latticexyz/world": patch | ||
--- | ||
|
||
`callFrom` decorator now accepts any `Client`, not just a `WalletClient`. It also no longer attempts to wrap/redirect calls to `call`, `callFrom`, and `registerDelegationWithSignature`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,20 @@ | ||
import type { Transport, Chain, Account, WalletActions, WalletClient } from "viem"; | ||
import type { Transport, Chain, Account, WalletActions, Client, PublicClient } from "viem"; | ||
import { writeContract as mud_writeContract } from "../writeContract"; | ||
import { sendTransaction as mud_sendTransaction } from "../sendTransaction"; | ||
|
||
export function transactionQueue<TChain extends Chain, TAccount extends Account>(): ( | ||
client: WalletClient<Transport, TChain, TAccount>, | ||
) => Pick<WalletActions<TChain, TAccount>, "writeContract" | "sendTransaction"> { | ||
export type TransactionQueueOptions<chain extends Chain> = { | ||
publicClient?: PublicClient<Transport, chain>; | ||
}; | ||
|
||
export function transactionQueue<chain extends Chain, account extends Account>({ | ||
publicClient, | ||
}: TransactionQueueOptions<chain> = {}): ( | ||
client: Client<Transport, chain, account>, | ||
) => Pick<WalletActions<chain, account>, "writeContract" | "sendTransaction"> { | ||
return (client) => ({ | ||
// Applies to: `client.writeContract`, `getContract(client, ...).write` | ||
writeContract: (args) => mud_writeContract(client, args), | ||
writeContract: (args) => mud_writeContract(client, args, publicClient), | ||
// Applies to: `client.sendTransaction` | ||
sendTransaction: (args) => mud_sendTransaction(client, args), | ||
sendTransaction: (args) => mud_sendTransaction(client, args, publicClient), | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { | |
WriteContractReturnType, | ||
ContractFunctionName, | ||
ContractFunctionArgs, | ||
PublicClient, | ||
} from "viem"; | ||
import { simulateContract, writeContract as viem_writeContract } from "viem/actions"; | ||
import pRetry from "p-retry"; | ||
|
@@ -31,6 +32,7 @@ export async function writeContract< | |
>( | ||
client: Client<Transport, chain, account>, | ||
request: WriteContractParameters<abi, functionName, args, chain, account, chainOverride>, | ||
publicClient?: PublicClient<Transport, chain>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this method is deprecated, so I didn't document this change in the changelog I also don't love this pattern of adding an extra param, ideally should be an object here for easier extending, but again, this is deprecated so will leave it be a future clean up should move this function inline into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. opened an issue for this so we can add it to the backlog: #2584 |
||
): Promise<WriteContractReturnType> { | ||
const rawAccount = request.account ?? client.account; | ||
if (!rawAccount) { | ||
|
@@ -40,7 +42,7 @@ export async function writeContract< | |
const account = parseAccount(rawAccount); | ||
|
||
const nonceManager = await getNonceManager({ | ||
client, | ||
client: publicClient ?? client, | ||
address: account.address, | ||
blockTag: "pending", | ||
}); | ||
|
@@ -54,11 +56,14 @@ export async function writeContract< | |
} | ||
|
||
debug("simulating", request.functionName, "at", request.address); | ||
const result = await simulateContract<chain, account, abi, functionName, args, chainOverride>(client, { | ||
...request, | ||
blockTag: "pending", | ||
account, | ||
} as unknown as SimulateContractParameters<abi, functionName, args, chain, chainOverride>); | ||
const result = await simulateContract<chain, account | undefined, abi, functionName, args, chainOverride>( | ||
publicClient ?? client, | ||
{ | ||
...request, | ||
blockTag: "pending", | ||
account, | ||
} as unknown as SimulateContractParameters<abi, functionName, args, chain, chainOverride>, | ||
); | ||
|
||
return result.request as unknown as WriteContractParameters<abi, functionName, args, chain, account, chainOverride>; | ||
} | ||
|
@@ -75,7 +80,10 @@ export async function writeContract< | |
|
||
const nonce = nonceManager.nextNonce(); | ||
debug("calling", preparedWrite.functionName, "with nonce", nonce, "at", preparedWrite.address); | ||
return await viem_writeContract(client, { nonce, ...preparedWrite } as typeof preparedWrite); | ||
return await viem_writeContract(client, { | ||
nonce, | ||
...preparedWrite, | ||
} as typeof preparedWrite); | ||
}, | ||
{ | ||
retries: 3, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
import { | ||
slice, | ||
concat, | ||
type WalletClient, | ||
type Transport, | ||
type Chain, | ||
type Account, | ||
|
@@ -10,6 +9,7 @@ import { | |
type WriteContractReturnType, | ||
type EncodeFunctionDataParameters, | ||
type PublicClient, | ||
Client, | ||
} from "viem"; | ||
import { getAction, encodeFunctionData } from "viem/utils"; | ||
import { writeContract } from "viem/actions"; | ||
|
@@ -52,12 +52,17 @@ type SystemFunction = { systemId: Hex; systemFunctionSelector: Hex }; | |
// The function mapping is cached to avoid redundant retrievals for the same World function. | ||
export function callFrom<TChain extends Chain, TAccount extends Account>( | ||
params: CallFromParameters, | ||
): (client: WalletClient<Transport, TChain, TAccount>) => Pick<WalletActions<TChain, TAccount>, "writeContract"> { | ||
): (client: Client<Transport, TChain, TAccount>) => Pick<WalletActions<TChain, TAccount>, "writeContract"> { | ||
return (client) => ({ | ||
// Applies to: `client.writeContract`, `getContract(client, ...).write` | ||
writeContract: async (writeArgs): Promise<WriteContractReturnType> => { | ||
// Skip if the contract isn't the World. | ||
if (writeArgs.address !== params.worldAddress) { | ||
// Skip if the contract isn't the World or the function called should not be redirected through `callFrom`. | ||
if ( | ||
writeArgs.address !== params.worldAddress || | ||
writeArgs.functionName === "call" || | ||
writeArgs.functionName === "callFrom" || | ||
writeArgs.functionName === "registerDelegationWithSignature" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make sense! Thanks. |
||
) { | ||
return getAction(client, writeContract, "writeContract")(writeArgs); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so according to semver, this should be
minor
because its an extra feature, not a fixbut maybe we don't want to trigger a bump to 2.1 yet?