controller-sessions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseController Sessions & Policies
Controller会话与策略
Sessions enable pre-approved, gasless transactions without user prompts for each interaction.
会话功能支持预批准的无Gas费交易,无需用户在每次交互时都进行确认。
How Sessions Work
会话工作机制
- Define policies (which contracts/methods your app needs)
- User approves policies once during connection
- Controller creates session with approved permissions
- Transactions execute seamlessly via Paymaster
- 定义策略(你的应用需要交互的合约/方法)
- 用户在连接时一次性批准策略
- Controller创建带有已批准权限的会话
- 通过Paymaster无缝执行交易
With vs Without Policies
启用与未启用策略的对比
| Feature | With Policies | Without Policies |
|---|---|---|
| Transaction approval | Pre-approved | Manual each time |
| Gasless transactions | Yes (Paymaster) | No |
| Error handling | Configurable display modes | Standard modal |
| Best for | Games, frequent txs | Simple apps |
| 特性 | 启用策略 | 未启用策略 |
|---|---|---|
| 交易审批 | 预批准 | 每次手动确认 |
| 无Gas费交易 | 是(通过Paymaster) | 否 |
| 错误处理 | 可配置显示模式 | 标准弹窗 |
| 适用场景 | 游戏、高频交易 | 简单应用 |
Defining Policies
定义策略
typescript
import { SessionPolicies } from "@cartridge/controller";
const policies: SessionPolicies = {
contracts: {
"0x1234...": {
name: "My Game",
description: "Game contract interactions",
methods: [
{
name: "Move Player",
entrypoint: "move_player",
description: "Move player on the map",
},
{
name: "Attack",
entrypoint: "attack",
},
],
},
},
};
const controller = new Controller({ policies });typescript
import { SessionPolicies } from "@cartridge/controller";
const policies: SessionPolicies = {
contracts: {
"0x1234...": {
name: "My Game",
description: "Game contract interactions",
methods: [
{
name: "Move Player",
entrypoint: "move_player",
description: "Move player on the map",
},
{
name: "Attack",
entrypoint: "attack",
},
],
},
},
};
const controller = new Controller({ policies });Token Spending Limits
代币支出限额
For methods, specify spending limits in hex format:
approvetypescript
const policies: SessionPolicies = {
contracts: {
// ETH contract
"0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7": {
name: "Ethereum",
methods: [
{
name: "approve",
entrypoint: "approve",
spender: "0x1234567890abcdef1234567890abcdef12345678",
amount: "0x3", // Limit: 3 ETH (hex, accounts for decimals)
},
],
},
},
};- Use for unlimited (max uint128)
0xffffffffffffffffffffffffffffffff - Users see USD values alongside token amounts when price data is available
对于方法,需以十六进制格式指定支出限额:
approvetypescript
const policies: SessionPolicies = {
contracts: {
// ETH contract
"0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7": {
name: "Ethereum",
methods: [
{
name: "approve",
entrypoint: "approve",
spender: "0x1234567890abcdef1234567890abcdef12345678",
amount: "0x3", // Limit: 3 ETH (hex, accounts for decimals)
},
],
},
},
};- 使用表示无限制(最大uint128值)
0xffffffffffffffffffffffffffffffff - 当有价格数据时,用户会在代币金额旁看到对应的USD价值
Signed Message Policies
签名消息策略
Pre-approve typed message signing:
typescript
const policies: SessionPolicies = {
messages: [
{
name: "Game Message",
types: {
StarknetDomain: [
{ name: "name", type: "shortstring" },
{ name: "version", type: "shortstring" },
{ name: "chainId", type: "shortstring" },
{ name: "revision", type: "shortstring" },
],
GameMessage: [
{ name: "content", type: "string" },
{ name: "timestamp", type: "felt" },
],
},
primaryType: "GameMessage",
domain: {
name: "MyGame",
version: "1",
chainId: "SN_MAIN",
revision: "1",
},
},
],
};预批准类型化消息签名:
typescript
const policies: SessionPolicies = {
messages: [
{
name: "Game Message",
types: {
StarknetDomain: [
{ name: "name", type: "shortstring" },
{ name: "version", type: "shortstring" },
{ name: "chainId", type: "shortstring" },
{ name: "revision", type: "shortstring" },
],
GameMessage: [
{ name: "content", type: "string" },
{ name: "timestamp", type: "felt" },
],
},
primaryType: "GameMessage",
domain: {
name: "MyGame",
version: "1",
chainId: "SN_MAIN",
revision: "1",
},
},
],
};Error Handling
错误处理
Error Display Modes
错误显示模式
typescript
const controller = new Controller({
policies,
errorDisplayMode: "notification", // "modal" | "notification" | "silent"
});- modal (default): Full error modal, blocks interaction
- notification: Toast notification (clickable to open modal), non-blocking
- silent: Console only, custom handling required
typescript
const controller = new Controller({
policies,
errorDisplayMode: "notification", // "modal" | "notification" | "silent"
});- modal(默认):全屏错误弹窗,阻止交互
- notification:提示消息(可点击打开弹窗),不阻止交互
- silent:仅在控制台输出,需自定义处理逻辑
Error Handling Interaction
错误处理交互逻辑
| | Behavior |
|---|---|---|
| Any | Errors rejected immediately, no UI shown |
| | Opens controller modal |
| | Shows clickable toast |
| | No UI, logged to console |
| | 行为 |
|---|---|---|
| 任意 | 错误立即抛出,不显示UI |
| | 打开Controller弹窗 |
| | 显示可点击的提示消息 |
| | 无UI提示,仅在控制台记录 |
Error Propagation
错误抛出
Return errors to your app instead of showing keychain UI:
typescript
import { Controller, ResponseCodes } from "@cartridge/controller";
const controller = new Controller({
policies,
propagateSessionErrors: true,
});
const result = await account.execute(calls);
if (result.code === ResponseCodes.SUCCESS) {
console.log("Tx hash:", result.transaction_hash);
} else if (result.code === ResponseCodes.ERROR) {
console.error(result.message, result.error);
}Note: and always show modal regardless of settings.
SessionRefreshRequiredManualExecutionRequired将错误返回至你的应用,而非显示密钥链UI:
typescript
import { Controller, ResponseCodes } from "@cartridge/controller";
const controller = new Controller({
policies,
propagateSessionErrors: true,
});
const result = await account.execute(calls);
if (result.code === ResponseCodes.SUCCESS) {
console.log("Tx hash:", result.transaction_hash);
} else if (result.code === ResponseCodes.ERROR) {
console.error(result.message, result.error);
}注意:无论设置如何,和始终会显示弹窗。
SessionRefreshRequiredManualExecutionRequiredDisconnect Redirect
断开连接重定向
For mobile apps and cross-platform logout flows:
typescript
const connector = new SessionConnector({
policies,
rpc: "https://api.cartridge.gg/x/starknet/mainnet",
chainId: "SN_MAIN",
redirectUrl: "myapp://callback",
disconnectRedirectUrl: "myapp://logout", // Where to go after logout
});适用于移动应用和跨平台登出流程:
typescript
const connector = new SessionConnector({
policies,
rpc: "https://api.cartridge.gg/x/starknet/mainnet",
chainId: "SN_MAIN",
redirectUrl: "myapp://callback",
disconnectRedirectUrl: "myapp://logout", // Where to go after logout
});Verified Sessions
已验证会话
Verified policies display trust badges and streamlined approval flows.
Submit configs to for verification.
@cartridge/presets已验证策略会显示信任标识并提供简化的审批流程。请将配置提交至进行验证。
@cartridge/presetsSessionOptions Type
SessionOptions类型
typescript
type SessionOptions = {
rpc: string; // RPC endpoint URL
chainId: string; // Chain ID
policies: SessionPolicies; // Approved transaction policies
redirectUrl: string; // URL to redirect after auth
disconnectRedirectUrl?: string; // URL to redirect after logout
signupOptions?: AuthOptions; // Auth methods to show
};typescript
type SessionOptions = {
rpc: string; // RPC endpoint URL
chainId: string; // Chain ID
policies: SessionPolicies; // Approved transaction policies
redirectUrl: string; // URL to redirect after auth
disconnectRedirectUrl?: string; // URL to redirect after logout
signupOptions?: AuthOptions; // Auth methods to show
};