From 428f01f7c97e73403b55d34d129a30b1b06725e7 Mon Sep 17 00:00:00 2001 From: Maharshi Mishra Date: Sun, 8 Mar 2026 12:39:36 +0530 Subject: [PATCH] docs: Add security token locking docs for TS SDK and TS Compat SDK v1.2.0 TS SDK (api-reference.mdx): - Add Security Token Locking section with all 6 methods: approveSecurityToken, escrowSecurityTokens, getLockedBalance, initiateSecurityTokensWithdrawal, cancelSecurityTokensWithdrawal, withdrawSecurityTokens TS SDK (examples.mdx): - Add locking + app registration example TS SDK (configuration.mdx): - Document lockingContractAddress in blockchain config TS Compat SDK (overview.mdx): - Add Security Token Locking method cheat sheet - Add locking usage example section - Add acknowledge, checkTokenAllowance, getBlockchains, getActionAllowances, getEscrowChannel to queries table - Add App Registry table (getApps, registerApp) - Add rebalanceAppSessions, waitForClose - Add OngoingStateTransitionError to error table - Fix getUserFacingMessage(err) -> getUserFacingMessage(typed) Made-with: Cursor --- docs/build/sdk/typescript-compat/overview.mdx | 57 +++++++++++++++++- docs/build/sdk/typescript/api-reference.mdx | 59 +++++++++++++++++++ docs/build/sdk/typescript/configuration.mdx | 17 ++++++ docs/build/sdk/typescript/examples.mdx | 45 ++++++++++++++ 4 files changed, 177 insertions(+), 1 deletion(-) diff --git a/docs/build/sdk/typescript-compat/overview.mdx b/docs/build/sdk/typescript-compat/overview.mdx index 718aa23..5866081 100644 --- a/docs/build/sdk/typescript-compat/overview.mdx +++ b/docs/build/sdk/typescript-compat/overview.mdx @@ -63,6 +63,8 @@ await client.close(); | `closeChannel(params?)` | Close open channels (optionally for a specific token) | | `resizeChannel({ allocate_amount, token })` | Resize an existing channel | | `challengeChannel({ state })` | Challenge a channel on-chain | +| `acknowledge(tokenAddress)` | Acknowledge a pending state or create a channel | +| `checkTokenAllowance(chainId, tokenAddress)` | Check ERC-20 allowance for the ChannelHub | | `createChannel()` | No-op in v1 (channel creation is implicit on `deposit()`) | ### Queries @@ -78,6 +80,9 @@ await client.close(); | `getAssetsList()` | List supported assets | | `getAccountInfo()` | Aggregate balance + channel count | | `getConfig()` | Node configuration | +| `getBlockchains()` | List supported blockchains | +| `getActionAllowances(wallet?)` | Get gated action allowances for a wallet | +| `getEscrowChannel(escrowChannelId)` | Query an escrow channel by ID | ### Transfers @@ -93,6 +98,14 @@ await client.close(); | `closeAppSession(appSessionId, allocations, quorumSigs?)` | Close an app session | | `submitAppState(params)` | Submit state update (operate/deposit/withdraw/close) | | `getAppDefinition(appSessionId)` | Get session definition | +| `rebalanceAppSessions(signedUpdates)` | Rebalance allocations across app sessions | + +### App Registry + +| Method | Description | +|--------|-------------| +| `getApps(options?)` | List registered applications (filter by appId, owner, pagination) | +| `registerApp(appID, metadata, creationApprovalNotRequired)` | Register a new application | ### App Session Signing Helpers @@ -126,12 +139,24 @@ await client.close(); | `parseAmount(tokenAddress, humanAmount)` | Human-readable string → raw bigint | | `findOpenChannel(tokenAddress, chainId?)` | Find an open channel for a given token | +### Security Token Locking + +| Method | Description | +|--------|-------------| +| `lockSecurityTokens(targetWallet, chainId, amount)` | Lock tokens into the Locking contract for a target address | +| `initiateSecurityTokensWithdrawal(chainId)` | Start the unlock process for locked tokens | +| `cancelSecurityTokensWithdrawal(chainId)` | Re-lock tokens, cancelling a pending unlock | +| `withdrawSecurityTokens(chainId, destination)` | Withdraw unlocked tokens to a destination address | +| `approveSecurityToken(chainId, amount)` | Approve the Locking contract to spend tokens | +| `getLockedBalance(chainId, wallet?)` | Query locked balance (returns raw bigint) | + ### Lifecycle | Method | Description | |--------|-------------| | `ping()` | Health check | | `close()` | Close the WebSocket connection | +| `waitForClose()` | Returns a promise that resolves when the connection is closed | | `refreshAssets()` | Re-fetch the asset map from the clearnode | ## Properties @@ -185,6 +210,7 @@ await v1Client.approveToken(chainId, 'usdc', amount); | `UserRejectedError` | `USER_REJECTED` | User cancelled in wallet | | `InsufficientFundsError` | `INSUFFICIENT_FUNDS` | Not enough balance | | `NotInitializedError` | `NOT_INITIALIZED` | Client not connected | +| `OngoingStateTransitionError` | `ONGOING_STATE_TRANSITION` | Previous action still finalizing | ```typescript import { getUserFacingMessage, AllowanceError } from '@yellow-org/sdk-compat'; @@ -197,7 +223,7 @@ try { if (typed instanceof AllowanceError) { // prompt user to approve token spending } - showToast(getUserFacingMessage(err)); + showToast(getUserFacingMessage(typed)); } ``` @@ -218,6 +244,35 @@ const poller = new EventPoller(client, { poller.start(); ``` +## Security Token Locking + +Lock tokens into the on-chain Locking contract to provide security deposits: + +```typescript +const chainId = 11155111; // Sepolia +const amount = 100_000_000n; // 100 USDC in raw units (6 decimals) + +// Approve the Locking contract to spend tokens +await client.approveSecurityToken(chainId, amount); + +// Lock tokens for a target address +await client.lockSecurityTokens(targetWallet, chainId, amount); + +// Query locked balance +const locked = await client.getLockedBalance(chainId); + +// Initiate unlock (starts the unlock period) +await client.initiateSecurityTokensWithdrawal(chainId); + +// Cancel unlock (re-lock tokens) +await client.cancelSecurityTokensWithdrawal(chainId); + +// After unlock period elapses, withdraw to a destination +await client.withdrawSecurityTokens(chainId, destinationWallet); +``` + +All amounts use raw `bigint` units (consistent with `deposit()` and `withdrawal()`). The compat layer converts to human-readable `Decimal` values internally. + ## Next.js Integration Add to `transpilePackages` in `next.config.ts`: diff --git a/docs/build/sdk/typescript/api-reference.mdx b/docs/build/sdk/typescript/api-reference.mdx index 830eee2..28c693c 100644 --- a/docs/build/sdk/typescript/api-reference.mdx +++ b/docs/build/sdk/typescript/api-reference.mdx @@ -148,6 +148,65 @@ const allowance = await client.checkTokenAllowance(80002n, '0xToken...', '0xOwne --- +## Security Token Locking + +Methods for interacting with the on-chain Locking (NonSlashableAppRegistry) contract. Used for staking security tokens to register apps and receive gated action allowances. + +### `approveSecurityToken(chainId, amount)` + +Approves the Locking contract to spend tokens. Must be called before `escrowSecurityTokens`. + +```typescript +const txHash = await client.approveSecurityToken(11155111n, new Decimal(100)); +``` + +### `escrowSecurityTokens(targetWalletAddress, blockchainId, amount)` + +Locks tokens into the Locking contract for a target address. + +```typescript +const txHash = await client.escrowSecurityTokens( + '0xTargetWallet...', + 11155111n, + new Decimal(100), +); +``` + +### `getLockedBalance(chainId, wallet)` + +Queries the locked balance for a wallet. + +```typescript +const balance = await client.getLockedBalance(11155111n, '0xWallet...'); +console.log('Locked:', balance.toString()); +``` + +### `initiateSecurityTokensWithdrawal(blockchainId)` + +Starts the unlock process. After the unlock period elapses, `withdrawSecurityTokens` can be called. + +```typescript +const txHash = await client.initiateSecurityTokensWithdrawal(11155111n); +``` + +### `cancelSecurityTokensWithdrawal(blockchainId)` + +Re-locks tokens that are in the unlocking state, cancelling the pending unlock. + +```typescript +const txHash = await client.cancelSecurityTokensWithdrawal(11155111n); +``` + +### `withdrawSecurityTokens(blockchainId, destinationWalletAddress)` + +Withdraws unlocked tokens to a destination address. Can only be called after the unlock period has elapsed. + +```typescript +const txHash = await client.withdrawSecurityTokens(11155111n, '0xDestination...'); +``` + +--- + ## Node Information ```typescript diff --git a/docs/build/sdk/typescript/configuration.mdx b/docs/build/sdk/typescript/configuration.mdx index 675f2a2..7ab3cf7 100644 --- a/docs/build/sdk/typescript/configuration.mdx +++ b/docs/build/sdk/typescript/configuration.mdx @@ -55,6 +55,23 @@ withErrorHandler((error) => { }) ``` +### Blockchain Configuration + +The node's `getConfig()` and `getBlockchains()` methods return blockchain details including contract addresses: + +```typescript +const config = await client.getConfig(); +for (const chain of config.blockchains) { + console.log(`${chain.name} (${chain.id})`); + console.log(` ChannelHub: ${chain.channelHubAddress}`); + if (chain.lockingContractAddress) { + console.log(` Locking: ${chain.lockingContractAddress}`); + } +} +``` + +The `lockingContractAddress` field is set on blockchains that support security token locking. When present, the `escrowSecurityTokens`, `approveSecurityToken`, and other locking methods can be used on that chain. + ## Home Blockchain `setHomeBlockchain(asset, blockchainId)` sets the default blockchain for an asset. Required before `transfer()` on a new channel (where no chain context exists yet). diff --git a/docs/build/sdk/typescript/examples.mdx b/docs/build/sdk/typescript/examples.mdx index 84494e5..7d61774 100644 --- a/docs/build/sdk/typescript/examples.mdx +++ b/docs/build/sdk/typescript/examples.mdx @@ -347,6 +347,51 @@ async function setupSessionKey(client: Client) { } ``` +## Security Token Locking + +Register an app by locking security tokens: + +```typescript +import { Client, createSigners, withBlockchainRPC } from '@yellow-org/sdk'; +import Decimal from 'decimal.js'; + +async function lockAndRegisterApp() { + const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!); + const client = await Client.create( + process.env.WS_URL!, + stateSigner, + txSigner, + withBlockchainRPC(11155111n, process.env.SEPOLIA_RPC!), + ); + + const chainId = 11155111n; + const lockAmount = new Decimal(100); + + // Approve the locking contract to spend tokens + await client.approveSecurityToken(chainId, lockAmount); + + // Lock tokens for yourself + const userAddress = client.getUserAddress(); + await client.escrowSecurityTokens(userAddress, chainId, lockAmount); + + // Check locked balance + const balance = await client.getLockedBalance(chainId, userAddress); + console.log('Locked balance:', balance.toString()); + + // Register an app (requires locked tokens) + await client.registerApp('my-app', '{"name": "My App", "description": "Demo"}', false); + console.log('App registered'); + + // Later: initiate unlock + // await client.initiateSecurityTokensWithdrawal(chainId); + + // After unlock period: withdraw + // await client.withdrawSecurityTokens(chainId, userAddress); + + await client.close(); +} +``` + ## Connection Monitoring ```typescript