diff --git a/docs/pages/viem/actions/deposit.mdx b/docs/pages/viem/actions/deposit.mdx new file mode 100644 index 00000000..128ff920 --- /dev/null +++ b/docs/pages/viem/actions/deposit.mdx @@ -0,0 +1,230 @@ +--- +description: Actions for interacting with the Seismic Deposit Contract for validator staking operations. +--- + +# Deposit Contract Actions + +Actions for interacting with the Seismic Deposit Contract, enabling validator staking operations. + +## What is the Deposit Contract? + +The Deposit Contract is the entry point for staking on Seismic's blockchain. It allows users to deposit ETH to become validators, similar to Ethereum 2.0's deposit contract. The contract handles: + +- Validator registration with node and consensus public keys +- Deposit tracking and root computation +- Withdrawal credential management + +## Import + +```ts +import { + depositContractPublicActions, + depositContractWalletActions, + DEPOSIT_CONTRACT_ADDRESS, +} from 'seismic-viem' +``` + +## Usage + +### Extending Clients + +The deposit contract actions are provided as client extensions that can be added to your existing clients: + +```ts +import { + createShieldedPublicClient, + createShieldedWalletClient, + depositContractPublicActions, + depositContractWalletActions, + seismicDevnet, +} from 'seismic-viem' +import { http, custom } from 'viem' + +// Extend public client with deposit contract read actions +const publicClient = createShieldedPublicClient({ + chain: seismicDevnet, + transport: http(), +}).extend(depositContractPublicActions) + +// Extend wallet client with deposit contract write actions +const walletClient = createShieldedWalletClient({ + chain: seismicDevnet, + transport: custom(window.ethereum), +}).extend(depositContractWalletActions) +``` + +## Public Actions + +### getDepositRoot + +Retrieves the current deposit root hash from the contract. + +```ts +const depositRoot = await publicClient.getDepositRoot({ + address: DEPOSIT_CONTRACT_ADDRESS, // optional, uses default if not specified +}) + +console.log('Deposit root:', depositRoot) +``` + +#### Parameters + +##### address (optional) + +- **Type:** `Address` + +The deposit contract address. Defaults to `DEPOSIT_CONTRACT_ADDRESS`. + +#### Return Value + +`Promise` - The SHA-256 hash of the deposit root. + +--- + +### getDepositCount + +Retrieves the current deposit count from the contract. + +```ts +const depositCount = await publicClient.getDepositCount({ + address: DEPOSIT_CONTRACT_ADDRESS, // optional +}) + +console.log('Total deposits:', depositCount) +``` + +#### Parameters + +##### address (optional) + +- **Type:** `Address` + +The deposit contract address. Defaults to `DEPOSIT_CONTRACT_ADDRESS`. + +#### Return Value + +`Promise` - The deposit count encoded as a little endian 64-bit number. + +## Wallet Actions + +### deposit + +Submits a deposit to register as a validator on the Seismic network. + +```ts +const txHash = await walletClient.deposit({ + nodePubkey: '0x...', // ED25519 public key (32 bytes) + consensusPubkey: '0x...', // BLS12-381 public key (48 bytes) + withdrawalCredentials: '0x...', // Commitment to withdrawal public key + nodeSignature: '0x...', // ED25519 signature (64 bytes) + consensusSignature: '0x...', // BLS12-381 signature (96 bytes) + depositDataRoot: '0x...', // SHA-256 hash of SSZ-encoded DepositData + value: 32000000000000000000n, // Amount in wei (e.g., 32 ETH) +}) + +console.log('Deposit transaction:', txHash) +``` + +#### Parameters + +##### nodePubkey + +- **Type:** `Hex` + +The validator's ED25519 public key (32 bytes). + +##### consensusPubkey + +- **Type:** `Hex` + +The validator's BLS12-381 public key for consensus (48 bytes). + +##### withdrawalCredentials + +- **Type:** `Hex` + +Commitment to a public key for future withdrawals. + +##### nodeSignature + +- **Type:** `Hex` + +ED25519 signature over the deposit data (64 bytes). + +##### consensusSignature + +- **Type:** `Hex` + +BLS12-381 signature over the deposit data (96 bytes). + +##### depositDataRoot + +- **Type:** `Hex` + +The SHA-256 hash of the SSZ-encoded DepositData object. Used as a protection against malformed input. + +##### value + +- **Type:** `bigint` + +The amount of ETH to deposit, in wei. + +##### address (optional) + +- **Type:** `Address` + +The deposit contract address. Defaults to `DEPOSIT_CONTRACT_ADDRESS`. + +#### Return Value + +`Promise` - The transaction hash. + +## Complete Example + +```ts +import { + createShieldedPublicClient, + createShieldedWalletClient, + depositContractPublicActions, + depositContractWalletActions, + seismicDevnet, +} from 'seismic-viem' +import { http, custom, parseEther } from 'viem' + +// Create clients with deposit contract extensions +const publicClient = createShieldedPublicClient({ + chain: seismicDevnet, + transport: http(), +}).extend(depositContractPublicActions) + +const walletClient = createShieldedWalletClient({ + chain: seismicDevnet, + transport: custom(window.ethereum), +}).extend(depositContractWalletActions) + +// Check current deposit state +const depositRoot = await publicClient.getDepositRoot({}) +const depositCount = await publicClient.getDepositCount({}) + +console.log('Current deposit root:', depositRoot) +console.log('Total deposits:', depositCount) + +// Submit a validator deposit +const txHash = await walletClient.deposit({ + nodePubkey: '0x...your-node-pubkey...', + consensusPubkey: '0x...your-consensus-pubkey...', + withdrawalCredentials: '0x...your-withdrawal-credentials...', + nodeSignature: '0x...your-node-signature...', + consensusSignature: '0x...your-consensus-signature...', + depositDataRoot: '0x...your-deposit-data-root...', + value: parseEther('32'), +}) + +console.log('Deposit submitted:', txHash) +``` + +## Remarks + +- The deposit contract address is pre-configured but can be overridden for testing or alternative deployments. +- Ensure all signatures and keys are properly formatted before submitting a deposit. +- The `depositDataRoot` serves as a checksum to prevent malformed deposit data from being accepted. diff --git a/docs/pages/viem/actions/src20.mdx b/docs/pages/viem/actions/src20.mdx new file mode 100644 index 00000000..f37e4e05 --- /dev/null +++ b/docs/pages/viem/actions/src20.mdx @@ -0,0 +1,250 @@ +--- +description: Actions for watching and decrypting SRC20 token events with privacy-preserving capabilities. +--- + +# SRC20 Event Actions + +Actions for watching and decrypting SRC20 token events. SRC20 is Seismic's privacy-preserving token standard that encrypts transfer amounts in events. + +## What is SRC20? + +SRC20 is Seismic's confidential token standard, similar to ERC20 but with privacy-preserving features. Unlike standard ERC20 tokens where all transfer amounts are publicly visible on-chain, SRC20: + +- Encrypts transfer and approval amounts in events +- Uses AES-GCM encryption with user-specific viewing keys +- Allows users to decrypt only events relevant to them via `encryptKeyHash` filtering + +The SRC20 event actions provide utilities to watch for these encrypted events and automatically decrypt them using either: +- A wallet client (automatically fetches the user's key from the Directory contract) +- A public client with an explicit viewing key + +## Import + +```ts +import { + src20PublicActions, + src20WalletActions, +} from 'seismic-viem' +``` + +## Usage + +### Extending Clients + +The SRC20 actions are provided as client extensions: + +```ts +import { + createShieldedPublicClient, + createShieldedWalletClient, + src20PublicActions, + src20WalletActions, + seismicDevnet, +} from 'seismic-viem' +import { http, custom } from 'viem' + +// For watching events with an explicit viewing key +const publicClient = createShieldedPublicClient({ + chain: seismicDevnet, + transport: http(), +}).extend(src20PublicActions) + +// For watching events with automatic key retrieval +const walletClient = createShieldedWalletClient({ + chain: seismicDevnet, + transport: custom(window.ethereum), +}).extend(src20WalletActions) +``` + +## Wallet Actions + +### watchSRC20Events + +Watches for SRC20 Transfer and Approval events, automatically decrypting amounts using the connected wallet's viewing key from the Directory contract. + +```ts +const unwatch = await walletClient.watchSRC20Events({ + address: '0x...', // SRC20 token contract address + onTransfer: (log) => { + console.log(`Transfer: ${log.from} → ${log.to}`) + console.log(`Amount: ${log.decryptedAmount}`) + }, + onApproval: (log) => { + console.log(`Approval: ${log.owner} → ${log.spender}`) + console.log(`Amount: ${log.decryptedAmount}`) + }, + onError: (error) => { + console.error('Decryption error:', error) + }, +}) + +// Later: stop watching +unwatch() +``` + +#### Parameters + +##### address + +- **Type:** `Address` + +The SRC20 token contract address to watch. + +##### onTransfer (optional) + +- **Type:** `(log: DecryptedTransferLog) => void` + +Callback function called when a Transfer event is detected and decrypted. + +##### onApproval (optional) + +- **Type:** `(log: DecryptedApprovalLog) => void` + +Callback function called when an Approval event is detected and decrypted. + +##### onError (optional) + +- **Type:** `(error: Error) => void` + +Callback function called when a decryption error occurs. + +#### Return Value + +`Promise<() => void>` - A function to stop watching events. + +#### Throws + +Throws an error if no AES key is registered in the Directory contract for the connected address. + +## Public Actions + +### watchSRC20EventsWithKey + +Watches for SRC20 Transfer and Approval events using an explicit viewing key. Useful for: +- Server-side monitoring +- Watching events without a connected wallet +- Monitoring multiple addresses with different keys + +```ts +const viewingKey = '0x...' // 32-byte AES key + +const unwatch = await publicClient.watchSRC20EventsWithKey(viewingKey, { + address: '0x...', // SRC20 token contract address + onTransfer: (log) => { + console.log(`Transfer: ${log.from} → ${log.to}`) + console.log(`Amount: ${log.decryptedAmount}`) + }, + onApproval: (log) => { + console.log(`Approval: ${log.owner} → ${log.spender}`) + console.log(`Amount: ${log.decryptedAmount}`) + }, + onError: (error) => { + console.error('Decryption error:', error) + }, +}) + +// Later: stop watching +unwatch() +``` + +#### Parameters + +##### viewingKey + +- **Type:** `Hex` + +The 32-byte AES viewing key used to decrypt event amounts. + +##### params + +Same as `watchSRC20Events` parameters (address, onTransfer, onApproval, onError). + +#### Return Value + +`Promise<() => void>` - A function to stop watching events. + +## Event Log Types + +### DecryptedTransferLog + +```ts +type DecryptedTransferLog = { + from: Address // Sender address + to: Address // Recipient address + encryptKeyHash: Hex // Hash of the encryption key + encryptedAmount: Hex // Original encrypted amount + decryptedAmount: bigint // Decrypted transfer amount + transactionHash: Hex // Transaction hash + blockNumber: bigint // Block number +} +``` + +### DecryptedApprovalLog + +```ts +type DecryptedApprovalLog = { + owner: Address // Token owner address + spender: Address // Approved spender address + encryptKeyHash: Hex // Hash of the encryption key + encryptedAmount: Hex // Original encrypted amount + decryptedAmount: bigint // Decrypted approval amount + transactionHash: Hex // Block number + blockNumber: bigint // Block number +} +``` + +## Complete Example + +```ts +import { + createShieldedWalletClient, + src20WalletActions, + seismicDevnet, +} from 'seismic-viem' +import { custom } from 'viem' + +// Create wallet client with SRC20 extensions +const walletClient = createShieldedWalletClient({ + chain: seismicDevnet, + transport: custom(window.ethereum), +}).extend(src20WalletActions) + +// Watch for all SRC20 events on a token +const unwatch = await walletClient.watchSRC20Events({ + address: '0x1234...', // Your SRC20 token address + onTransfer: (log) => { + if (log.to === walletClient.account.address) { + console.log(`Received ${log.decryptedAmount} tokens from ${log.from}`) + } else if (log.from === walletClient.account.address) { + console.log(`Sent ${log.decryptedAmount} tokens to ${log.to}`) + } + }, + onApproval: (log) => { + console.log( + `Approved ${log.spender} to spend ${log.decryptedAmount} tokens` + ) + }, + onError: (error) => { + console.error('Failed to decrypt event:', error.message) + }, +}) + +// Clean up when done +// unwatch() +``` + +## How Event Decryption Works + +1. **Key Registration**: Users register their AES viewing key in the Directory contract. +2. **Event Emission**: When a Transfer or Approval occurs, the SRC20 contract emits an event with: + - The `encryptKeyHash` (keccak256 hash of the viewing key) + - The `encryptedAmount` (AES-GCM encrypted amount) +3. **Event Filtering**: The watcher filters events by `encryptKeyHash` to only receive events decryptable with the user's key. +4. **Decryption**: Each event's `encryptedAmount` is decrypted using the viewing key to reveal the actual amount. + +## Remarks + +- The `encryptKeyHash` is used to efficiently filter events on-chain, so users only receive events they can decrypt. +- For `watchSRC20Events`, the viewing key is automatically fetched from the Directory contract using a signed read. +- Events are processed as they arrive; there may be a slight delay in decryption for high-throughput scenarios. +- Always call the returned `unwatch` function when you no longer need to monitor events to clean up resources. diff --git a/docs/sidebar.ts b/docs/sidebar.ts index 8a31cf0d..19466e34 100644 --- a/docs/sidebar.ts +++ b/docs/sidebar.ts @@ -49,6 +49,14 @@ const viemSidebar = [ text: 'Wallet', link: '/viem/actions/wallet', }, + { + text: 'Deposit Contract', + link: '/viem/actions/deposit', + }, + { + text: 'SRC20 Events', + link: '/viem/actions/src20', + }, ], }, {