
tempo-codegen
by wevm
TypeScript Interface for Ethereum
SKILL.md
name: tempo-codegen description: Skill for generating Tempo code.
Tempo Code Generation
When generating actions (in src/tempo/actions/), follow these guidelines.
An example of a generated action set can be found in src/tempo/actions/token.ts.
Source of Truth
- All actions must be based on precompile contract specifications in
test/tempo/docs/specs/. - It could be likely that some interfaces may be inconsistent between the specs (
test/tempo/docs/specs) and the precompiles (test/tempo/crates/contracts/src/precompiles). Always prefer the precompile interfaces over the specs. - If the specification is unclear or missing details, prompt the developer for guidance rather than making assumptions
Documentation Requirements
All actions must include comprehensive JSDoc with:
- Function description - What the action does
@exampleblock - Complete working example showing:- Required imports (
createClient,http, action imports) - Client setup with chain and transport
- Action usage with realistic parameters
- Expected return value handling (if applicable)
- Required imports (
@paramtags - For each parameter (client, parameters)@returnstag - Description of the return value
Example:
/**
* Gets the pool ID for a token pair.
*
* @example
* ```ts
* import { createClient, http } from 'viem'
* import { tempo } from 'tempo.ts/chains'
* import { Actions } from 'tempo.ts/viem'
*
* const client = createClient({
* chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' })
* transport: http(),
* })
*
* const poolId = await Actions.amm.getPoolId(client, {
* userToken: '0x...',
* validatorToken: '0x...',
* })
* ```
*
* @param client - Client.
* @param parameters - Parameters.
* @returns The pool ID.
*/
Action Types
Read-Only Actions
For view/pure functions that only read state:
- Use
readContractfromviem/actions - Return type should use
ReadContractReturnType - Parameters extend
ReadParameters
Mutate-Based Actions
For state-changing functions, both variants must be implemented:
1. Standard Async Variant
- Uses
writeContractfromviem/actions - Returns transaction hash
- Async operation that doesn't wait for confirmation
export async function myAction<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: myAction.Parameters<chain, account>,
): Promise<myAction.ReturnValue> {
return myAction.inner(writeContract, client, parameters)
}
2. Sync Variant (*Sync)
- Named with
Syncsuffix (e.g.,mintSync,burnSync,rebalanceSwapSync) - Uses
writeContractSyncfromviem/actions - Waits for transaction confirmation
- Returns both the receipt and extracted event data
- Must use
extractEventto get return values (notsimulateContract)
export async function myActionSync<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: myActionSync.Parameters<chain, account>,
): Promise<myActionSync.ReturnValue> {
const { throwOnReceiptRevert = true, ...rest } = parameters
const receipt = await myAction.inner(writeContractSync, client, {
...rest,
throwOnReceiptRevert,
} as never)
const { args } = myAction.extractEvent(receipt.logs)
return {
...args,
receipt,
} as never
}
Namespace Properties
All actions must include the following components within their namespace:
1. Parameters Type
// Read actions
export type Parameters = ReadParameters & Args
// Write actions
export type Parameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
> = WriteParameters<chain, account> & Args
2. Args Type
Arguments must be documented with JSDoc.
export type Args = {
/** JSDoc for each argument */
argName: Type
}
3. ReturnValue Type
// Read actions
export type ReturnValue = ReadContractReturnType<typeof Abis.myAbi, 'functionName', never>
// Write actions
export type ReturnValue = WriteContractReturnType
4. ErrorType Type (for write actions)
Write actions must include an ErrorType export. Use BaseErrorType from viem as a placeholder with a TODO comment for future exhaustive error typing:
// TODO: exhaustive error type
export type ErrorType = BaseErrorType
5. call Function
Required for all actions - enables composition with other viem actions:
/**
* Defines a call to the `functionName` function.
*
* Can be passed as a parameter to:
* - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call
* - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call
* - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls
*
* @example
* ```ts
* import { createClient, http, walletActions } from 'viem'
* import { tempo } from 'tempo.ts/chains'
* import { Actions } from 'tempo.ts/viem'
*
* const client = createClient({
* chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' })
* transport: http(),
* }).extend(walletActions)
*
* const hash = await client.sendTransaction({
* calls: [actions.amm.myAction.call({ arg1, arg2 })],
* })
* ```
*
* @param args - Arguments.
* @returns The call.
*/
export function call(args: Args) {
return defineCall({
address: Addresses.contractName,
abi: Abis.contractName,
args: [/* transformed args */],
functionName: 'functionName',
})
}
The call function enables these use cases:
sendCalls- Batch multiple calls in one transactionsendTransactionwithcalls- Send transaction with multiple operationsmulticall- Execute multiple calls in parallelestimateContractGas- Estimate gas costssimulateContract- Simulate execution
6. extractEvent Function (for mutate-based actions)
Required for all actions that emit events:
/**
* Extracts the `EventName` event from logs.
*
* @param logs - The logs.
* @returns The `EventName` event.
*/
export function extractEvent(logs: Log[]) {
const [log] = parseEventLogs({
abi: Abis.contractName,
logs,
eventName: 'EventName',
strict: true,
})
if (!log) throw new Error('`EventName` event not found.')
return log
}
7. inner Function (for write actions)
/** @internal */
export async function inner<
action extends typeof writeContract | typeof writeContractSync,
chain extends Chain | undefined,
account extends Account | undefined,
>(
action: action,
client: Client<Transport, chain, account>,
parameters: Parameters<chain, account>,
): Promise<ReturnType<action>> {
const { arg1, arg2, ...rest } = parameters
const call = myAction.call({ arg1, arg2 })
return (await action(client, {
...rest,
...call,
} as never)) as never
}
Namespace Structure
Organize actions using namespace pattern:
export async function myAction(...) { ... }
export namespace myAction {
export type Parameters = ...
export type Args = ...
export type ReturnValue = ...
export async function inner(...) { ... } // for write actions
export function call(args: Args) { ... }
export function extractEvent(logs: Log[]) { ... } // for mutate actions
}
Decision-Making
When encountering situations that require judgment:
- Specification ambiguities: Prompt developer for clarification
- Missing contract details: Request ABI or specification update
- Event structure uncertainty: Ask for event definition
- Parameter transformations: Confirm expected input/output formats
- Edge cases: Discuss handling strategy with developer
Naming Conventions
- Action names should match contract function names (in camelCase)
- Sync variants use
Syncsuffix (e.g.,myActionSync) - Event names in
extractEventshould match contract event names exactly - Namespace components should be exported within the action's namespace
Testing
Tests should be co-located with actions in *action-name*.test.ts files. Reference contract tests in test/tempo/crates/precompiles/ for expected behavior.
See src/tempo/actions/token.test.ts for a comprehensive example of test patterns and structure.
Test Structure
Organize tests by action name with a default test case and behavior-specific tests:
describe('actionName', () => {
test('default', async () => {
// Test the primary/happy path scenario
const { receipt, ...result } = await Actions.namespace.actionSync(client, {
param1: value1,
param2: value2,
})
expect(receipt).toBeDefined()
expect(result).toMatchInlineSnapshot(`...`)
})
test('behavior: specific edge case', async () => {
// Test specific behaviors, edge cases, or variations
})
test('behavior: error conditions', async () => {
// Test error handling
await expect(
actions.namespace.actionSync(client, { ... })
).rejects.toThrow()
})
})
describe.todo('unimplementedAction')
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 1000以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon

