关于 squads
squads 是面向 Solana 开发者的协议开发指南,介绍多签、智能账户和 Grid 开放金融基础设施。内容涵盖提案审批、可编程钱包和稳定币支付,适合构建团队资产管理及支付系统。
主要功能
- 01使用 Squads V4 管理多签提案与金库
- 02设置时间锁、支出限额和批量交易
- 03通过智能账户配置会话密钥与策略
- 04使用 passkey 进行身份验证
- 05通过 Grid 构建稳定币支付和定期付款
适用场景
- 01为团队金库创建提案、投票并执行交易
- 02限制成员权限并为高价值交易添加时间锁
- 03为钱包配置临时授权和支出策略
- 04为支付平台实现稳定币转账与定期付款
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sendaifun/ skills --skill squads安装后在 Claude Code 中输入/squads确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
docs/troubleshooting.mdexamples/grid/api-quickstart.tspayments.tsexamples/multisig/create-multisig.tsproposals-voting.tsspending-limits.tsvault-transactions.tsexamples/smart-account/account-creation.tssession-keys.tsresources/grid-api-reference.mdmultisig-api-reference.mdprogram-addresses.mdsmart-account-api-reference.mdtemplates/grid-client.tsmultisig-setup.tssmart-account-setup.ts详细介绍
Squads Protocol 开发指南
Squads Protocol 是 Solana 首屈一指的智能账户基础设施,保障着价值超过 100 亿美元的数字资产。本指南涵盖全部三款主要产品:Squads V4 Multisig、Smart Account Program 和 Grid。
概览
Squads Protocol 提供:
- Squads V4 Multisig - 面向团队的多重签名钱包,支持提案、投票、时间锁、支出限额和程序升级管理
- Smart Account Program - 账户抽象基础设施,支持会话密钥、通行密钥、可编程策略和直接扣款
- Grid - 开放式金融基础设施,面向稳定币支付通道、新银行平台和企业支付系统
程序 ID
| 程序 | 主网 | 开发网 |
|---|---|---|
| Squads V4 Multisig | SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf | SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf |
| Smart Account | SMRTzfY6DfH5ik3TKiyLFfXexV8uSG3d2UksSCYdunG | SMRTzfY6DfH5ik3TKiyLFfXexV8uSG3d2UksSCYdunG |
| External Signature (Grid) | ExtSgUPtP3JyKUysFw2S5fpL5fWfUPzGUQLd2bTwftXN | ExtSgUPtP3JyKUysFw2S5fpL5fWfUPzGUQLd2bTwftXN |
Eclipse 主网:
| 程序 | 地址 |
|---|---|
| Squads V4 Multisig | eSQDSMLf3qxwHVHeTr9amVAGmZbRLY2rFdSURandt6f |
快速开始
安装
# Squads V4 Multisig SDK
npm install @sqds/multisig @solana/web3.js
# Grid SDK
npm install @sqds/grid
# Grid React Native SDK
npm install @sqds/grid-react-native
基本设置
import * as multisig from "@sqds/multisig";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
// Setup connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
// Load wallet
const wallet = Keypair.fromSecretKey(/* your secret key */);
// Program ID constant
const SQUADS_PROGRAM_ID = new PublicKey("SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf");
Squads V4 Multisig
Squads V4 是多重签名协议的最新版本,具备增强的安全性、时间锁、支出限额和批量交易功能。
核心概念
Multisig 账户:保存配置(成员、阈值、时间锁设置)的主账户。
金库:由 Multisig 控制、用于存储资产的 PDA。每个 Multisig 可以有多个金库(索引为 0、1、2……)。
提案:一项交易执行请求,需要获得 Multisig 成员的批准。
交易:提案获批后要执行的实际指令。
权限系统
成员可以拥有不同的权限:
import { Permission, Permissions } from "@sqds/multisig/lib/types";
// All permissions (can initiate, vote, and execute)
const fullPermissions = Permissions.all();
// Specific permissions
const voteOnly = Permissions.fromPermissions([Permission.Vote]);
const initiateAndVote = Permissions.fromPermissions([Permission.Initiate, Permission.Vote]);
const executeOnly = Permissions.fromPermissions([Permission.Execute]);
| 权限 | 描述 |
|---|---|
Initiate | 可以创建新提案 |
Vote | 可以批准或拒绝提案 |
Execute | 可以执行已批准的提案 |
创建 Multisig
import * as multisig from "@sqds/multisig";
const { Permissions } = multisig.types;
// Generate a unique create key (one-time use)
const createKey = Keypair.generate();
// Derive the multisig PDA
const [multisigPda] = multisig.getMultisigPda({
createKey: createKey.publicKey,
});
// Create a 2-of-3 multisig
const signature = await multisig.rpc.multisigCreateV2({
connection,
createKey,
creator: wallet,
multisigPda,
configAuthority: null, // Immutable config
threshold: 2,
members: [
{ key: member1.publicKey, permissions: Permissions.all() },
{ key: member2.publicKey, permissions: Permissions.all() },
{ key: member3.publicKey, permissions: Permissions.fromPermissions([Permission.Vote]) },
],
timeLock: 0, // No time lock (in seconds)
rentCollector: null,
});
console.log("Multisig created:", multisigPda.toString());
console.log("Transaction:", signature);
金库操作
金库是用于存放 Multisig 资产的 PDA:
// Derive vault PDA (index 0 is the default vault)
const [vaultPda] = multisig.getVaultPda({
multisigPda,
index: 0,
});
console.log("Vault address:", vaultPda.toString());
// Check vault balance
const balance = await connection.getBalance(vaultPda);
console.log("Vault balance:", balance / 1e9, "SOL");
重要提示:请始终将资金发送到金库 PDA,而不是 Multisig 账户本身。
创建金库交易
import { SystemProgram, LAMPORTS_PER_SOL } from "@solana/web3.js";
// Get current transaction index
const multisigAccount = await multisig.accounts.Multisig.fromAccountAddress(
connection,
multisigPda
);
const transactionIndex = BigInt(Number(multisigAccount.transactionIndex) + 1);
// Derive transaction PDA
const [transactionPda] = multisig.getTransactionPda({
multisigPda,
index: transactionIndex,
});
// Create a transfer instruction
const transferIx = SystemProgram.transfer({
fromPubkey: vaultPda,
toPubkey: recipientPubkey,
lamports: 0.1 * LAMPORTS_PER_SOL,
});
// Create the vault transaction
const signature = await multisig.rpc.vaultTransactionCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet.publicKey,
vaultIndex: 0,
ephemeralSigners: 0,
transactionMessage: new TransactionMessage({
payerKey: vaultPda,
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
instructions: [transferIx],
}),
});
console.log("Vault transaction created:", transactionPda.toString());
创建和管理提案
// Derive proposal PDA
const [proposalPda] = multisig.getProposalPda({
multisigPda,
transactionIndex,
});
// Create proposal for the transaction
const createProposalSig = await multisig.rpc.proposalCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet,
});
console.log("Proposal created:", proposalPda.toString());
对提案投票
// Approve the proposal
const approveSig = await multisig.rpc.proposalApprove({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
member: wallet,
});
console.log("Proposal approved");
// Or reject the proposal
const rejectSig = await multisig.rpc.proposalReject({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
member: wallet,
memo: "Reason for rejection",
});
执行已批准的交易
// Check if proposal is approved and ready
const proposal = await multisig.accounts.Proposal.fromAccountAddress(
connection,
proposalPda
);
if (proposal.status.__kind === "Approved") {
// Execute the vault transaction
const executeSig = await multisig.rpc.vaultTransactionExecute({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
member: wallet.publicKey,
});
console.log("Transaction executed:", executeSig);
}
支出限额
支出限额允许成员在无需获得完整 Multisig 批准的情况下,执行金额不超过指定上限的交易:
// Create a spending limit
const createSpendingLimitSig = await multisig.rpc.configTransactionCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet.publicKey,
actions: [{
__kind: "AddSpendingLimit",
createKey: spendingLimitCreateKey.publicKey,
vaultIndex: 0,
mint: SOL_MINT, // or token mint
amount: BigInt(1 * LAMPORTS_PER_SOL), // 1 SOL
period: multisig.types.Period.Day,
members: [trustedMember.publicKey],
destinations: [allowedDestination],
}],
});
// Use spending limit (no proposal needed)
const useSpendingLimitSig = await multisig.rpc.spendingLimitUse({
connection,
feePayer: wallet,
multisigPda,
member: trustedMember,
spendingLimit: spendingLimitPda,
mint: SOL_MINT,
vaultIndex: 0,
amount: BigInt(0.5 * LAMPORTS_PER_SOL),
decimals: 9,
destination: allowedDestination,
});
批量交易
以原子方式执行多项交易:
// Create a batch
const [batchPda] = multisig.getBatchPda({
multisigPda,
batchIndex: transactionIndex,
});
const createBatchSig = await multisig.rpc.batchCreate({
connection,
feePayer: wallet,
multisigPda,
batchIndex: transactionIndex,
creator: wallet,
vaultIndex: 0,
});
// Add transactions to the batch
await multisig.rpc.batchAddTransaction({
connection,
feePayer: wallet,
multisigPda,
batchIndex: transactionIndex,
transactionIndex: 1,
vaultIndex: 0,
transactionMessage: /* first transaction */,
});
await multisig.rpc.batchAddTransaction({
connection,
feePayer: wallet,
multisigPda,
batchIndex: transactionIndex,
transactionIndex: 2,
vaultIndex: 0,
transactionMessage: /* second transaction */,
});
// Create proposal and execute as usual
配置交易
修改 Multisig 设置(需要提案获批):
// Add a new member
const addMemberSig = await multisig.rpc.configTransactionCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet.publicKey,
actions: [{
__kind: "AddMember",
newMember: {
key: newMemberPubkey,
permissions: Permissions.all(),
},
}],
});
// Change threshold
const changeThresholdSig = await multisig.rpc.configTransactionCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet.publicKey,
actions: [{
__kind: "ChangeThreshold",
newThreshold: 3,
}],
});
// Remove a member
const removeMemberSig = await multisig.rpc.configTransactionCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet.publicKey,
actions: [{
__kind: "RemoveMember",
oldMember: memberToRemove,
}],
});
时间锁
为已批准的交易添加一段执行延迟:
// Create multisig with time lock (1 day = 86400 seconds)
const signature = await multisig.rpc.multisigCreateV2({
connection,
createKey,
creator: wallet,
multisigPda,
configAuthority: null,
threshold: 2,
members: [...],
timeLock: 86400, // 1 day in seconds
rentCollector: null,
});
PDA 派生参考
import * as multisig from "@sqds/multisig";
// Multisig PDA
const [multisigPda] = multisig.getMultisigPda({
createKey: createKeyPubkey,
});
// Vault PDA
const [vaultPda] = multisig.getVaultPda({
multisigPda,
index: 0, // vault index
});
// Transaction PDA
const [transactionPda] = multisig.getTransactionPda({
multisigPda,
index: transactionIndex,
});
// Proposal PDA
const [proposalPda] = multisig.getProposalPda({
multisigPda,
transactionIndex,
});
// Batch PDA
const [batchPda] = multisig.getBatchPda({
multisigPda,
batchIndex,
});
// Spending Limit PDA
const [spendingLimitPda] = multisig.getSpendingLimitPda({
multisigPda,
createKey: spendingLimitCreateKey,
});
// Program Config PDA
const [programConfigPda] = multisig.getProgramConfigPda({});
// Ephemeral Signer PDA (for CPI calls)
const [ephemeralSignerPda] = multisig.getEphemeralSignerPda({
transactionPda,
ephemeralSignerIndex: 0,
});
Smart Account Program
Smart Account Program 为 Solana 提供账户抽象功能,让用户能够使用会话密钥、通行密钥和基于策略的执行,创建可编程钱包。
核心概念
Smart Account:由策略而非仅由私钥控制的可编程钱包。
会话密钥:针对特定操作、权限受限的临时密钥。
通行密钥:使用生物识别或硬件密钥进行的 WebAuthn/FIDO2 身份验证。
策略:规定可执行哪些交易的规则。
功能
- 免租部署 - 智能账户无需支付租金
- 原子策略执行 - 所有策略检查均以原子方式完成
- 账户压缩 - 高效存储多个签名者
- 可扩展策略 - 可添加自定义策略程序
- 直接扣款 - 自动定期付款
- 订阅 - 托管订阅计费
REST API 基础 URL
https://developer-api.squads.so/api/v1
创建智能账户
// Via REST API
const response = await fetch("https://developer-api.squads.so/api/v1/accounts", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
email: "[email protected]",
// or
signer: signerPublicKey,
}),
});
const account = await response.json();
console.log("Smart account:", account.address);
会话密钥管理
会话密钥可授予具有特定权限的委托访问权限:
// Create a session key
const sessionResponse = await fetch(
`https://developer-api.squads.so/api/v1/accounts/${accountId}/sessions`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
publicKey: sessionKeyPublicKey,
expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
permissions: ["transfer", "swap"],
limits: {
maxAmount: "1000000000", // 1 SOL in lamports
dailyLimit: "5000000000", // 5 SOL daily
},
}),
}
);
通行密钥身份验证
// Register a passkey
const registerResponse = await fetch(
`https://developer-api.squads.so/api/v1/accounts/${accountId}/passkeys`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
credentialId: webAuthnCredential.id,
publicKey: webAuthnCredential.publicKey,
attestation: webAuthnCredential.attestation,
}),
}
);
// Authenticate with passkey
const authResponse = await fetch(
"https://developer-api.squads.so/api/v1/auth/passkey",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
credentialId: webAuthnCredential.id,
assertion: webAuthnAssertion,
}),
}
);
策略配置
// Set spending policy
const policyResponse = await fetch(
`https://developer-api.squads.so/api/v1/accounts/${accountId}/policies`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify({
type: "spending_limit",
params: {
mint: "So11111111111111111111111111111111111111112", // SOL
amount: "10000000000", // 10 SOL
period: "daily",
},
}),
}
);
Grid
Grid 是 Squads 的开放金融基础设施,为稳定币提供支付通道,助力新型银行平台和企业支付系统。
功能
- 稳定币支付通道 - USDC/USDT 支付基础设施
- 可编程支付 - 自动化资金流转
- 虚拟账户 - 法币出入金通道
- KYC 集成 - 内置合规工具
- 自托管 - 用户自行掌控资产
API 身份验证
// Email OTP authentication
const otpResponse = await fetch("https://developer-api.squads.so/api/v1/auth/email/otp", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "[email protected]",
}),
});
// Verify OTP
const verifyResponse = await fetch("https://developer-api.squads.so/api/v1/auth/email/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "[email protected]",
otp: "123456",
}),
});
const { accessToken } = await verifyResponse.json();
账户管理
// Get account details
const accountResponse = await fetch(
`https://developer-api.squads.so/api/v1/accounts/${accountId}`,
{
headers: {
"Authorization": `Bearer ${accessToken}`,
},
}
);
const account = await accountResponse.json();
console.log("Balance:", account.balance);
console.log("Status:", account.status);
支付操作
// Create a payment intent
const paymentResponse = await fetch(
"https://developer-api.squads.so/api/v1/payments",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
},
body: JSON.stringify({
amount: "100000000", // 100 USDC (6 decimals)
currency: "USDC",
recipient: recipientAddress,
memo: "Payment for services",
}),
}
);
const payment = await paymentResponse.json();
console.log("Payment ID:", payment.id);
console.log("Status:", payment.status);
定期指令(周期性支付)
// Create a standing order
const standingOrderResponse = await fetch(
"https://developer-api.squads.so/api/v1/standing-orders",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
},
body: JSON.stringify({
amount: "50000000", // 50 USDC
currency: "USDC",
recipient: recipientAddress,
frequency: "monthly",
startDate: "2024-02-01",
memo: "Monthly subscription",
}),
}
);
支出限额
// Set spending limit
const limitResponse = await fetch(
`https://developer-api.squads.so/api/v1/accounts/${accountId}/limits`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
},
body: JSON.stringify({
type: "daily",
amount: "1000000000", // 1000 USDC
currency: "USDC",
}),
}
);
最佳实践
安全
- 切勿共享私钥 - 使用环境变量存储敏感数据
- 验证程序 ID - 始终确认你正在与官方程序交互
- 使用时间锁 - 对于高价值资金库,添加时间锁以增强安全性
- 限制权限 - 仅向成员授予所需权限
- 在 devnet 上测试 - 在 mainnet 上使用前,务必先在 devnet 上测试交易
交易优化
- 使用地址查找表 - 减小复杂操作的交易大小
- 批量处理交易 - 尽可能将相关操作分组
- 设置适当的计算预算 - 避免因计算限制导致交易失败
import { ComputeBudgetProgram } from "@solana/web3.js";
// Add compute budget instruction
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({
units: 400_000,
});
// Add priority fee for faster inclusion
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 10_000,
});
错误处理
try {
const signature = await multisig.rpc.proposalCreate({
connection,
feePayer: wallet,
multisigPda,
transactionIndex,
creator: wallet,
});
} catch (error) {
if (error.message.includes("NotAMember")) {
console.error("Wallet is not a member of this multisig");
} else if (error.message.includes("Unauthorized")) {
console.error("Wallet does not have required permissions");
} else if (error.message.includes("InvalidTransactionIndex")) {
console.error("Transaction index already used");
} else {
throw error;
}
}
获取账户状态
// Get multisig account
const multisigAccount = await multisig.accounts.Multisig.fromAccountAddress(
connection,
multisigPda
);
console.log("Threshold:", multisigAccount.threshold);
console.log("Members:", multisigAccount.members);
console.log("Transaction Index:", multisigAccount.transactionIndex.toString());
// Get proposal status
const proposal = await multisig.accounts.Proposal.fromAccountAddress(
connection,
proposalPda
);
console.log("Status:", proposal.status.__kind);
console.log("Approved:", proposal.approved.length);
console.log("Rejected:", proposal.rejected.length);
常见模式
程序升级多签
使用多签保护程序升级权限:
// Transfer upgrade authority to multisig vault
const transferAuthIx = createSetAuthorityInstruction(
programDataAddress,
currentAuthority,
AuthorityType.UpgradeAuthority,
vaultPda
);
// Execute via multisig proposal
// Now program upgrades require multisig approval
资金库管理
// Create multiple vaults for different purposes
const [operationsVault] = multisig.getVaultPda({ multisigPda, index: 0 });
const [reserveVault] = multisig.getVaultPda({ multisigPda, index: 1 });
const [grantVault] = multisig.getVaultPda({ multisigPda, index: 2 });
// Set spending limits for operations vault
// Reserve vault requires full multisig approval
验证者操作
// Manage validator identity and vote account with multisig
// Transfer validator identity to vault
// Set up spending limits for operational costs
资源
官方文档
GitHub 仓库
安全审计
- OtterSec 审计
- Neodyme 审计
- Certora 审计
- Trail of Bits 审计
验证程序构建
# Install solana-verify
cargo install solana-verify
# Verify Squads V4 program
solana-verify get-program-hash -u mainnet-beta SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf
技能结构
squads/
├── SKILL.md # This file
├── resources/
│ ├── program-addresses.md # All program IDs and PDAs
│ ├── multisig-api-reference.md # @sqds/multisig SDK reference
│ ├── smart-account-api-reference.md # Smart Account API reference
│ └── grid-api-reference.md # Grid REST API reference
├── examples/
│ ├── multisig/
│ │ ├── create-multisig.ts # Create multisig with members
│ │ ├── proposals-voting.ts # Proposals and voting
│ │ ├── vault-transactions.ts # Vault operations
│ │ └── spending-limits.ts # Spending limit management
│ ├── smart-account/
│ │ ├── account-creation.ts # Smart account setup
│ │ └── session-keys.ts # Session key management
│ └── grid/
│ ├── api-quickstart.ts # REST API basics
│ └── payments.ts # Payment operations
├── templates/
│ ├── multisig-setup.ts # Multisig client template
│ ├── smart-account-setup.ts # Smart account template
│ └── grid-client.ts # Grid API client template
└── docs/
└── troubleshooting.md # Common issues and solutions