diff --git a/bun.lock b/bun.lock index ee2bfea..fa11fd5 100644 --- a/bun.lock +++ b/bun.lock @@ -62,7 +62,7 @@ }, "packages/seismic-react": { "name": "seismic-react", - "version": "1.0.50", + "version": "1.0.53", "peerDependencies": { "@rainbow-me/rainbowkit": "^2.0.0", "react": "^18", @@ -86,7 +86,7 @@ }, "packages/seismic-viem": { "name": "seismic-viem", - "version": "1.0.50", + "version": "1.0.54", "dependencies": { "@noble/ciphers": "^1.2.0", "@noble/curves": "^1.8.0", @@ -2678,7 +2678,7 @@ "rpc-websockets/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], - "seismic-bot/@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="], + "seismic-bot/@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], "seismic-spammer/seismic-viem": ["seismic-viem@1.0.15", "", { "dependencies": { "@noble/ciphers": "^1.2.0", "@noble/curves": "^1.8.0", "@noble/hashes": "^1.7.0", "viem": "^2.21.50" } }, "sha512-xw6lZuZ0l1SeoAFfaqpIY2Hd09WtsjqKWlqtDqWZ3ZNStOCYEFR6m8W7MQYnc1fKpSV93JJNsV9m0GOoclPYXQ=="], @@ -2798,7 +2798,7 @@ "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "seismic-bot/@types/bun/bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="], + "seismic-bot/@types/bun/bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], "seismic-viem-tests/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="], diff --git a/packages/seismic-viem/package.json b/packages/seismic-viem/package.json index ff57c25..8f8fb21 100644 --- a/packages/seismic-viem/package.json +++ b/packages/seismic-viem/package.json @@ -1,6 +1,6 @@ { "name": "seismic-viem", - "version": "1.0.53", + "version": "1.0.54", "description": "Typescript interface for Seismic", "type": "module", "main": "./dist/_cjs/index.js", diff --git a/packages/seismic-viem/src/abis/directory.ts b/packages/seismic-viem/src/abis/directory.ts new file mode 100644 index 0000000..bd7109b --- /dev/null +++ b/packages/seismic-viem/src/abis/directory.ts @@ -0,0 +1,35 @@ +import type { Abi, Address } from 'viem' + +export const DIRECTORY_ADDRESS = + '0x1000000000000000000000000000000000000004' as Address + +export const DirectoryAbi = [ + { + inputs: [{ name: '_addr', type: 'address' }], + name: 'checkHasKey', + outputs: [{ type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ name: 'to', type: 'address' }], + name: 'keyHash', + outputs: [{ type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getKey', + outputs: [{ type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ name: '_key', type: 'suint256' }], + name: 'setKey', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const satisfies Abi diff --git a/packages/seismic-viem/src/abis/src20.ts b/packages/seismic-viem/src/abis/src20.ts new file mode 100644 index 0000000..61d822c --- /dev/null +++ b/packages/seismic-viem/src/abis/src20.ts @@ -0,0 +1,185 @@ +import type { Abi } from 'viem' + +export const SRC20Abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address', + indexed: true, + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + indexed: true, + }, + { + internalType: 'bytes32', + name: 'encryptKeyHash', + type: 'bytes32', + indexed: true, + }, + { + internalType: 'bytes', + name: 'encryptedAmount', + type: 'bytes', + indexed: false, + }, + ], + type: 'event', + name: 'Approval', + anonymous: false, + }, + { + inputs: [ + { + internalType: 'address', + name: 'from', + type: 'address', + indexed: true, + }, + { + internalType: 'address', + name: 'to', + type: 'address', + indexed: true, + }, + { + internalType: 'bytes32', + name: 'encryptKeyHash', + type: 'bytes32', + indexed: true, + }, + { + internalType: 'bytes', + name: 'encryptedAmount', + type: 'bytes', + indexed: false, + }, + ], + type: 'event', + name: 'Transfer', + anonymous: false, + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'DOMAIN_SEPARATOR', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'INTELLIGENCE_ADDRESS', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + }, + { + inputs: [{ internalType: 'address', name: 'spender', type: 'address' }], + stateMutability: 'view', + type: 'function', + name: 'allowance', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'suint256', name: 'amount', type: 'suint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + name: 'approve', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'balance', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'decimals', + outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }], + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'intelligence', + outputs: [ + { + internalType: 'contract IIntelligence', + name: '', + type: 'address', + }, + ], + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'name', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + name: 'nonces', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'suint256', name: 'value', type: 'suint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'uint8', name: 'v', type: 'uint8' }, + { internalType: 'bytes32', name: 'r', type: 'bytes32' }, + { internalType: 'bytes32', name: 's', type: 'bytes32' }, + ], + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + name: 'permit', + }, + { + inputs: [], + stateMutability: 'view', + type: 'function', + name: 'symbol', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + }, + { + inputs: [ + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'suint256', name: 'amount', type: 'suint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + name: 'transfer', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + }, + { + inputs: [ + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'suint256', name: 'amount', type: 'suint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + name: 'transferFrom', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + }, +] as const satisfies Abi diff --git a/packages/seismic-viem/src/actions/src20/crypto.ts b/packages/seismic-viem/src/actions/src20/crypto.ts new file mode 100644 index 0000000..894d76a --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/crypto.ts @@ -0,0 +1,18 @@ +import type { Hex } from 'viem' + +export const NONCE_LENGTH = 24 // 12 bytes in hex string + +export function parseEncryptedData(encryptedData: Hex): { + ciphertext: Hex + nonce: Hex +} { + // Handle empty/zero encrypted data + if (!encryptedData || encryptedData === '0x' || encryptedData.length <= 2) { + throw new Error('Empty encrypted data - recipient has no key') + } + + const nonce = `0x${encryptedData.slice(-NONCE_LENGTH)}` as Hex + const ciphertext = encryptedData.slice(0, -NONCE_LENGTH) as Hex + + return { ciphertext, nonce } +} diff --git a/packages/seismic-viem/src/actions/src20/directory.ts b/packages/seismic-viem/src/actions/src20/directory.ts new file mode 100644 index 0000000..73ff271 --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/directory.ts @@ -0,0 +1,74 @@ +import type { Address, Hex } from 'viem' +import { keccak256 } from 'viem' + +import { DIRECTORY_ADDRESS } from '@sviem/abis/directory.ts' +import { DirectoryAbi } from '@sviem/abis/directory.ts' +import type { ShieldedWalletClient } from '@sviem/client.ts' +import { signedReadContract } from '@sviem/contract/read.ts' +import { shieldedWriteContract } from '@sviem/contract/write.ts' + +const TX_TIMEOUT_MS = 30_000 + +function withTimeout(promise: Promise, ms: number): Promise { + const timeout = new Promise((_, reject) => + setTimeout( + () => reject(new Error(`Transaction timed out after ${ms}ms`)), + ms + ) + ) + return Promise.race([promise, timeout]) +} + +export async function checkRegistration( + client: ShieldedWalletClient, + address: Address +): Promise { + const hasKey = await client.readContract({ + address: DIRECTORY_ADDRESS, + abi: DirectoryAbi, + functionName: 'checkHasKey', + args: [address], + }) + return hasKey as boolean +} + +export async function getKeyHash( + client: ShieldedWalletClient, + address: Address +): Promise { + const keyHash = await client.readContract({ + address: DIRECTORY_ADDRESS, + abi: DirectoryAbi, + functionName: 'keyHash', + args: [address], + }) + return keyHash as Hex +} + +export async function getKey(client: ShieldedWalletClient): Promise { + const key = await signedReadContract(client, { + address: DIRECTORY_ADDRESS, + abi: DirectoryAbi, + functionName: 'getKey', + }) + return ('0x' + (key as bigint).toString(16).padStart(64, '0')) as Hex // TODO: shift to different function +} + +export async function registerKey( + client: ShieldedWalletClient, + aesKey: Hex +): Promise { + const txPromise = shieldedWriteContract(client, { + chain: client.chain, + address: DIRECTORY_ADDRESS, + abi: DirectoryAbi, + functionName: 'setKey', + args: [BigInt(aesKey)], + }) + + return withTimeout(txPromise, TX_TIMEOUT_MS) +} + +export function computeKeyHash(aesKey: Hex): Hex { + return keccak256(aesKey) as Hex +} diff --git a/packages/seismic-viem/src/actions/src20/src20Actions.ts b/packages/seismic-viem/src/actions/src20/src20Actions.ts new file mode 100644 index 0000000..87e4049 --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/src20Actions.ts @@ -0,0 +1,70 @@ +import type { Account, Chain, Hex, Transport } from 'viem' + +import type { WatchSRC20EventsParams } from '@sviem/actions/src20/types.ts' +import { watchSRC20Events } from '@sviem/actions/src20/watchSRC20Events.ts' +import { watchSRC20EventsWithKey } from '@sviem/actions/src20/watchSRC20EventsWithKey.ts' +import type { + ShieldedPublicClient, + ShieldedWalletClient, +} from '@sviem/client.ts' + +/** Actions for SRC20 on a public client */ +export type SRC20PublicActions = { + watchSRC20EventsWithKey: ( + viewingKey: Hex, + params: WatchSRC20EventsParams + ) => Promise<() => void> +} + +/** Actions for SRC20 on a wallet client */ +export type SRC20WalletActions = { + watchSRC20Events: (params: WatchSRC20EventsParams) => Promise<() => void> +} + +/** + * SRC20 actions for a public client. + * + * @example + * ```typescript + * const publicClient = createShieldedPublicClient(...) + * .extend(src20PublicActions) + * + * const unwatch = await publicClient.watchSRC20EventsWithKey(viewingKey, { + * address: '0x...', + * onTransfer: (log) => console.log(log), + * }) + * ``` + */ +export const src20PublicActions = < + TTransport extends Transport, + TChain extends Chain | undefined = Chain | undefined, +>( + client: ShieldedPublicClient +): SRC20PublicActions => ({ + watchSRC20EventsWithKey: (viewingKey, params) => + watchSRC20EventsWithKey(client as any, viewingKey, params), +}) + +/** + * SRC20 actions for a wallet client. + * + * @example + * ```typescript + * const walletClient = createShieldedWalletClient(...) + * .extend(src20WalletActions) + * + * const unwatch = await walletClient.watchSRC20Events({ + * address: '0x...', + * onTransfer: (log) => console.log(log), + * }) + * ``` + */ +export const src20WalletActions = < + TTransport extends Transport, + TChain extends Chain | undefined = Chain | undefined, + TAccount extends Account = Account, +>( + client: ShieldedWalletClient +): SRC20WalletActions => ({ + watchSRC20Events: (params) => watchSRC20Events(client as any, params), +}) diff --git a/packages/seismic-viem/src/actions/src20/types.ts b/packages/seismic-viem/src/actions/src20/types.ts new file mode 100644 index 0000000..d6893e6 --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/types.ts @@ -0,0 +1,37 @@ +import type { Address, Hex } from 'viem' + +export type DecryptedTransferLog = { + from: Address + to: Address + encryptKeyHash: Hex + encryptedAmount: Hex + decryptedAmount: bigint + transactionHash: Hex + blockNumber: bigint +} + +export type DecryptedApprovalLog = { + owner: Address + spender: Address + encryptKeyHash: Hex + encryptedAmount: Hex + decryptedAmount: bigint + transactionHash: Hex + blockNumber: bigint +} + +export type WatchSRC20EventsParams = { + /** SRC20 contract address */ + address: Address + /** Callback for Transfer events */ + onTransfer?: (log: DecryptedTransferLog) => void + /** Callback for Approval events */ + onApproval?: (log: DecryptedApprovalLog) => void + /** Callback for decryption errors */ + onError?: (error: Error) => void +} + +export type WatchSRC20EventsWithKeyParams = WatchSRC20EventsParams & { + /** The AES viewing key for decryption */ + viewingKey: Hex +} diff --git a/packages/seismic-viem/src/actions/src20/watchSRC20Events.ts b/packages/seismic-viem/src/actions/src20/watchSRC20Events.ts new file mode 100644 index 0000000..bc9ae58 --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/watchSRC20Events.ts @@ -0,0 +1,112 @@ +import type { Address, Hex } from 'viem' + +import { SRC20Abi } from '@sviem/abis/src20.ts' +import { parseEncryptedData } from '@sviem/actions/src20/crypto.ts' +import { computeKeyHash, getKey } from '@sviem/actions/src20/directory.ts' +import type { WatchSRC20EventsParams } from '@sviem/actions/src20/types.ts' +import type { ShieldedWalletClient } from '@sviem/client.ts' +import { AesGcmCrypto } from '@sviem/crypto/aes.ts' + +/** + * Watch SRC20 events for the connected wallet. + * Automatically fetches the user's AES key from the Directory contract. + * + * @example + * + * const unwatch = await client.watchSRC20Events({ + * address: '0x...', + * onTransfer: (log) => console.log(`Received ${log.decryptedAmount} from ${log.from}`), + * onApproval: (log) => console.log(`Approved ${log.decryptedAmount} to ${log.spender}`), + * }) + * + * // Later: stop watching + * unwatch() + * */ +export async function watchSRC20Events( + client: ShieldedWalletClient, + params: WatchSRC20EventsParams +): Promise<() => void> { + const { address, onTransfer, onApproval, onError } = params + + // Get user's AES key from Directory via signed read + const aesKey = await getKey(client) + if ( + !aesKey || + aesKey === '0x' || + aesKey === + '0x0000000000000000000000000000000000000000000000000000000000000000' + ) { + throw new Error('No AES key registered in Directory for this address') + } + + // Compute encryptKeyHash for filtering events + const encryptKeyHash = computeKeyHash(aesKey) + + // Create AES cipher + const aesCipher = new AesGcmCrypto(aesKey) + + // Watch Transfer events + const unwatchTransfer = client.watchContractEvent({ + address, + abi: SRC20Abi, + eventName: 'Transfer', + args: { encryptKeyHash }, + onLogs: async (logs) => { + for (const log of logs) { + try { + const { ciphertext, nonce } = parseEncryptedData( + log.args.encryptedAmount as Hex + ) + + const decryptedAmount = await aesCipher.decrypt(ciphertext, nonce) + onTransfer?.({ + from: log.args.from as Address, + to: log.args.to as Address, + encryptKeyHash: log.args.encryptKeyHash as Hex, + encryptedAmount: log.args.encryptedAmount as Hex, + decryptedAmount: BigInt(decryptedAmount), + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + }) + } catch (e) { + onError?.(e as Error) + } + } + }, + }) + + // Watch Approval events + const unwatchApproval = client.watchContractEvent({ + address, + abi: SRC20Abi, + eventName: 'Approval', + args: { encryptKeyHash }, + onLogs: async (logs) => { + for (const log of logs) { + try { + const { ciphertext, nonce } = parseEncryptedData( + log.args.encryptedAmount as Hex + ) + const decryptedAmount = await aesCipher.decrypt(ciphertext, nonce) + onApproval?.({ + owner: log.args.owner as Address, + spender: log.args.spender as Address, + encryptKeyHash: log.args.encryptKeyHash as Hex, + encryptedAmount: log.args.encryptedAmount as Hex, + decryptedAmount: BigInt(decryptedAmount), + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + }) + } catch (e) { + onError?.(e as Error) + } + } + }, + }) + + // Return combined unwatch function + return () => { + unwatchTransfer() + unwatchApproval() + } +} diff --git a/packages/seismic-viem/src/actions/src20/watchSRC20EventsWithKey.ts b/packages/seismic-viem/src/actions/src20/watchSRC20EventsWithKey.ts new file mode 100644 index 0000000..a205b5a --- /dev/null +++ b/packages/seismic-viem/src/actions/src20/watchSRC20EventsWithKey.ts @@ -0,0 +1,102 @@ +import type { Address, Hex } from 'viem' + +import { SRC20Abi } from '@sviem/abis/src20.ts' +import { parseEncryptedData } from '@sviem/actions/src20/crypto.ts' +import { computeKeyHash } from '@sviem/actions/src20/directory.ts' +import type { WatchSRC20EventsParams } from '@sviem/actions/src20/types.ts' +import type { ShieldedPublicClient } from '@sviem/client.ts' +import { AesGcmCrypto } from '@sviem/crypto/aes.ts' + +/** + * Watch SRC20 events with a viewing key. + * Uses a `ShieldedPublicClient` to watch events. + * + * @example + * + * const unwatch = await client.watchSRC20EventsWithKey({ + * address: '0x...', + * onTransfer: (log) => console.log(`Received ${log.decryptedAmount} from ${log.from}`), + * onApproval: (log) => console.log(`Approved ${log.decryptedAmount} to ${log.spender}`), + * }) + * + * // Later: stop watching + * unwatch() + * */ +export async function watchSRC20EventsWithKey( + client: ShieldedPublicClient, + viewingKey: Hex, + params: WatchSRC20EventsParams +): Promise<() => void> { + const { address, onTransfer, onApproval, onError } = params + + // Create AES cipher + const aesCipher = new AesGcmCrypto(viewingKey) + + // Compute encryptKeyHash for filtering events + const encryptKeyHash = computeKeyHash(viewingKey) + + // Watch Transfer events + const unwatchTransfer = client.watchContractEvent({ + address, + abi: SRC20Abi, + eventName: 'Transfer', + args: { encryptKeyHash }, + onLogs: async (logs) => { + for (const log of logs) { + try { + const { ciphertext, nonce } = parseEncryptedData( + log.args.encryptedAmount as Hex + ) + + const decryptedAmount = await aesCipher.decrypt(ciphertext, nonce) + onTransfer?.({ + from: log.args.from as Address, + to: log.args.to as Address, + encryptKeyHash: log.args.encryptKeyHash as Hex, + encryptedAmount: log.args.encryptedAmount as Hex, + decryptedAmount: BigInt(decryptedAmount), + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + }) + } catch (e) { + onError?.(e as Error) + } + } + }, + }) + + // Watch Approval events + const unwatchApproval = client.watchContractEvent({ + address, + abi: SRC20Abi, + eventName: 'Approval', + args: { encryptKeyHash }, + onLogs: async (logs) => { + for (const log of logs) { + try { + const { ciphertext, nonce } = parseEncryptedData( + log.args.encryptedAmount as Hex + ) + const decryptedAmount = await aesCipher.decrypt(ciphertext, nonce) + onApproval?.({ + owner: log.args.owner as Address, + spender: log.args.spender as Address, + encryptKeyHash: log.args.encryptKeyHash as Hex, + encryptedAmount: log.args.encryptedAmount as Hex, + decryptedAmount: BigInt(decryptedAmount), + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + }) + } catch (e) { + onError?.(e as Error) + } + } + }, + }) + + // Return combined unwatch function + return () => { + unwatchTransfer() + unwatchApproval() + } +} diff --git a/packages/seismic-viem/src/client.ts b/packages/seismic-viem/src/client.ts index ec1e890..91d15f9 100644 --- a/packages/seismic-viem/src/client.ts +++ b/packages/seismic-viem/src/client.ts @@ -33,6 +33,14 @@ import { } from '@sviem/actions/encryption.ts' import type { ShieldedPublicActions } from '@sviem/actions/public.ts' import { shieldedPublicActions } from '@sviem/actions/public.ts' +import type { + SRC20PublicActions, + SRC20WalletActions, +} from '@sviem/actions/src20/src20Actions.ts' +import { + src20PublicActions, + src20WalletActions, +} from '@sviem/actions/src20/src20Actions.ts' import type { ShieldedWalletActions } from '@sviem/actions/wallet.ts' import { shieldedWalletActions } from '@sviem/actions/wallet.ts' import { seismicRpcSchema } from '@sviem/chain.ts' @@ -46,6 +54,8 @@ import { compressPublicKey } from '@sviem/crypto/secp.ts' * - `deposit`: deposit into the deposit contract * - `getDepositRoot`: get the deposit root from the deposit contract * - `getDepositCount`: get the deposit count from the deposit contract + * - `watchSRC20Events`: watch SRC20 events for the connected wallet + * - `watchSRC20EventsWithKey`: watch SRC20 events with a viewing key */ export type ShieldedPublicClient< transport extends Transport = Transport, @@ -62,7 +72,8 @@ export type ShieldedPublicClient< : PublicRpcSchema, PublicActions & ShieldedPublicActions & - DepositContractPublicActions + DepositContractPublicActions & + SRC20PublicActions > > @@ -80,6 +91,7 @@ export type ShieldedPublicClient< * - `writeContract`: execute a function on a contract via a Seismic transaction, encrypting the calldata * - `twriteContract`: execute a function on a contract via a standard ethereum transaction * - `deposit`: deposit into the deposit contract + * - `watchSRC20Events`: watch SRC20 events for the connected wallet */ export type ShieldedWalletClient< transport extends Transport = Transport, @@ -97,7 +109,8 @@ export type ShieldedWalletClient< ShieldedPublicActions & ShieldedWalletActions & DepositContractPublicActions & - DepositContractWalletActions + DepositContractWalletActions & + SRC20WalletActions > type SeismicClients< @@ -189,6 +202,8 @@ export const createShieldedPublicClient = < .extend(shieldedPublicActions as any) // @ts-ignore .extend(depositContractPublicActions as any) + // @ts-ignore + .extend(src20PublicActions as any) ) } @@ -235,6 +250,8 @@ export const getSeismicClients = async < .extend(shieldedWalletActions) // @ts-ignore .extend(depositContractWalletActions as any) + // @ts-ignore + .extend(src20WalletActions as any) return { public: pubClient, wallet, diff --git a/packages/seismic-viem/src/index.ts b/packages/seismic-viem/src/index.ts index 8da0632..6f405e9 100644 --- a/packages/seismic-viem/src/index.ts +++ b/packages/seismic-viem/src/index.ts @@ -110,3 +110,31 @@ export type { Secp256K1SigParams } from '@sviem/precompiles/secp256k1.ts' export type { CallClient, Precompile } from '@sviem/precompiles/precompile.ts' export { DEPOSIT_CONTRACT_ADDRESS } from '@sviem/actions/depositContract.ts' + +// SRC20 event watching +export { watchSRC20Events } from '@sviem/actions/src20/watchSRC20Events.ts' +export { watchSRC20EventsWithKey } from '@sviem/actions/src20/watchSRC20EventsWithKey.ts' +export { + src20PublicActions, + src20WalletActions, +} from '@sviem/actions/src20/src20Actions.ts' +export type { + SRC20PublicActions, + SRC20WalletActions, +} from '@sviem/actions/src20/src20Actions.ts' +export type { + DecryptedTransferLog, + DecryptedApprovalLog, + WatchSRC20EventsParams, + WatchSRC20EventsWithKeyParams, +} from '@sviem/actions/src20/types.ts' + +// Directory contract helpers +export { + checkRegistration, + getKeyHash, + getKey, + registerKey, + computeKeyHash, +} from '@sviem/actions/src20/directory.ts' +export { DIRECTORY_ADDRESS, DirectoryAbi } from '@sviem/abis/directory.ts'