Skip to content
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

📝 Docs: Update memoryClient jsdoc #1234

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-zoos-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tevm/memory-client": patch
---

Add more jsdoc to MemoryClient docs
15 changes: 14 additions & 1 deletion packages/memory-client/src/MemoryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { TevmActions } from './TevmActions.js'

/**
* A local EVM instance running in JavaScript. Similar to Anvil in your browser/node/bun environments
* It wraps the viem [public client](https://viem.sh/docs/clients/public#public-client) and [test client](https://viem.sh/docs/clients/test)
* It wraps the viem [public client](https://viem.sh/docs/clients/public#public-client)
*
* @see {@link TevmClient}
* @see {@link https://todo.todo WrappedEvm} for an remote client
Expand Down Expand Up @@ -36,6 +36,19 @@ import type { TevmActions } from './TevmActions.js'
* )
* console.log(balance) // 1n
* ```
*
* Test actions can be added with `client.extend`
*
* ```ts
* import {testActions} from 'viem'
*
* const tevm = createMemoryClient().extend(testActions({mode: 'anvil'}))
*
* tevm.setBytecode({
* address: `0x${'0'.repeat(40)}`,
* bytecode: '0x608060405234801561001057600080fd5b5060405',
* })
* ```
*/
export type MemoryClient = Prettify<
Client<
Expand Down
223 changes: 221 additions & 2 deletions packages/memory-client/src/TevmActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,245 @@ import type { BaseClient } from '@tevm/base-client'
import { type EIP1193RequestFn, type Eip1193RequestProvider, type TevmActionsApi } from '@tevm/decorators'
import type { TevmJsonRpcBulkRequestHandler, TevmJsonRpcRequestHandler } from '@tevm/procedures'

/**
* Powerful actions for interacting with the EVM
*/
export type TevmActions = {
/**
* Low level access to tevm can be accessed via `tevm_tevm`. These apis are not guaranteed to be stable
* @see {@link BaseClient}
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const memoryClient = createMemoryClient()
*
* // low level access to the tevm vm, blockchain, evm, stateManager, mempool, receiptsManager and more are available
* const vm = await memoryClient._tevm.getVm()
* vm.runBlocl(...)
* const {blockchain, evm, stateManager} = vm
* blockchain.addBlock(...)
* evm.runCall(...)
* stateManager.putAccount(...)
*
* const mempool = await memoryClient._tevm.getTxPool()
* const receiptsManager = await memoryClient._tevm.getReceiptsManager()
* ````
*/
_tevm: BaseClient &
Eip1193RequestProvider &
TevmActionsApi & {
send: TevmJsonRpcRequestHandler
sendBulk: TevmJsonRpcBulkRequestHandler
request: EIP1193RequestFn
}
tevmForkUrl?: string
/**
* Returns a promise that resolves when the tevm is ready
* This is not needed to explicitly be called as all actions will wait for the tevm to be ready
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* await client.tevmReady()
* ```
* Same as calling `client._tevm.ready()`
*/
tevmReady: () => Promise<true>
/**
* A powerful low level api for executing calls and sending transactions
* See [CallParams](https://tevm.sh/reference/tevm/actions/type-aliases/callparams/) for options reference
* See [CallResult](https://tevm.sh/reference/tevm/precompiles/type-aliases/callresult/) for return values reference
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise it will be a call`. You must also mine the transaction
* before it updates the cannonical head state.` This can be avoided by setting mining mode to `auto` when using createMemoryClient`
* @example
* ```typescript`
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from 'tevm/contract'
*
* const client = createMemoryClient()
*
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
*
* await client.setAccount(token)
*
* const balance = await client.tevmCall({
* to: token.address,
* data: encodeFunctionData(token.read.balanceOf, [token.address]),
* })
* ```
* In addiiton to making basic call, you can also do advanced things like
* - impersonate accounts via passing in `from`, `caller`, or `origin`
* - set the call depth via `depth`
* - Create a trace or access list using `createTrace: true` or `createAccessList: true`
* - send as a transaction with `createTransaction: true`
* For all options see [CallParams](https://tevm.sh/reference/tevm/actions/type-aliases/callparams/)
* Same as calling `client._tevm.call`
* `
*/
tevmCall: TevmActionsApi['call']
/**
* A powerful low level api for calling contracts. Similar to `tevmCall` but takes care of encoding and decoding data, revert messages, etc.
* See [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/) for options reference]
* See [ContractResult](https://tevm.sh/reference/tevm/actions/type-aliases/contractresult/) for return values reference
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise it will be a call`. You must also mine the transaction
* before it updates the cannonical head state.` This can be avoided by setting mining mode to `auto` when using createMemoryClient`
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from './MyERC721.sol'
*
* const client = createMemoryClient()
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
* await client.setAccount(token)
* const balance = await client.tevmContract({
* contract: token,
* method: token.read.balanceOf,
* args: [token.address],
* })
* ```
* In addiiton to making basic call, you can also do advanced things like
* - impersonate accounts via passing in `from`, `caller`, or `origin`
* - set the call depth via `depth`
* - Create a trace or access list using `createTrace: true` or `createAccessList: true`
* - send as a transaction with `createTransaction: true`
* For all options see [ContractParams](https://tevm.sh/reference/tevm/actions/type-aliases/contractparams/)
*/
tevmContract: TevmActionsApi['contract']
/**
* @deprecated in favor of tevmContract
* @deprecated in favor of tevmContract. To migrate simply replace `tevmScript` with `tevmContract` as the api is supported and more
* tevmContract also now supports deploying contracts with constructor arguments too via `params.code`. TevmScript previously did not support this
* and only supported deployedBytecode with no constructor arguments. tevmContract supports using deployedBytecode as waell.
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise it will be a call`. You must also mine the transaction
* before it updates the cannonical head state.` This can be avoided by setting mining mode to `auto` when using createMemoryClient`
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'`
* import { ERC20 } from './MyERC721.sol'
*
* const client = createMemoryClient()
*
* const balance = await client.tevmContract({
* createTransaction: true,
* deployedBytecode: ERC20.deployedBytecode,
* abi: ERC20.abi,
* method: 'mint',
* args: [client.address, 1n],
* })
* ```
* Same as calling `client._tevm.script`
* `
*/
tevmScript: TevmActionsApi['script']
/**
* Deploys a contract to the EVM with encoded constructor arguments. Extends `tevmCall` so it supports all advanced options
* @see [DeployParams](https://tevm.sh/reference/tevm/actions/type-aliases/deployparams/) for options reference
* @see [DeployResult](https://tevm.sh/reference/tevm/actions/type-aliases/deployresult/) for return values reference
* Remember, you must set `createTransaction: true` to send a transaction. Otherwise it will be a call`. You must also mine the transaction
* before it updates the cannonical head state.` This can be avoided by setting mining mode to `auto` when using createMemoryClient`
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import { ERC20 } from './MyERC721.sol'
*
* const client = createMemoryClient()
* const token = ERC20.withAddress(`0x${'0721'.repeat(10)}`)
*
* const deploymentResult = await client.tevmDeploy({
* abi: token.abi,
* bytecode: token.bytecode,
* args: ['TokenName', 18, 'SYMBOL'],
* })
*
* console.log(deployedResult.createdAddressess)
*/
tevmDeploy: TevmActionsApi['deploy']
/**
* Mines a new block with all pending transactions. In `manual` mode you must call this manually before the cannonical head state is updated
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* await client.tevmMine()
* ```
*/
tevmMine: TevmActionsApi['mine']
/**
* Loads a json serializable state into the evm. This can be useful for persisting and restoring state between processes
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import fs from 'fs'
*
* const client = createMemoryClient()
*
* const state = fs.readFileSync('state.json', 'utf8')
*
* await client.tevmLoadState(state)
* ````
*/
tevmLoadState: TevmActionsApi['loadState']
/**
* Dumps a json serializable state from the evm. This can be useful for persisting and restoring state between processes
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
* import fs from 'fs'
* const client = createMemoryClient()
* const state = await client.tevmDumpState()
* fs.writeFileSync('state.json', JSON.stringify(state))
* ```
*/
tevmDumpState: TevmActionsApi['dumpState']
/**
* Sets any property of an account including
* - it's balance
* - It's nonce
* - It's contract deployedBytecode
* - It's contract state
* - more
* @see [SetAccountParams](https://tevm.sh/reference/tevm/actions/type-aliases/setaccountparams/) for options reference]
* @see [SetAccountResult](https://tevm.sh/reference/tevm/actions/type-aliases/setaccountresult/) for return values reference
* @example
* ```typescript
* import { createMemoryClient, numberToHex } from 'tevm'
* import { SimpleContract } from 'tevm/contract'
*
* const client = createMemoryClient()
*
* await client.tevmSetAccount({
* address: `0x${'0123'.repeat(10)}`,
* balance: 100n,
* nonce: 1n,
* deployedBytecode: SimpleContract.deployedBytecode,
* state: {
* [`0x${'0'.repeat(64)}`]: numberToHex(420n),
* }
* })
* ```
*
*/
tevmSetAccount: TevmActionsApi['setAccount']
/**
* Gets the account state of an account
* It does not return the storage state by default but can if `returnStorage` is set to `true`. In forked mode the storage is only the storage
* Tevm has cached and may not represent all the onchain storage.
* @see [GetAccountParams](https://tevm.sh/reference/tevm/actions/type-aliases/getaccountparams/) for options reference
* @see [GetAccountResult](https://tevm.sh/reference/tevm/actions/type-aliases/getaccountresult/) for return values reference
* @example
* ```typescript
* import { createMemoryClient } from 'tevm'
*
* const client = createMemoryClient()
*
* const account = await client.tevmGetAccount({
* address: `0x${'0000'.repeat(10)}`,
* returnStorage: true,
* })
* ```
*/
Comment on lines +5 to +244
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comprehensive API expansion and excellent documentation!

The API has been significantly expanded to include a variety of new methods that enhance interaction with the EVM. The documentation is detailed, providing clear examples and descriptions of each method's functionality. However, consider adding more detailed examples for the new methods to ensure users can fully understand their usage without ambiguity.

Would you like assistance in creating additional examples or refining the existing documentation?

tevmGetAccount: TevmActionsApi['getAccount']
}
57 changes: 56 additions & 1 deletion packages/memory-client/src/createMemoryClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createClient, createTransport, publicActions } from 'viem'
// TODO strongly type this! Currently it's return type is inferred

/**
* A local EVM instance running in JavaScript. Similar to Anvil in your browser
* Creates a {@link MemoryClient} which is an viem client with an in-memory ethereum client as it's transport.
* It wraps the viem [public client](https://viem.sh/docs/clients/public#public-client) and [test client](https://viem.sh/docs/clients/test)
* @param {import('@tevm/base-client').BaseClientOptions} [options]
* @returns {import('./MemoryClient.js').MemoryClient}
Expand Down Expand Up @@ -36,6 +36,61 @@ import { createClient, createTransport, publicActions } from 'viem'
* )
* console.log(balance) // 1n
* ```
* @see {@link https://tevm.sh/learn/clients/}
*
* ## Actions API
*
* MemoryClient supports the following actions
*
* - [Tevm actions api](https://tevm.sh/reference/tevm/memory-client/type-aliases/tevmactions/)
*
* ```typescript
* import { createMemoryClient } from "tevm"
* import { testActions } from "tevm/decorators"
*
* const tevm = createMemoryClient()
* await tevm.setAccount({address: `0x${'01'.repeat(20)}`, balance: 100n})
* ```
* - [Viem public actions api](https://viem.sh/docs/actions/public/introduction) such as [getBlockNumber}(https://viem.sh/docs/actions/public/getBlockNumber)
*
* ```typescript
* import { createMemoryClient } from "tevm"
* import { testActions } from "tevm/decorators"
*
* const tevm = createMemoryClient()
* const bn = await tevm.getBlockNumber()
* ```
*
* - [test actions](https://viem.sh/docs/actions/test/introduction) are not included by default but can be added via calling `.extend` on the client.`
*
* ```typescript
* import { createMemoryClient } from "tevm"
* import { testActions } from "tevm/decorators"
*
* const tevm = createMemoryClient().extend(testActions({mode: 'anvil'}))
* tevm.setBalance({address: `0x${'01'.repeat(20)}`, balance: 100n})
* ```
*
* ## Forking
*
* To fork an existing network simply pass an eip-1193 transport to the fork.transport option with an optional block tag.
* When you fork tevm will pin the block tag and lazily cache state from the fork transport.
* It's highly recomended to pass in a `common` object that matches the chain. This will increase the performance of forking with known values.
*
* ```typescript
* import { createMemoryClient, http } from "tevm"
* import { optimism } from "tevm/common"
*
* const forkedClient = createMemoryClient({
* fork: {
* transport: http("https://mainnet.optimism.io")({}),
* },
* common: optimism,
* })
* ```
*
* Tevm clients are themselves EIP-1193 transports. This means you can fork a client with another client.
*
*/
export const createMemoryClient = (options) => {
const tevm = createBaseClient(options).extend(tevmSend()).extend(requestEip1193()).extend(tevmActions())
Expand Down
Loading