From 593ed88d1f113bd5e39f4eaf8dd24a773cfc5a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E6=B2=92code=20=E6=88=91=E6=B2=92code?= <135327579+ZouBadCode@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:25:35 +0800 Subject: [PATCH 1/3] feat: add new skill to bucket sdk --- skill/bucket-sdk/SKILL.md | 427 ++++++++++++++++++ skill/bucket-sdk/references/coin-types.md | 100 ++++ .../references/protocol-concepts.md | 342 ++++++++++++++ skill/bucket-sdk/scripts/query-state.ts | 112 +++++ 4 files changed, 981 insertions(+) create mode 100644 skill/bucket-sdk/SKILL.md create mode 100644 skill/bucket-sdk/references/coin-types.md create mode 100644 skill/bucket-sdk/references/protocol-concepts.md create mode 100644 skill/bucket-sdk/scripts/query-state.ts diff --git a/skill/bucket-sdk/SKILL.md b/skill/bucket-sdk/SKILL.md new file mode 100644 index 0000000..cfb2cca --- /dev/null +++ b/skill/bucket-sdk/SKILL.md @@ -0,0 +1,427 @@ +--- +name: bucket-sdk +description: Use when integrating with Bucket Protocol on Sui blockchain — building CDP transactions, PSM swaps, saving pool deposits/withdrawals, oracle price queries, flash mints, or querying vault and position data. Also use when the user wants to mint/repay USDB stablecoin, manage collateralized debt positions, swap stablecoins via PSM, or earn yield in Bucket saving pools. Trigger whenever someone needs to use @bucket-protocol/sdk as a dependency. +--- + +# Bucket Protocol SDK — Integration Guide + +`@bucket-protocol/sdk` is a TypeScript SDK for [Bucket Protocol](https://bucketprotocol.io), a CDP-based stablecoin protocol on Sui purpose-built for capital efficiency. Users deposit supported on-chain assets as collateral to borrow **USDB** (a decentralized, over-collateralized stablecoin pegged to $1 USD). The SDK lets you query on-chain state and build Programmable Transaction Blocks (PTBs) for CDPs, saving pools (sUSDB + BSR yield), PSM stablecoin swaps, flash mints, oracle price feeds, and one-click leverage. + +**Official docs**: + +## Installation + +```bash +npm install @bucket-protocol/sdk @mysten/sui @mysten/bcs +# or +pnpm add @bucket-protocol/sdk @mysten/sui @mysten/bcs +``` + +Peer dependencies: `@mysten/sui >=2.0.0`, `@mysten/bcs >=2.0.0`. + +## Quick Start + +```typescript +import { BucketClient, coinWithBalance } from '@bucket-protocol/sdk'; +import { Transaction } from '@mysten/sui/transactions'; + +// 1. Initialize (fetches config from chain automatically) +const client = await BucketClient.initialize({ network: 'mainnet' }); + +// 2. Build a transaction +const tx = new Transaction(); +const [, usdbCoin] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + depositCoinOrAmount: 1_000_000_000, // 1 SUI (9 decimals) + borrowAmount: 800_000, // 0.8 USDB (6 decimals) +}); +tx.transferObjects([usdbCoin], myAddress); + +// 3. Sign and execute (with your own signer) +await suiClient.signAndExecuteTransaction({ transaction: tx, signer }); +``` + +## Initialization + +```typescript +import { BucketClient } from '@bucket-protocol/sdk'; +// Custom RPC endpoint +import { SuiGrpcClient } from '@mysten/sui/grpc'; + +// Recommended: initialize() waits for config to be ready +const client = await BucketClient.initialize({ network: 'mainnet' }); + +const suiClient = new SuiGrpcClient({ network: 'mainnet', baseUrl: 'https://my-rpc.example.com' }); +const client = await BucketClient.initialize({ suiClient, network: 'mainnet' }); + +// Override specific config (e.g. Pyth Hermes endpoint) +const client = await BucketClient.initialize({ + network: 'mainnet', + configOverrides: { PRICE_SERVICE_ENDPOINT: 'https://custom-hermes.example.com' }, +}); + +// Alternative: sync constructor (config loads in background) +const client = new BucketClient({ network: 'mainnet' }); +await client.getConfig(); // wait before config-dependent methods +``` + +`initialize()` reads on-chain config objects to resolve all package IDs, vault/pool/aggregator shared object refs, and Pyth settings. If using `new BucketClient(...)`, treat config-dependent methods as async and call them with `await`. Call `client.refreshConfig()` later to pick up protocol upgrades without re-creating the client. + +## Key Concepts + +### PTB Builders — Build, Don't Execute + +All write operations return PTB commands, not executed transactions. Methods prefixed `build*` take a `Transaction` object and append Move calls. You sign and execute separately. This lets you compose multiple SDK calls into a single atomic transaction. + +### `coinWithBalance` — Automatic Coin Merging + +Pass raw amounts instead of coin objects. The SDK auto-fetches user coins, merges them, and splits the needed amount at `tx.build()` time: + +```typescript +import { coinWithBalance } from '@bucket-protocol/sdk'; + +// These are equivalent: +await client.buildPSMSwapInTransaction(tx, { + coinType: usdcType, + inputCoinOrAmount: 1_000_000, // pass number directly +}); +await client.buildPSMSwapInTransaction(tx, { + coinType: usdcType, + inputCoinOrAmount: coinWithBalance({ type: usdcType, balance: 1_000_000 }), // explicit factory +}); +``` + +### Decimals + +| Token | Decimals | 1 unit in raw | +| ----- | -------- | --------------- | +| SUI | 9 | `1_000_000_000` | +| USDB | 6 | `1_000_000` | +| USDC | 6 | `1_000_000` | +| BTC | 8 | `100_000_000` | + +Always pass amounts in raw (smallest unit). The SDK does not auto-scale. + +### Account vs EOA + +Bucket supports `Account` objects that hold positions on behalf of a wallet. Most builder methods accept an optional `accountObjectOrId` parameter: + +- **Omit** → operates on the wallet address directly (EOA mode) +- **Pass Account object ID** → operates on that Account's positions + +## API Reference + +### Querying On-Chain Data + +All query methods are `async` and read-only — no transaction needed. + +```typescript +// Protocol-level data +const supply = await client.getUsdbSupply(); // bigint +const prices = await client.getOraclePrices({ coinTypes: [SUI_TYPE_ARG] }); // Record +const allPrices = await client.getAllOraclePrices(); // all supported coins + +// Vault data +const vaults = await client.getAllVaultObjects(); // Record +const collateralTypes = await client.getAllCollateralTypes(); // string[] + +// Saving pool data +const pools = await client.getAllSavingPoolObjects(); // Record + +// PSM pool data +const psmPools = await client.getAllPsmPoolObjects(); // Record + +// Flash mint info +const flash = await client.getFlashMintInfo(); // { feeRate, partner } + +// User-specific data +const positions = await client.getUserPositions({ address }); // PositionInfo[] +const savings = await client.getUserSavings({ address }); // SavingInfo[] +const accounts = await client.getUserAccounts({ address }); // Account[] + +// Paginated position listing by collateral +const { positions, nextCursor } = await client.getAllPositions({ + coinType: SUI_TYPE_ARG, + pageSize: 50, + cursor: null, +}); + +// Reward queries +const borrowRewards = await client.getAccountBorrowRewards({ + address, + coinTypes: [SUI_TYPE_ARG], +}); // Record> + +const savingRewards = await client.getAccountSavingPoolRewards({ + address, + lpTypes: [susdbLpType], +}); // Record> +``` + +### Building Transactions + +#### CDP — Manage Collateralized Debt Positions + +```typescript +const tx = new Transaction(); + +// Deposit collateral + borrow USDB +const [collateralCoin, usdbCoin] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + depositCoinOrAmount: 2_000_000_000, // 2 SUI + borrowAmount: 1_000_000, // 1 USDB +}); +tx.transferObjects([usdbCoin], myAddress); + +// Repay debt (partial or full) +await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + repayCoinOrAmount: 500_000, // 0.5 USDB +}); + +// Withdraw collateral (requires sufficient CR) +const [withdrawnCoin] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + withdrawAmount: 500_000_000, // 0.5 SUI +}); +tx.transferObjects([withdrawnCoin], myAddress); + +// Close position entirely — repays all debt, returns all collateral +const [allCollateral] = await client.buildClosePositionTransaction(tx, { + address: myAddress, + coinType: '0x2::sui::SUI', +}); +tx.transferObjects([allCollateral], myAddress); + +// Claim borrow incentive rewards +const rewards = await client.buildClaimBorrowRewardsTransaction(tx, { + coinType: '0x2::sui::SUI', +}); +// rewards: Record +Object.values(rewards).forEach((coin) => tx.transferObjects([coin], myAddress)); +``` + +**Price is auto-fetched**: `buildManagePositionTransaction` calls `aggregatePrices` internally when `borrowAmount > 0` or `withdrawAmount > 0`. Deposit-only or repay-only operations skip the oracle call. + +#### Saving Pools — Two Layers of USDB Yield + +Bucket's saving system has **two layers**: + +- **Layer 1 — sUSDB (BSR)**: Stake USDB → receive sUSDB. Value appreciates via the Base Savings Rate (BSR) through an increasing exchange rate. `minted_sUSDB = staked_USDB / exchange_rate`. +- **Layer 2 — sUSDB Savings Pool**: Deposit sUSDB → earn additional SUI rewards on top of BSR. Total APR = BSR + SUI rewards APR. + +No stake/unstake fee. No lockup. + +```typescript +const tx = new Transaction(); + +// Deposit USDB +await client.buildDepositToSavingPoolTransaction(tx, { + address: myAddress, + lpType: susdbLpType, // saving pool LP type + depositCoinOrAmount: 1_000_000, // 1 USDB +}); + +// Withdraw USDB +const usdbCoin = await client.buildWithdrawFromSavingPoolTransaction(tx, { + lpType: susdbLpType, + amount: 500_000, +}); +tx.transferObjects([usdbCoin], myAddress); + +// Claim saving pool rewards +const rewards = await client.buildClaimSavingRewardsTransaction(tx, { + lpType: susdbLpType, +}); +Object.values(rewards).forEach((coin) => tx.transferObjects([coin], myAddress)); +``` + +#### PSM — Peg Stability Module Swaps + +```typescript +const tx = new Transaction(); + +// Swap USDC → USDB +const usdbCoin = await client.buildPSMSwapInTransaction(tx, { + coinType: usdcType, + inputCoinOrAmount: 1_000_000, // 1 USDC +}); +tx.transferObjects([usdbCoin], myAddress); + +// Swap USDB → USDC +const usdcCoin = await client.buildPSMSwapOutTransaction(tx, { + coinType: usdcType, + usdbCoinOrAmount: 1_000_000, // 1 USDB +}); +tx.transferObjects([usdcCoin], myAddress); +``` + +#### Flash Mint — Borrow USDB Within a Single Transaction + +```typescript +const tx = new Transaction(); + +// Mint USDB (must be burned in the same tx) +const [usdbCoin, receipt] = await client.flashMint(tx, { amount: 10_000_000 }); + +// ... use usdbCoin for arbitrage, liquidation, etc. ... + +// Burn (repay) — must include the fee +await client.flashBurn(tx, { usdbCoin: remainingUsdb, flashMintReceipt: receipt }); +``` + +### Composing Multiple Operations + +A key strength of PTBs is atomic composition. You can chain SDK calls in one transaction: + +```typescript +const tx = new Transaction(); + +// 1. Swap USDC to USDB +const usdbCoin = await client.buildPSMSwapInTransaction(tx, { + coinType: usdcType, + inputCoinOrAmount: 1_000_000, +}); + +// 2. Deposit the USDB into a saving pool +await client.buildDepositToSavingPoolTransaction(tx, { + address: myAddress, + lpType: susdbLpType, + depositCoinOrAmount: usdbCoin, // pass TransactionResult directly +}); +``` + +#### Leverage via Flash Mint (One-Click Leverage Pattern) + +Bucket supports leveraged positions using flash mints. The one-click flow: + +1. Flash-mint USDB +2. Swap flash-minted USDB → target collateral (via DEX) +3. Deposit all collateral → borrow USDB +4. Repay flash mint with borrowed USDB + +```typescript +const tx = new Transaction(); + +// 1. Flash mint USDB for the leverage amount +const [flashUsdb, receipt] = await client.flashMint(tx, { amount: leverageUsdbAmount }); + +// 2. Swap USDB → SUI via external DEX aggregator (e.g. Cetus) +// ... (DEX swap calls — not part of Bucket SDK) ... + +// 3. Deposit all SUI as collateral, borrow USDB to repay flash +const [, borrowedUsdb] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + depositCoinOrAmount: totalSuiCoin, + borrowAmount: leverageUsdbAmount + flashFee, +}); + +// 4. Repay flash mint +await client.flashBurn(tx, { usdbCoin: borrowedUsdb, flashMintReceipt: receipt }); +``` + +### Low-Level PTB Helpers + +For advanced use cases, the building blocks behind `build*` methods are also public. These helpers are async in the latest SDK, so call them with `await`: + +- **Price**: `aggregateBasicPrices(tx, { coinTypes })` (Pyth-only feeds), `aggregatePrices(tx, { coinTypes })` (all feeds incl. derivatives) → `TransactionResult[]` +- **CDP internals**: `debtorRequest()` → `checkUpdatePositionRequest()` → `updatePosition()` → `checkUpdatePositionResponse()` +- **Saving pool calls**: `savingPoolDeposit()`, `savingPoolWithdraw()`, `checkDepositResponse()`, `checkWithdrawResponse()`, `claimPoolIncentive()` +- **PSM calls**: `psmSwapIn()`, `psmSwapOut()` +- **Object refs**: `treasury(tx)`, `vault(tx, { coinType })`, `aggregator(tx, { coinType })`, `savingPoolObj(tx, { lpType })`, `psmPoolObj(tx, { coinType })`, `vaultRewarderRegistry(tx)`, `savingPoolGlobalConfig(tx)`, `flashGlobalConfig(tx)` +- **Account helpers**: `accountAddress(tx, { address, accountObjectOrId })`, `newAccountRequest(tx, { address, accountObjectOrId })`, `newPriceCollector(tx, { coinType })` + +## Key Types + +```typescript +// Vault info — returned by getAllVaultObjects() +type VaultInfo = { + collateralType: string; + collateralDecimal: number; + collateralBalance: bigint; + usdbSupply: bigint; + maxUsdbSupply: bigint; + minCollateralRatio: number; // e.g. 1.1 = 110% + interestRate: number; + positionTableSize: number; + rewardRate: Record; +}; + +// User position — returned by getUserPositions() +type PositionInfo = { + collateralType: string; + collateralAmount: bigint; + debtAmount: bigint; + debtor: string; + accountId?: string; + rewards?: Record; +}; + +// Saving pool info — returned by getAllSavingPoolObjects() +type SavingPoolInfo = { + lpType: string; + lpSupply: bigint; + usdbBalance: bigint; + usdbDepositCap: bigint | null; + savingRate: number; + rewardRate: Record; +}; + +// PSM pool info — returned by getAllPsmPoolObjects() +type PsmPoolInfo = { + coinType: string; + decimal: number; + balance: bigint; + usdbSupply: bigint; + feeRate: { swapIn: number; swapOut: number }; + partnerFeeRate: Record; +}; + +// User saving — returned by getUserSavings() +type SavingInfo = { + lpType: string; + address: string; + accountId?: string; + usdbBalance: bigint; + lpBalance: bigint; + rewards: Record; +}; + +// Flash mint info — returned by getFlashMintInfo() +type FlashMintInfo = { + feeRate: number; + partner: Record; +}; +``` + +## Common Gotchas + +1. **Async migration**: many methods that were previously synchronous are now async in v2.1.0+ (`getConfig`, `getAllCollateralTypes`, `getUsdbCoinType`, object info getters, `buildClosePositionTransaction`, `buildClaimBorrowRewardsTransaction`, saving builders, flash methods, and low-level helpers like `debtorRequest` / `updatePosition`). Always use `await` for these calls. + +2. **Zero coin auto-cleanup**: When `borrowAmount` is 0, the returned USDB coin is a zero coin that gets auto-destroyed. Same for collateral when `withdrawAmount` is 0. You don't need to handle this. + +3. **Dry-run / simulation**: Use `suiClient.simulateTransaction({ transaction: tx })` to test without signing. Set `tx.setSender(address)` first. + +4. **Config refresh**: If the protocol upgrades, call `client.refreshConfig()` to re-fetch on-chain config. Overrides from `initialize()` are preserved automatically. + +5. **No borrow fee**: The protocol has **no** one-time borrow fee (removed in the v2 upgrade). Only fixed per-asset interest rates apply. Interest accrues in real time and is added to debt continuously. + +6. **Mint caps**: Each vault has a max USDB supply (`VaultInfo.maxUsdbSupply`). Borrowing beyond this cap will fail on-chain. + +7. **Full liquidation**: When a position's CR drops below MCR, **all collateral is seized** (not partial). Liquidations are protocol-run. User loss ≈ `(MCR - 1) × Debt`. The SDK does not execute liquidations. + +8. **Repay with collateral**: The "repay with collateral" feature (selling collateral to repay debt) is a UI-level feature that routes through on-chain DEXes. The base SDK provides `buildManagePositionTransaction` with `repayCoinOrAmount` for repaying with USDB you already hold. + +9. **sUSDB exchange rate**: sUSDB appreciates vs USDB over time via BSR. When withdrawing, users receive more USDB per sUSDB than they deposited. The exchange rate only increases. + +## Bundled Resources + +This skill includes additional reference files. Consult them when you need detailed data: + +| Resource | Path | When to use | +| ---------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| **Coin Types** | `references/coin-types.md` | Need the full `0x...` type string for a specific token (collateral, PSM, LP, reward) | +| **Protocol Concepts** | `references/protocol-concepts.md` | Need to understand CDP mechanics, PSM vs CDP decision, saving pool yield, flash mints, Account vs EOA, or oracle pricing | +| **Query State Script** | `scripts/query-state.ts` | Need to inspect live on-chain state (vault stats, prices, pool balances). Run with `npx tsx skills/bucket-sdk/scripts/query-state.ts` | + + diff --git a/skill/bucket-sdk/references/coin-types.md b/skill/bucket-sdk/references/coin-types.md new file mode 100644 index 0000000..1217cbd --- /dev/null +++ b/skill/bucket-sdk/references/coin-types.md @@ -0,0 +1,100 @@ +# Bucket Protocol — Supported Coin Types (Mainnet) + +This file lists all coin types supported by Bucket Protocol on Sui mainnet. Use these exact strings when calling SDK methods like `buildManagePositionTransaction`, `buildPSMSwapInTransaction`, etc. + +> **Note**: Coin types may change as the protocol adds or removes support. Call `await client.getAllCollateralTypes()`, `await client.getAllOracleCoinTypes()`, or inspect `await client.getConfig()` for the live list. + +## USDB (Bucket's Stablecoin) + +| Token | Coin Type | Decimals | +| ----- | -------------------------------------------------------------------------------- | -------- | +| USDB | `0xe14726c336e81b32328e92afc37345d159f5b550b09fa92bd43640cfdd0a0cfd::usdb::USDB` | 6 | + +Get it programmatically with `await client.getUsdbCoinType()`. + +## Basic Collateral (Direct Pyth Price Feed) + +These tokens have a direct Pyth oracle price. They can be used as CDP collateral and are supported by `aggregateBasicPrices()`. + +| Token | Coin Type | Decimals | Notes | +| ------ | ------------------------------------------------------------------------------------ | -------- | -------------------- | +| SUI | `0x2::sui::SUI` | 9 | Native gas token | +| BTC | `0xaafb102dd0902f5055cadecd687fb5b71ca82ef0e0285d90afde828ec58ca96b::btc::BTC` | 8 | | +| ETH | `0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH` | 8 | | +| WAL | `0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL` | 9 | Walrus token | +| USDC | `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC` | 6 | | +| USDT | `0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT` | 6 | | +| haSUI | `0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI` | 9 | Haedal staked SUI | +| CERT | `0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT` | 9 | Volo staked SUI | +| afSUI | `0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI` | 9 | Aftermath staked SUI | +| SCA | `0x7016aae72cfc67f2fadf55769c0a7dd54291a583b63051a5ed71081cce836ac6::sca::SCA` | 9 | Scallop token | +| BUCK | `0xce7ff77a83ea0cb6fd39bd8748e2ec89a3f41e8efdc3f4eb123e0ca37b184db2::buck::BUCK` | 9 | Bucket V1 stablecoin | +| DEEP | `0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP` | 6 | DeepBook token | +| XBTC | `0x876a4b7bce8aeaef60464c11f4026903e9afacab79b9b142686158aa86560b50::xbtc::XBTC` | 8 | | +| WBTC | `0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC` | 8 | | +| UP_USD | `0x5de877a152233bdd59c7269e2b710376ca271671e9dd11076b1ff261b2fd113c::up_usd::UP_USD` | 6 | Unihouse USD | +| XAUM | `0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM` | 6 | Tokenized gold | + +## Derivative Collateral (Price from Underlying) + +These tokens derive their price from a basic token via an exchange rate (Scallop sCoin, Unihouse gCoin, or BFBTC). The SDK handles this automatically in `aggregatePrices()` — you don't need to treat them differently from basic collateral when using `build*` methods. + +### sCoin (Scallop Lending Receipts) — derivative_kind: `sCoin` + +| Token | Coin Type | Underlying | +| ----- | ------------------------------------------------------------------------------------------------------ | ---------- | +| sSUI | `0xaafc4f740de0dd0dde642a31148fb94517087052f19afb0f7bed1dc41a50c77b::scallop_sui::SCALLOP_SUI` | SUI | +| sUSDC | `0x854950aa624b1df59fe64e630b2ba7c550642e9342267a33061d59fb31582da5::scallop_usdc::SCALLOP_USDC` | USDC | +| sUSDT | `0xb1d7df34829d1513b73ba17cb7ad90c88d1e104bb65ab8f62f13e0cc103783d3::scallop_sb_usdt::SCALLOP_SB_USDT` | USDT | +| sWAL | `0x622345b3f80ea5947567760eec7b9639d0582adcfd6ab9fccb85437aeda7c0d0::scallop_wal::SCALLOP_WAL` | WAL | +| sDEEP | `0xeb7a05a3224837c5e5503575aed0be73c091d1ce5e43aa3c3e716e0ae614608f::scallop_deep::SCALLOP_DEEP` | DEEP | +| sETH | `0xb14f82d8506d139eacef109688d1b71e7236bcce9b2c0ad526abcd6aa5be7de0::scallop_sb_eth::SCALLOP_SB_ETH` | ETH | +| sSCA | `0x5ca17430c1d046fae9edeaa8fd76c7b4193a00d764a0ecfa9418d733ad27bc1e::scallop_sca::SCALLOP_SCA` | SCA | + +### gCoin (Unihouse Staked House Coins) — derivative_kind: `gCoin` + +| Token | Coin Type | Underlying | +| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| gSUI | `0x2f2226a22ebeb7a0e63ea39551829b238589d981d1c6dd454f01fcc513035593::house::StakedHouseCoin<0x2::sui::SUI>` | SUI | +| gUP_USD | `0x2f2226a22ebeb7a0e63ea39551829b238589d981d1c6dd454f01fcc513035593::house::StakedHouseCoin<0x5de877a152233bdd59c7269e2b710376ca271671e9dd11076b1ff261b2fd113c::up_usd::UP_USD>` | UP_USD | + +### BFBTC — derivative_kind: `BFBTC` + +| Token | Coin Type | Underlying | +| ----- | ---------------------------------------------------------------------------------- | ---------- | +| BFBTC | `0x7438e8caf5c345fbd3772517380bf0ca432f53892dee65ee0dda3eb127993cd9::bfbtc::BFBTC` | BTC | + +## PSM Pool Coins + +These coins can be swapped 1:1 with USDB via `buildPSMSwapInTransaction` / `buildPSMSwapOutTransaction`: + +| Token | Coin Type | Decimals | +| ----- | -------------------------------------------------------------------------------- | -------- | +| USDC | `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC` | 6 | +| USDT | `0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT` | 6 | +| BUCK | `0xce7ff77a83ea0cb6fd39bd8748e2ec89a3f41e8efdc3f4eb123e0ca37b184db2::buck::BUCK` | 9 | + +## Saving Pool LP Types + +Pass these as the `lpType` parameter to saving pool methods (`buildDepositToSavingPoolTransaction`, etc.): + +| Token | LP Type | +| ----- | ---------------------------------------------------------------------------------- | +| sUSDB | `0x38f61c75fa8407140294c84167dd57684580b55c3066883b48dedc344b1cde1e::susdb::SUSDB` | + +## Common Reward Types + +These appear as keys in borrow/saving reward records: + +| Token | Coin Type | +| ----- | -------------------------------------------------------------------------------- | +| SUI | `0x2::sui::SUI` | +| SCA | `0x7016aae72cfc67f2fadf55769c0a7dd54291a583b63051a5ed71081cce836ac6::sca::SCA` | +| DEEP | `0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP` | +| XAUM | `0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM` | + +## Protocol Token + +| Token | Coin Type | Decimals | Notes | +| ----- | ------------------------------------------------------------------------------ | -------- | ------------------------------------------ | +| BUT | `0xbc858cb910b9914bee64fff0f9b38855355a040c49155a17b265d9086d256545::but::BUT` | 9 | Native protocol token; stakeable for deBUT | diff --git a/skill/bucket-sdk/references/protocol-concepts.md b/skill/bucket-sdk/references/protocol-concepts.md new file mode 100644 index 0000000..61745bb --- /dev/null +++ b/skill/bucket-sdk/references/protocol-concepts.md @@ -0,0 +1,342 @@ +# Bucket Protocol — Concepts & Decision Guide + +This document explains the core protocol concepts an agent needs to understand to make correct integration decisions. + +**Official docs**: + +## What is Bucket Protocol? + +Bucket Protocol is a **CDP-based stablecoin protocol on Sui, purpose-built for capital efficiency**. Users deposit supported on-chain assets as collateral to borrow **USDB**, a decentralized, over-collateralized stablecoin pegged to $1 USD. + +USDB serves two user needs: + +- **Volatile-asset holders** borrow USDB against collateral for long-term leverage or liquidity without selling core positions. +- **Stablecoin allocators** hold USDB and deposit into the sUSDB Savings Pool for competitive, flexible yield. + +### Key Advantages + +- **Fixed per-asset interest rates** — funding costs known upfront, no variable rate anxiety +- **High LTV** — per-asset CDP isolation enables more usable capital +- **Explicit risk boundaries** — simple CR/MCR rule with live liquidation price; no Recovery Mode +- **No one-time borrow fee** — only fixed interest rates apply +- **Derivative collateral support** — LSTs, sCoins, gCoins can be used as collateral + +## CDP (Collateralized Debt Positions) + +### How It Works + +1. User deposits collateral (e.g. SUI, BTC, ETH) into a vault +2. User borrows USDB against that collateral +3. The position must maintain a **minimum collateral ratio** (MCR) — typically 110% +4. Interest accrues on the debt over time +5. User can repay debt and/or withdraw collateral at any time (within CR constraints) + +### Collateral Ratio (CR) & Liquidation Price + +``` +CR = (Collateral Price × Collateral Amount) / (initial Borrow Amount + Accrued Interest) +``` + +Each collateral has a fixed **Minimum Collateral Ratio (MCR)** (e.g. 110%). If CR < MCR, the position is liquidatable. + +``` +Liquidation Price = (MCR × Debt) / Collateral Amount +``` + +**Example**: 1,000 SUI at $5/SUI ($5,000 collateral), borrow 4,000 USDB, MCR = 110% + +- Entry CR = 5,000 / 4,000 = 125% +- Liquidation Price = (1.10 × 4,000) / 1,000 = $4.40/SUI + +> After every action, the position must satisfy CR ≥ MCR. + +### When to Use Which CDP Method + +| Goal | Method | Needs Price? | +| -------------------------- | ----------------------------------------------------------------------- | :----------: | +| Deposit collateral only | `buildManagePositionTransaction({ depositCoinOrAmount })` | No | +| Borrow USDB | `buildManagePositionTransaction({ borrowAmount })` | Yes (auto) | +| Repay debt | `buildManagePositionTransaction({ repayCoinOrAmount })` | No | +| Withdraw collateral | `buildManagePositionTransaction({ withdrawAmount })` | Yes (auto) | +| Deposit + borrow in one tx | `buildManagePositionTransaction({ depositCoinOrAmount, borrowAmount })` | Yes (auto) | +| Close entire position | `buildClosePositionTransaction()` | No | +| Claim borrow incentives | `buildClaimBorrowRewardsTransaction()` | No | + +`buildManagePositionTransaction` is the all-in-one method. You can combine any of deposit/borrow/repay/withdraw in a single call. It handles zero-coin cleanup automatically. + +### Fees & Interest + +- **No one-time borrow fee** (removed in the v2 upgrade) +- **Fixed borrow interest rate** per collateral type (visible in `VaultInfo.interestRate`) +- Interest accrues in real time and is added to debt continuously +- Rates are protocol-set and not user-adjustable + +### Mint Caps + +Each vault has a maximum USDB supply (`VaultInfo.maxUsdbSupply`). Borrowing beyond this cap will fail on-chain. Mint caps help manage market depth during liquidations and reduce slippage risk in extreme conditions. + +### Liquidation + +- **Trigger**: CR < MCR → position becomes liquidatable +- **Scope**: **Full seizure** — ALL collateral in that CDP is taken +- **Executor**: Liquidations are protocol-run (not by users) + +**How liquidation is executed on-chain:** + +1. Flash-mint USDB to immediately repay the CDP's outstanding debt +2. Seize all collateral from the liquidated CDP +3. Sell the seized collateral for USDB using on-chain venues +4. Repay the flash-minted USDB from step 1 + +**User loss**: At liquidation threshold, `User loss ≈ (MCR - 1) × Debt`. The user keeps the USDB previously borrowed. + +**Bad-debt backstop**: If collateral proceeds < debt, the protocol's Insurance Fund (funded from protocol revenue) covers the gap. + +**Avoiding liquidation**: Deposit more collateral or repay part of the debt to raise CR. + +> The SDK does **not** execute liquidations — it only builds position management transactions. + +## USDB Peg Mechanism + +USDB targets $1 USD via two mechanisms: + +### Peg Stability Module (PSM) + +The PSM enables trustless 1:1 conversions between USDB and supported stablecoins (USDC, USDT, BUCK), subject to a PSM fee. + +- **Swap In**: Stablecoin → USDB (e.g. deposit 1 USDC, receive ~1 USDB minus fee) +- **Swap Out**: USDB → Stablecoin (e.g. deposit 1 USDB, receive ~1 USDC minus fee) + +Each PSM pool has `swapIn` and `swapOut` fee rates (visible in `PsmPoolInfo.feeRate`). Partner accounts may get lower fees via `partnerFeeRate`. + +### Price Stability & Arbitrage + +Let `price_usdb` = USDB market price on DEX, `fee_in` = PSM IN fee, `fee_out` = PSM OUT fee. + +**Upward depeg (USDB > $1)**: Acquire USDB via PSM IN at ~$1, sell on market at `price_usdb > 1`. Profitable when `price_usdb > 1 + fee_in + gas`. + +**Downward depeg (USDB < $1)**: Buy USDB on market at `price_usdb < 1`, exit via PSM OUT at ~$1. Profitable when `price_usdb < 1 - fee_out - gas`. + +**Flash-mint assisted arbitrage**: For capital efficiency, use flash mint to source/retire USDB within one transaction, pairing the opposite leg through PSM or market liquidity. + +### When to Use PSM vs CDP + +| Scenario | Use PSM | Use CDP | +| ------------------------------- | :-----: | :-----: | +| Quickly get USDB from USDC/USDT | ✓ | | +| Convert USDB back to USDC/USDT | ✓ | | +| Leverage crypto exposure | | ✓ | +| Earn borrow incentive rewards | | ✓ | +| Long-term USDB generation | | ✓ | +| Arbitrage USDB peg on DEX | ✓ | | + +## Saving System — Two Layers of USDB Yield + +Bucket provides two layers of yield for USDB holders. Total APR = BSR + SUI rewards APR. + +### Layer 1: sUSDB and BSR (Base Savings Rate) + +- **BSR** is Bucket’s fixed savings rate for USDB. It accrues in real time by increasing the exchange rate between sUSDB and USDB. +- **sUSDB** is the yield-bearing stablecoin you receive when you stake USDB. Yield does not change your sUSDB balance; instead, each unit of sUSDB represents more USDB over time. + +**Formulas**: + +``` +minted_sUSDB = staked_USDB / exchange_rate +unstaked_USDB = sUSDB_balance × exchange_rate +``` + +- No stake or unstake fee. No lockup. +- Balances and the exchange rate update in real time. + +### Layer 2: sUSDB Savings Pool + +- Deposit sUSDB into the sUSDB Savings Pool to earn **additional SUI rewards** on top of BSR. +- Savings rewards accrue continuously and are claimable at any time. +- Withdraw whenever — no fees, no lockup. + +### Key Parameters + +- `savingRate`: BSR yield rate (exchange rate growth) +- `rewardRate`: Additional token incentive rates (per reward type, e.g. SUI) +- `usdbDepositCap`: Maximum total USDB the pool accepts (null = no cap) +- `lpSupply`: Total sUSDB LP tokens outstanding + +### SDK Methods + +| Goal | Method | +| --------------------------------------------- | ------------------------------------------ | +| Deposit USDB → get sUSDB → earn BSR + rewards | `buildDepositToSavingPoolTransaction()` | +| Withdraw sUSDB → receive USDB | `buildWithdrawFromSavingPoolTransaction()` | +| Claim SUI rewards from savings pool | `buildClaimSavingRewardsTransaction()` | + +## Flash Mint + +### How It Works + +Flash minting allows borrowing USDB **without collateral** within a single atomic transaction. The borrowed USDB must be repaid (plus fee) before the transaction completes, or the entire transaction reverts. + +### Use Cases + +- Arbitrage between USDB price on DEXes +- Self-liquidation or position restructuring +- Leveraged operations composed in a single PTB + +### Fee + +A small fee rate applies (visible in `FlashMintInfo.feeRate`). The repayment must cover principal + fee. + +```typescript +const [usdbCoin, receipt] = await client.flashMint(tx, { amount: 10_000_000 }); +// ... do things with usdbCoin (arbitrage, etc.) ... +// Must return principal + fee: +await client.flashBurn(tx, { usdbCoin, flashMintReceipt: receipt }); +``` + +## Leverage + +Bucket supports two ways to build a leveraged long on supported assets: + +### One-Click Leverage (SUI/LST, Wrapped BTC) + +Uses flash minting to automatically create a leveraged position in one transaction: + +1. User deposits initial capital (e.g. 100 USDC) +2. Flash-mints USDB worth the leverage amount +3. Swaps initial capital + flash-minted USDB for target collateral (via Cetus aggregator) +4. Deposits all as collateral → borrows USDB +5. Repays the flash-mint with borrowed USDB + +**Result**: Leveraged position established atomically. Costs shown: flash-loan fee + price impact. + +### Manual Looping (All Collaterals) + +For assets without one-click support: + +1. Deposit collateral → Borrow USDB +2. Swap USDB → more collateral (via DEX) +3. Deposit the new collateral +4. Repeat until desired leverage + +### De-Leveraging + +To reduce leverage or raise CR: + +- **Repay with collateral**: sell portion of collateral into USDB to repay debt (atomically via DEX routing) +- **Repay with USDB**: repay from USDB in wallet +- After repayment, CR rises and liquidation price moves lower (safer) + +## Account System + +### EOA vs Account Objects + +Bucket supports two modes for holding positions: + +- **EOA (Externally Owned Account)**: Positions are tied directly to the wallet address. This is the default when `accountObjectOrId` is omitted. +- **Account Object**: A Sui on-chain object (`Account`) that holds positions on behalf of the owner. Useful for managing multiple independent positions from one wallet, or for protocol-level integrations. + +### When to Use Account Objects + +- Most integrations should **omit** `accountObjectOrId` and operate in EOA mode +- Use Account objects when: the user has existing Account-based positions (check with `getUserAccounts()`), or the integration needs separate position management + +### Checking for Existing Accounts + +```typescript +const accounts = await client.getUserAccounts({ address: walletAddress }); +// accounts is an array of Account objects +// If empty, the user only has EOA positions +``` + +## Oracle Price System + +### How Prices Work + +Bucket uses **Pyth Network** as its oracle. The SDK handles price feeds automatically: + +1. Fetches latest price data (VAA) from Pyth's Hermes REST API +2. Builds on-chain Wormhole verification + Pyth update calls +3. Passes the verified price to CDP/PSM operations + +### Basic vs Derivative Prices + +- **Basic**: Direct Pyth feed (SUI, BTC, ETH, USDC, etc.) +- **Derivative**: Price derived from basic price × exchange rate + - **sCoin** (Scallop): sSUI price = SUI price × Scallop exchange rate + - **gCoin** (Unihouse): gSUI price = SUI price × Unihouse exchange rate + - **BFBTC**: BFBTC price = BTC price × BFBTC exchange rate + +`aggregatePrices()` handles both basic and derivative prices transparently. The `build*` methods that need prices (borrow, withdraw, PSM swap) call it internally. + +### Querying Prices Without a Transaction + +```typescript +// Get live prices (simulates a PTB internally) +const prices = await client.getOraclePrices({ coinTypes: ['0x2::sui::SUI'] }); +console.log(prices['0x2::sui::SUI']); // e.g. 3.45 (USD) + +// Get all supported prices +const allPrices = await client.getAllOraclePrices(); +``` + +## Composing Operations in a Transaction + +Sui's PTB model allows combining multiple operations atomically. Common patterns: + +### Pattern 1: PSM → Saving (get USDB then earn yield) + +```typescript +const tx = new Transaction(); +const usdb = await client.buildPSMSwapInTransaction(tx, { + coinType: usdcType, + inputCoinOrAmount: 1_000_000, +}); +await client.buildDepositToSavingPoolTransaction(tx, { + address: myAddress, + lpType: susdbLpType, + depositCoinOrAmount: usdb, +}); +``` + +### Pattern 2: Borrow → PSM out (borrow USDB then convert to USDC) + +```typescript +const tx = new Transaction(); +const [, usdb] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + depositCoinOrAmount: 2_000_000_000, + borrowAmount: 1_000_000, +}); +const usdc = await client.buildPSMSwapOutTransaction(tx, { + coinType: usdcType, + usdbCoinOrAmount: usdb, +}); +tx.transferObjects([usdc], myAddress); +``` + +### Pattern 3: Flash mint → Arbitrage → Repay + +```typescript +const tx = new Transaction(); +const [usdb, receipt] = await client.flashMint(tx, { amount: 10_000_000 }); +// ... use usdb for arbitrage on a DEX ... +await client.flashBurn(tx, { usdbCoin: usdbAfterArb, flashMintReceipt: receipt }); +``` + +### Pattern 4: One-Click Leverage (Flash Mint → Swap → Deposit → Borrow → Repay) + +```typescript +const tx = new Transaction(); +// 1. Flash mint USDB for leverage +const [flashUsdb, receipt] = await client.flashMint(tx, { amount: leverageAmount }); +// 2. Swap USDB → target collateral via DEX (not part of Bucket SDK) +// ... DEX swap calls ... +// 3. Deposit all collateral, borrow USDB to cover flash mint +const [, borrowedUsdb] = await client.buildManagePositionTransaction(tx, { + coinType: '0x2::sui::SUI', + depositCoinOrAmount: totalCollateralCoin, + borrowAmount: leverageAmount + flashFee, +}); +// 4. Repay flash mint +await client.flashBurn(tx, { usdbCoin: borrowedUsdb, flashMintReceipt: receipt }); +``` diff --git a/skill/bucket-sdk/scripts/query-state.ts b/skill/bucket-sdk/scripts/query-state.ts new file mode 100644 index 0000000..53d4391 --- /dev/null +++ b/skill/bucket-sdk/scripts/query-state.ts @@ -0,0 +1,112 @@ +/** + * Diagnostic script: query Bucket Protocol on-chain state. + * + * Usage (from project root, or any project that has @bucket-protocol/sdk installed): + * npx tsx skills/bucket-sdk/scripts/query-state.ts + * + * Requires: @bucket-protocol/sdk, @mysten/sui + * + * Prints a summary of: + * - USDB total supply + * - Oracle prices for all supported collateral + * - Vault stats (TVL, collateral ratio, interest rate, max supply) + * - PSM pool balances and fee rates + * - Saving pool stats (rate, deposit cap, LP supply) + * - Flash mint info (fee rate) + */ + +import { BucketClient } from '@bucket-protocol/sdk'; + +function printLine(message = '') { + process.stdout.write(`${message}\n`); +} + +function isDefined(value: T | null | undefined): value is T { + return value !== null && value !== undefined; +} + +async function main() { + printLine('Initializing BucketClient (mainnet)...'); + printLine(); + const client = await BucketClient.initialize({ network: 'mainnet' }); + + // --- USDB Supply --- + const supply = await client.getUsdbSupply(); + printLine(`USDB Total Supply: ${(Number(supply) / 1e6).toLocaleString()} USDB`); + printLine(); + + // --- Oracle Prices --- + printLine('=== Oracle Prices ==='); + const prices = await client.getAllOraclePrices(); + const sortedPrices = Object.entries(prices).sort(([, a], [, b]) => b - a); + for (const [coinType, price] of sortedPrices) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` ${shortName.padEnd(20)} $${price}`); + } + printLine(); + + // --- Vaults --- + printLine('=== Vaults ==='); + const vaults = await client.getAllVaultObjects(); + for (const [coinType, vault] of Object.entries(vaults)) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` [${shortName}]`); + printLine(` Min CR: ${vault.minCollateralRatio}`); + printLine(` Interest Rate: ${vault.interestRate}`); + printLine( + ` Max USDB: ${isDefined(vault.maxUsdbSupply) ? (Number(vault.maxUsdbSupply) / 1e6).toLocaleString() : 'unlimited'}`, + ); + printLine(` USDB Minted: ${(Number(vault.usdbSupply) / 1e6).toLocaleString()}`); + printLine(` Collateral: ${vault.collateralBalance}`); + printLine(` Positions: ${vault.positionTableSize}`); + } + printLine(); + + // --- PSM Pools --- + printLine('=== PSM Pools ==='); + const psmPools = await client.getAllPsmPoolObjects(); + for (const [coinType, pool] of Object.entries(psmPools)) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` [${shortName}]`); + printLine(` Balance: ${pool.balance}`); + printLine(` Swap-In Fee: ${pool.feeRate.swapIn}`); + printLine(` Swap-Out Fee:${pool.feeRate.swapOut}`); + } + printLine(); + + // --- Saving Pools --- + printLine('=== Saving Pools ==='); + const savingPools = await client.getAllSavingPoolObjects(); + for (const [lpType, pool] of Object.entries(savingPools)) { + const shortName = lpType.split('::').pop() ?? lpType; + printLine(` [${shortName}]`); + printLine(` Saving Rate: ${pool.savingRate}`); + printLine(` LP Supply: ${pool.lpSupply}`); + printLine( + ` Deposit Cap: ${isDefined(pool.usdbDepositCap) ? (Number(pool.usdbDepositCap) / 1e6).toLocaleString() : 'none'}`, + ); + } + printLine(); + + // --- Flash Mint --- + printLine('=== Flash Mint ==='); + const flashMint = await client.getFlashMintInfo(); + printLine(` Fee Rate: ${flashMint.feeRate}`); + printLine(); + + // --- Supported Coin Types --- + printLine('=== Supported Collateral Types ==='); + const collTypes = await client.getAllCollateralTypes(); + for (const ct of collTypes) { + const shortName = ct.split('::').pop() ?? ct; + printLine(` ${shortName}`); + } + printLine(); + + printLine('Done.'); +} + +main().catch((err) => { + console.error('Error:', err); + process.exit(1); +}); From a20932f626008f1ab044ada624f1b60e8f3da5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E6=B2=92code=20=E6=88=91=E6=B2=92code?= <135327579+ZouBadCode@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:34:55 +0800 Subject: [PATCH 2/3] feat: update documentation for SDK integration and add query cheatsheet --- skill/bucket-sdk/SKILL.md | 470 ++++-------------- skill/bucket-sdk/references/api-workflows.md | 122 +++++ skill/bucket-sdk/references/coin-types.md | 119 ++--- .../bucket-sdk/references/query-cheatsheet.md | 85 ++++ 4 files changed, 327 insertions(+), 469 deletions(-) create mode 100644 skill/bucket-sdk/references/api-workflows.md create mode 100644 skill/bucket-sdk/references/query-cheatsheet.md diff --git a/skill/bucket-sdk/SKILL.md b/skill/bucket-sdk/SKILL.md index cfb2cca..2528d14 100644 --- a/skill/bucket-sdk/SKILL.md +++ b/skill/bucket-sdk/SKILL.md @@ -1,427 +1,137 @@ --- name: bucket-sdk -description: Use when integrating with Bucket Protocol on Sui blockchain — building CDP transactions, PSM swaps, saving pool deposits/withdrawals, oracle price queries, flash mints, or querying vault and position data. Also use when the user wants to mint/repay USDB stablecoin, manage collateralized debt positions, swap stablecoins via PSM, or earn yield in Bucket saving pools. Trigger whenever someone needs to use @bucket-protocol/sdk as a dependency. +description: Use when integrating Bucket Protocol on Sui with @bucket-protocol/sdk: CDP position updates, USDB mint and repay, PSM swaps, saving pools, flash mint, oracle prices, and protocol state queries. --- -# Bucket Protocol SDK — Integration Guide +# Bucket SDK -`@bucket-protocol/sdk` is a TypeScript SDK for [Bucket Protocol](https://bucketprotocol.io), a CDP-based stablecoin protocol on Sui purpose-built for capital efficiency. Users deposit supported on-chain assets as collateral to borrow **USDB** (a decentralized, over-collateralized stablecoin pegged to $1 USD). The SDK lets you query on-chain state and build Programmable Transaction Blocks (PTBs) for CDPs, saving pools (sUSDB + BSR yield), PSM stablecoin swaps, flash mints, oracle price feeds, and one-click leverage. +Use this skill whenever the task touches `@bucket-protocol/sdk`. -**Official docs**: +Official docs: +- https://docs.bucketprotocol.io/ +- https://github.com/Bucket-Protocol/bucket-protocol-sdk -## Installation +## Trigger Scope -```bash -npm install @bucket-protocol/sdk @mysten/sui @mysten/bcs -# or -pnpm add @bucket-protocol/sdk @mysten/sui @mysten/bcs -``` - -Peer dependencies: `@mysten/sui >=2.0.0`, `@mysten/bcs >=2.0.0`. - -## Quick Start - -```typescript -import { BucketClient, coinWithBalance } from '@bucket-protocol/sdk'; -import { Transaction } from '@mysten/sui/transactions'; +Use for: +- Building PTBs with `buildManagePositionTransaction`, `buildPSMSwapInTransaction`, saving pool builders, or flash mint. +- Querying collateral, pool, oracle, position, account, or reward data. +- Debugging Bucket integration issues (`Unsupported collateral type`, price feed issues, pool balance checks). -// 1. Initialize (fetches config from chain automatically) -const client = await BucketClient.initialize({ network: 'mainnet' }); +Do not use for: +- Generic Sui SDK tasks that do not involve Bucket Protocol. -// 2. Build a transaction -const tx = new Transaction(); -const [, usdbCoin] = await client.buildManagePositionTransaction(tx, { - coinType: '0x2::sui::SUI', - depositCoinOrAmount: 1_000_000_000, // 1 SUI (9 decimals) - borrowAmount: 800_000, // 0.8 USDB (6 decimals) -}); -tx.transferObjects([usdbCoin], myAddress); - -// 3. Sign and execute (with your own signer) -await suiClient.signAndExecuteTransaction({ transaction: tx, signer }); -``` +## Fast Workflow -## Initialization +1. Initialize client: -```typescript +```ts import { BucketClient } from '@bucket-protocol/sdk'; -// Custom RPC endpoint -import { SuiGrpcClient } from '@mysten/sui/grpc'; - -// Recommended: initialize() waits for config to be ready const client = await BucketClient.initialize({ network: 'mainnet' }); - -const suiClient = new SuiGrpcClient({ network: 'mainnet', baseUrl: 'https://my-rpc.example.com' }); -const client = await BucketClient.initialize({ suiClient, network: 'mainnet' }); - -// Override specific config (e.g. Pyth Hermes endpoint) -const client = await BucketClient.initialize({ - network: 'mainnet', - configOverrides: { PRICE_SERVICE_ENDPOINT: 'https://custom-hermes.example.com' }, -}); - -// Alternative: sync constructor (config loads in background) -const client = new BucketClient({ network: 'mainnet' }); -await client.getConfig(); // wait before config-dependent methods ``` -`initialize()` reads on-chain config objects to resolve all package IDs, vault/pool/aggregator shared object refs, and Pyth settings. If using `new BucketClient(...)`, treat config-dependent methods as async and call them with `await`. Call `client.refreshConfig()` later to pick up protocol upgrades without re-creating the client. - -## Key Concepts - -### PTB Builders — Build, Don't Execute - -All write operations return PTB commands, not executed transactions. Methods prefixed `build*` take a `Transaction` object and append Move calls. You sign and execute separately. This lets you compose multiple SDK calls into a single atomic transaction. - -### `coinWithBalance` — Automatic Coin Merging - -Pass raw amounts instead of coin objects. The SDK auto-fetches user coins, merges them, and splits the needed amount at `tx.build()` time: - -```typescript -import { coinWithBalance } from '@bucket-protocol/sdk'; +2. Resolve live types (never assume static lists): -// These are equivalent: -await client.buildPSMSwapInTransaction(tx, { - coinType: usdcType, - inputCoinOrAmount: 1_000_000, // pass number directly -}); -await client.buildPSMSwapInTransaction(tx, { - coinType: usdcType, - inputCoinOrAmount: coinWithBalance({ type: usdcType, balance: 1_000_000 }), // explicit factory -}); +```ts +const usdbType = await client.getUsdbCoinType(); +const collateralTypes = await client.getAllCollateralTypes(); +const oracleTypes = await client.getAllOracleCoinTypes(); +const psmTypes = Object.keys(await client.getAllPsmPoolObjects()); +const savingLpTypes = Object.keys(await client.getAllSavingPoolObjects()); ``` -### Decimals +3. Build PTB commands on `Transaction`, then sign and execute separately. +4. For unsupported user input, validate against live lists/maps first and return a clear error. +5. If config may be stale (protocol upgrade), call `await client.refreshConfig()`. -| Token | Decimals | 1 unit in raw | -| ----- | -------- | --------------- | -| SUI | 9 | `1_000_000_000` | -| USDB | 6 | `1_000_000` | -| USDC | 6 | `1_000_000` | -| BTC | 8 | `100_000_000` | +## Coin Type Policy -Always pass amounts in raw (smallest unit). The SDK does not auto-scale. +Keep context small. Do not paste long coin-type tables unless explicitly requested. -### Account vs EOA +Rules: +1. CDP `coinType` must come from `getAllCollateralTypes()`. +2. PSM `coinType` must come from keys of `getAllPsmPoolObjects()`. +3. Saving `lpType` must come from keys of `getAllSavingPoolObjects()`. +4. Oracle price queries should use `getAllOracleCoinTypes()` when possible. +5. Use `references/coin-types.md` only when the user asks for static literals. -Bucket supports `Account` objects that hold positions on behalf of a wallet. Most builder methods accept an optional `accountObjectOrId` parameter: +## Core Behavior Notes -- **Omit** → operates on the wallet address directly (EOA mode) -- **Pass Account object ID** → operates on that Account's positions +- All write methods are PTB builders (`build*`): they append Move calls, not execute transactions. +- Amounts are raw integers (smallest unit). No auto decimal scaling. +- Most config-dependent methods are async; always `await`. +- `buildManagePositionTransaction` auto-aggregates prices when borrow or withdraw is requested. +- `accountObjectOrId` switches from EOA mode to Bucket Account mode. -## API Reference - -### Querying On-Chain Data - -All query methods are `async` and read-only — no transaction needed. - -```typescript -// Protocol-level data -const supply = await client.getUsdbSupply(); // bigint -const prices = await client.getOraclePrices({ coinTypes: [SUI_TYPE_ARG] }); // Record -const allPrices = await client.getAllOraclePrices(); // all supported coins - -// Vault data -const vaults = await client.getAllVaultObjects(); // Record -const collateralTypes = await client.getAllCollateralTypes(); // string[] - -// Saving pool data -const pools = await client.getAllSavingPoolObjects(); // Record - -// PSM pool data -const psmPools = await client.getAllPsmPoolObjects(); // Record - -// Flash mint info -const flash = await client.getFlashMintInfo(); // { feeRate, partner } - -// User-specific data -const positions = await client.getUserPositions({ address }); // PositionInfo[] -const savings = await client.getUserSavings({ address }); // SavingInfo[] -const accounts = await client.getUserAccounts({ address }); // Account[] - -// Paginated position listing by collateral -const { positions, nextCursor } = await client.getAllPositions({ - coinType: SUI_TYPE_ARG, - pageSize: 50, - cursor: null, -}); - -// Reward queries -const borrowRewards = await client.getAccountBorrowRewards({ - address, - coinTypes: [SUI_TYPE_ARG], -}); // Record> - -const savingRewards = await client.getAccountSavingPoolRewards({ - address, - lpTypes: [susdbLpType], -}); // Record> -``` - -### Building Transactions - -#### CDP — Manage Collateralized Debt Positions - -```typescript -const tx = new Transaction(); - -// Deposit collateral + borrow USDB -const [collateralCoin, usdbCoin] = await client.buildManagePositionTransaction(tx, { - coinType: '0x2::sui::SUI', - depositCoinOrAmount: 2_000_000_000, // 2 SUI - borrowAmount: 1_000_000, // 1 USDB -}); -tx.transferObjects([usdbCoin], myAddress); - -// Repay debt (partial or full) -await client.buildManagePositionTransaction(tx, { - coinType: '0x2::sui::SUI', - repayCoinOrAmount: 500_000, // 0.5 USDB -}); - -// Withdraw collateral (requires sufficient CR) -const [withdrawnCoin] = await client.buildManagePositionTransaction(tx, { - coinType: '0x2::sui::SUI', - withdrawAmount: 500_000_000, // 0.5 SUI -}); -tx.transferObjects([withdrawnCoin], myAddress); - -// Close position entirely — repays all debt, returns all collateral -const [allCollateral] = await client.buildClosePositionTransaction(tx, { - address: myAddress, - coinType: '0x2::sui::SUI', -}); -tx.transferObjects([allCollateral], myAddress); - -// Claim borrow incentive rewards -const rewards = await client.buildClaimBorrowRewardsTransaction(tx, { - coinType: '0x2::sui::SUI', -}); -// rewards: Record -Object.values(rewards).forEach((coin) => tx.transferObjects([coin], myAddress)); -``` +## Default Implementation Skeleton -**Price is auto-fetched**: `buildManagePositionTransaction` calls `aggregatePrices` internally when `borrowAmount > 0` or `withdrawAmount > 0`. Deposit-only or repay-only operations skip the oracle call. +Use this shape unless the user asks for another architecture: -#### Saving Pools — Two Layers of USDB Yield - -Bucket's saving system has **two layers**: - -- **Layer 1 — sUSDB (BSR)**: Stake USDB → receive sUSDB. Value appreciates via the Base Savings Rate (BSR) through an increasing exchange rate. `minted_sUSDB = staked_USDB / exchange_rate`. -- **Layer 2 — sUSDB Savings Pool**: Deposit sUSDB → earn additional SUI rewards on top of BSR. Total APR = BSR + SUI rewards APR. - -No stake/unstake fee. No lockup. - -```typescript -const tx = new Transaction(); - -// Deposit USDB -await client.buildDepositToSavingPoolTransaction(tx, { - address: myAddress, - lpType: susdbLpType, // saving pool LP type - depositCoinOrAmount: 1_000_000, // 1 USDB -}); - -// Withdraw USDB -const usdbCoin = await client.buildWithdrawFromSavingPoolTransaction(tx, { - lpType: susdbLpType, - amount: 500_000, -}); -tx.transferObjects([usdbCoin], myAddress); - -// Claim saving pool rewards -const rewards = await client.buildClaimSavingRewardsTransaction(tx, { - lpType: susdbLpType, -}); -Object.values(rewards).forEach((coin) => tx.transferObjects([coin], myAddress)); -``` - -#### PSM — Peg Stability Module Swaps - -```typescript -const tx = new Transaction(); - -// Swap USDC → USDB -const usdbCoin = await client.buildPSMSwapInTransaction(tx, { - coinType: usdcType, - inputCoinOrAmount: 1_000_000, // 1 USDC -}); -tx.transferObjects([usdbCoin], myAddress); - -// Swap USDB → USDC -const usdcCoin = await client.buildPSMSwapOutTransaction(tx, { - coinType: usdcType, - usdbCoinOrAmount: 1_000_000, // 1 USDB -}); -tx.transferObjects([usdcCoin], myAddress); -``` - -#### Flash Mint — Borrow USDB Within a Single Transaction +```ts +import { BucketClient } from '@bucket-protocol/sdk'; +import { Transaction } from '@mysten/sui/transactions'; -```typescript +const client = await BucketClient.initialize({ network: 'mainnet' }); const tx = new Transaction(); -// Mint USDB (must be burned in the same tx) -const [usdbCoin, receipt] = await client.flashMint(tx, { amount: 10_000_000 }); - -// ... use usdbCoin for arbitrage, liquidation, etc. ... - -// Burn (repay) — must include the fee -await client.flashBurn(tx, { usdbCoin: remainingUsdb, flashMintReceipt: receipt }); -``` - -### Composing Multiple Operations - -A key strength of PTBs is atomic composition. You can chain SDK calls in one transaction: - -```typescript -const tx = new Transaction(); +// validate types from live config here +// append build* commands here -// 1. Swap USDC to USDB -const usdbCoin = await client.buildPSMSwapInTransaction(tx, { - coinType: usdcType, - inputCoinOrAmount: 1_000_000, -}); - -// 2. Deposit the USDB into a saving pool -await client.buildDepositToSavingPoolTransaction(tx, { - address: myAddress, - lpType: susdbLpType, - depositCoinOrAmount: usdbCoin, // pass TransactionResult directly -}); +tx.setSender(address); +await client.getSuiClient().signAndExecuteTransaction({ signer, transaction: tx }); ``` -#### Leverage via Flash Mint (One-Click Leverage Pattern) +If user asks for simulation only, use `simulateTransaction` after setting sender. -Bucket supports leveraged positions using flash mints. The one-click flow: +## Method Map -1. Flash-mint USDB -2. Swap flash-minted USDB → target collateral (via DEX) -3. Deposit all collateral → borrow USDB -4. Repay flash mint with borrowed USDB +Query methods: +- `getUsdbSupply`, `getAllVaultObjects`, `getAllPsmPoolObjects`, `getAllSavingPoolObjects` +- `getUserPositions`, `getUserSavings`, `getUserAccounts` +- `getOraclePrices`, `getAllOraclePrices` -```typescript -const tx = new Transaction(); +Build methods: +- CDP: `buildManagePositionTransaction`, `buildClosePositionTransaction`, `buildClaimBorrowRewardsTransaction` +- PSM: `buildPSMSwapInTransaction`, `buildPSMSwapOutTransaction` +- Saving: `buildDepositToSavingPoolTransaction`, `buildWithdrawFromSavingPoolTransaction`, `buildClaimSavingRewardsTransaction` +- Flash: `flashMint`, `flashBurn` -// 1. Flash mint USDB for the leverage amount -const [flashUsdb, receipt] = await client.flashMint(tx, { amount: leverageUsdbAmount }); +## What To Open Next (Modular References) -// 2. Swap USDB → SUI via external DEX aggregator (e.g. Cetus) -// ... (DEX swap calls — not part of Bucket SDK) ... +Read only what you need: +- `references/api-workflows.md` + - End-to-end PTB examples for CDP, PSM, saving, flash, and composition. +- `references/query-cheatsheet.md` + - Query API quick reference, return-shape expectations, and troubleshooting checks. +- `references/protocol-concepts.md` + - CDP mechanics, CR/MCR, liquidation model, PSM peg behavior, and yield layers. +- `references/coin-types.md` + - Dynamic type resolution patterns and a small literal snapshot. -// 3. Deposit all SUI as collateral, borrow USDB to repay flash -const [, borrowedUsdb] = await client.buildManagePositionTransaction(tx, { - coinType: '0x2::sui::SUI', - depositCoinOrAmount: totalSuiCoin, - borrowAmount: leverageUsdbAmount + flashFee, -}); +## Runtime Diagnostics -// 4. Repay flash mint -await client.flashBurn(tx, { usdbCoin: borrowedUsdb, flashMintReceipt: receipt }); -``` +Use the bundled script when you need a quick live state snapshot: -### Low-Level PTB Helpers - -For advanced use cases, the building blocks behind `build*` methods are also public. These helpers are async in the latest SDK, so call them with `await`: - -- **Price**: `aggregateBasicPrices(tx, { coinTypes })` (Pyth-only feeds), `aggregatePrices(tx, { coinTypes })` (all feeds incl. derivatives) → `TransactionResult[]` -- **CDP internals**: `debtorRequest()` → `checkUpdatePositionRequest()` → `updatePosition()` → `checkUpdatePositionResponse()` -- **Saving pool calls**: `savingPoolDeposit()`, `savingPoolWithdraw()`, `checkDepositResponse()`, `checkWithdrawResponse()`, `claimPoolIncentive()` -- **PSM calls**: `psmSwapIn()`, `psmSwapOut()` -- **Object refs**: `treasury(tx)`, `vault(tx, { coinType })`, `aggregator(tx, { coinType })`, `savingPoolObj(tx, { lpType })`, `psmPoolObj(tx, { coinType })`, `vaultRewarderRegistry(tx)`, `savingPoolGlobalConfig(tx)`, `flashGlobalConfig(tx)` -- **Account helpers**: `accountAddress(tx, { address, accountObjectOrId })`, `newAccountRequest(tx, { address, accountObjectOrId })`, `newPriceCollector(tx, { coinType })` - -## Key Types - -```typescript -// Vault info — returned by getAllVaultObjects() -type VaultInfo = { - collateralType: string; - collateralDecimal: number; - collateralBalance: bigint; - usdbSupply: bigint; - maxUsdbSupply: bigint; - minCollateralRatio: number; // e.g. 1.1 = 110% - interestRate: number; - positionTableSize: number; - rewardRate: Record; -}; - -// User position — returned by getUserPositions() -type PositionInfo = { - collateralType: string; - collateralAmount: bigint; - debtAmount: bigint; - debtor: string; - accountId?: string; - rewards?: Record; -}; - -// Saving pool info — returned by getAllSavingPoolObjects() -type SavingPoolInfo = { - lpType: string; - lpSupply: bigint; - usdbBalance: bigint; - usdbDepositCap: bigint | null; - savingRate: number; - rewardRate: Record; -}; - -// PSM pool info — returned by getAllPsmPoolObjects() -type PsmPoolInfo = { - coinType: string; - decimal: number; - balance: bigint; - usdbSupply: bigint; - feeRate: { swapIn: number; swapOut: number }; - partnerFeeRate: Record; -}; - -// User saving — returned by getUserSavings() -type SavingInfo = { - lpType: string; - address: string; - accountId?: string; - usdbBalance: bigint; - lpBalance: bigint; - rewards: Record; -}; - -// Flash mint info — returned by getFlashMintInfo() -type FlashMintInfo = { - feeRate: number; - partner: Record; -}; +```bash +npx tsx skill/bucket-sdk/scripts/query-state.ts ``` -## Common Gotchas - -1. **Async migration**: many methods that were previously synchronous are now async in v2.1.0+ (`getConfig`, `getAllCollateralTypes`, `getUsdbCoinType`, object info getters, `buildClosePositionTransaction`, `buildClaimBorrowRewardsTransaction`, saving builders, flash methods, and low-level helpers like `debtorRequest` / `updatePosition`). Always use `await` for these calls. - -2. **Zero coin auto-cleanup**: When `borrowAmount` is 0, the returned USDB coin is a zero coin that gets auto-destroyed. Same for collateral when `withdrawAmount` is 0. You don't need to handle this. - -3. **Dry-run / simulation**: Use `suiClient.simulateTransaction({ transaction: tx })` to test without signing. Set `tx.setSender(address)` first. - -4. **Config refresh**: If the protocol upgrades, call `client.refreshConfig()` to re-fetch on-chain config. Overrides from `initialize()` are preserved automatically. - -5. **No borrow fee**: The protocol has **no** one-time borrow fee (removed in the v2 upgrade). Only fixed per-asset interest rates apply. Interest accrues in real time and is added to debt continuously. - -6. **Mint caps**: Each vault has a max USDB supply (`VaultInfo.maxUsdbSupply`). Borrowing beyond this cap will fail on-chain. - -7. **Full liquidation**: When a position's CR drops below MCR, **all collateral is seized** (not partial). Liquidations are protocol-run. User loss ≈ `(MCR - 1) × Debt`. The SDK does not execute liquidations. - -8. **Repay with collateral**: The "repay with collateral" feature (selling collateral to repay debt) is a UI-level feature that routes through on-chain DEXes. The base SDK provides `buildManagePositionTransaction` with `repayCoinOrAmount` for repaying with USDB you already hold. - -9. **sUSDB exchange rate**: sUSDB appreciates vs USDB over time via BSR. When withdrawing, users receive more USDB per sUSDB than they deposited. The exchange rate only increases. - -## Bundled Resources +It prints supply, prices, vault stats, PSM pools, saving pools, and supported collateral types. -This skill includes additional reference files. Consult them when you need detailed data: +## Response Expectations -| Resource | Path | When to use | -| ---------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| **Coin Types** | `references/coin-types.md` | Need the full `0x...` type string for a specific token (collateral, PSM, LP, reward) | -| **Protocol Concepts** | `references/protocol-concepts.md` | Need to understand CDP mechanics, PSM vs CDP decision, saving pool yield, flash mints, Account vs EOA, or oracle pricing | -| **Query State Script** | `scripts/query-state.ts` | Need to inspect live on-chain state (vault stats, prices, pool balances). Run with `npx tsx skills/bucket-sdk/scripts/query-state.ts` | +- Return code that is copy-paste runnable in TypeScript. +- Mention which live type source was used (`getAllCollateralTypes`, PSM keys, or saving LP keys). +- When rejecting input, include the checked list source and a short fix suggestion. +- Prefer small, composable PTBs over unrelated helper abstractions. +## Quality Gates Before Finalizing +1. Type validation done against live config (not hardcoded memory). +2. Amount units are raw integer units. +3. Transaction path is complete: build -> set sender -> sign+execute (or simulate). +4. Failure handling includes useful checks: + - Unsupported collateral or PSM or lp type + - Missing price feed + - Insufficient pool balance + - Insufficient user balance diff --git a/skill/bucket-sdk/references/api-workflows.md b/skill/bucket-sdk/references/api-workflows.md new file mode 100644 index 0000000..63bb00e --- /dev/null +++ b/skill/bucket-sdk/references/api-workflows.md @@ -0,0 +1,122 @@ +# API Workflows + +Use this file for write-path examples. Keep `SKILL.md` minimal and read this only when implementing flows. + +## Setup + +```ts +import { BucketClient } from '@bucket-protocol/sdk'; +import { Transaction } from '@mysten/sui/transactions'; + +const client = await BucketClient.initialize({ network: 'mainnet' }); +const tx = new Transaction(); +``` + +## CDP: Deposit and Borrow + +```ts +const [collateralCoin, usdbCoin] = await client.buildManagePositionTransaction(tx, { + coinType, + depositCoinOrAmount: 1_000_000_000, + borrowAmount: 800_000, +}); +``` + +## CDP: Repay and Withdraw + +```ts +await client.buildManagePositionTransaction(tx, { + coinType, + repayCoinOrAmount: 500_000, + withdrawAmount: 200_000_000, +}); +``` + +## CDP: Close Position + +```ts +const [allCollateral] = await client.buildClosePositionTransaction(tx, { + address, + coinType, +}); +``` + +## PSM: Stablecoin -> USDB + +```ts +const usdbCoin = await client.buildPSMSwapInTransaction(tx, { + coinType: psmCoinType, + inputCoinOrAmount: 1_000_000, +}); +``` + +## PSM: USDB -> Stablecoin + +```ts +const stableCoin = await client.buildPSMSwapOutTransaction(tx, { + coinType: psmCoinType, + usdbCoinOrAmount: 1_000_000, +}); +``` + +## Saving Pool: Deposit and Withdraw + +```ts +await client.buildDepositToSavingPoolTransaction(tx, { + address, + lpType, + depositCoinOrAmount: 1_000_000, +}); + +const usdbOut = await client.buildWithdrawFromSavingPoolTransaction(tx, { + lpType, + amount: 500_000, +}); +``` + +## Saving Pool: Claim Rewards + +```ts +const rewards = await client.buildClaimSavingRewardsTransaction(tx, { lpType }); +for (const coin of Object.values(rewards)) { + tx.transferObjects([coin], address); +} +``` + +## Flash Mint + +```ts +const [flashUsdb, receipt] = await client.flashMint(tx, { amount: 10_000_000 }); +// use flashUsdb in the same PTB +await client.flashBurn(tx, { usdbCoin: flashUsdb, flashMintReceipt: receipt }); +``` + +## Compose Operations Atomically + +Example: swap to USDB then deposit to saving pool in one PTB. + +```ts +const usdbCoin = await client.buildPSMSwapInTransaction(tx, { + coinType: psmCoinType, + inputCoinOrAmount: 1_000_000, +}); + +await client.buildDepositToSavingPoolTransaction(tx, { + address, + lpType, + depositCoinOrAmount: usdbCoin, +}); +``` + +## Execution + +```ts +tx.setSender(address); +await client.getSuiClient().signAndExecuteTransaction({ signer, transaction: tx }); +``` + +## Notes + +- Build methods append commands only; they do not execute on chain. +- Use raw integer units, not decimal strings. +- For dry run, set sender and call `simulateTransaction`. diff --git a/skill/bucket-sdk/references/coin-types.md b/skill/bucket-sdk/references/coin-types.md index 1217cbd..edc3d4b 100644 --- a/skill/bucket-sdk/references/coin-types.md +++ b/skill/bucket-sdk/references/coin-types.md @@ -1,100 +1,41 @@ -# Bucket Protocol — Supported Coin Types (Mainnet) +# Bucket Protocol - Coin Types (Lean Reference) -This file lists all coin types supported by Bucket Protocol on Sui mainnet. Use these exact strings when calling SDK methods like `buildManagePositionTransaction`, `buildPSMSwapInTransaction`, etc. +Use runtime queries first. Do not rely on static tables unless the user explicitly asks for literals. -> **Note**: Coin types may change as the protocol adds or removes support. Call `await client.getAllCollateralTypes()`, `await client.getAllOracleCoinTypes()`, or inspect `await client.getConfig()` for the live list. +## Live Type Discovery (Preferred) -## USDB (Bucket's Stablecoin) +```ts +const usdbType = await client.getUsdbCoinType(); +const collateralTypes = await client.getAllCollateralTypes(); +const oracleTypes = await client.getAllOracleCoinTypes(); +const psmTypes = Object.keys(await client.getAllPsmPoolObjects()); +const savingLpTypes = Object.keys(await client.getAllSavingPoolObjects()); +``` -| Token | Coin Type | Decimals | -| ----- | -------------------------------------------------------------------------------- | -------- | -| USDB | `0xe14726c336e81b32328e92afc37345d159f5b550b09fa92bd43640cfdd0a0cfd::usdb::USDB` | 6 | +Validation rules: +- CDP `coinType`: must be in `collateralTypes` +- PSM `coinType`: must be in `psmTypes` +- Saving `lpType`: must be in `savingLpTypes` -Get it programmatically with `await client.getUsdbCoinType()`. +If not present, return an explicit unsupported-type error. -## Basic Collateral (Direct Pyth Price Feed) +## Minimal Literal Snapshot (Mainnet, May Change) -These tokens have a direct Pyth oracle price. They can be used as CDP collateral and are supported by `aggregateBasicPrices()`. +These are common values only. Treat as a convenience snapshot, not source of truth. -| Token | Coin Type | Decimals | Notes | -| ------ | ------------------------------------------------------------------------------------ | -------- | -------------------- | -| SUI | `0x2::sui::SUI` | 9 | Native gas token | -| BTC | `0xaafb102dd0902f5055cadecd687fb5b71ca82ef0e0285d90afde828ec58ca96b::btc::BTC` | 8 | | -| ETH | `0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH` | 8 | | -| WAL | `0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL` | 9 | Walrus token | -| USDC | `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC` | 6 | | -| USDT | `0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT` | 6 | | -| haSUI | `0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI` | 9 | Haedal staked SUI | -| CERT | `0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT` | 9 | Volo staked SUI | -| afSUI | `0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI` | 9 | Aftermath staked SUI | -| SCA | `0x7016aae72cfc67f2fadf55769c0a7dd54291a583b63051a5ed71081cce836ac6::sca::SCA` | 9 | Scallop token | -| BUCK | `0xce7ff77a83ea0cb6fd39bd8748e2ec89a3f41e8efdc3f4eb123e0ca37b184db2::buck::BUCK` | 9 | Bucket V1 stablecoin | -| DEEP | `0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP` | 6 | DeepBook token | -| XBTC | `0x876a4b7bce8aeaef60464c11f4026903e9afacab79b9b142686158aa86560b50::xbtc::XBTC` | 8 | | -| WBTC | `0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC` | 8 | | -| UP_USD | `0x5de877a152233bdd59c7269e2b710376ca271671e9dd11076b1ff261b2fd113c::up_usd::UP_USD` | 6 | Unihouse USD | -| XAUM | `0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM` | 6 | Tokenized gold | +| Token | Type | +| --- | --- | +| SUI | `0x2::sui::SUI` | +| USDB | `0xe14726c336e81b32328e92afc37345d159f5b550b09fa92bd43640cfdd0a0cfd::usdb::USDB` | +| USDC | `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC` | +| USDT | `0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT` | +| BUCK | `0xce7ff77a83ea0cb6fd39bd8748e2ec89a3f41e8efdc3f4eb123e0ca37b184db2::buck::BUCK` | +| sUSDB LP | `0x38f61c75fa8407140294c84167dd57684580b55c3066883b48dedc344b1cde1e::susdb::SUSDB` | -## Derivative Collateral (Price from Underlying) +## When To Use Static Literals -These tokens derive their price from a basic token via an exchange rate (Scallop sCoin, Unihouse gCoin, or BFBTC). The SDK handles this automatically in `aggregatePrices()` — you don't need to treat them differently from basic collateral when using `build*` methods. +Use static literals only when: +- user requests a documented literal string, or +- runtime access is not available. -### sCoin (Scallop Lending Receipts) — derivative_kind: `sCoin` - -| Token | Coin Type | Underlying | -| ----- | ------------------------------------------------------------------------------------------------------ | ---------- | -| sSUI | `0xaafc4f740de0dd0dde642a31148fb94517087052f19afb0f7bed1dc41a50c77b::scallop_sui::SCALLOP_SUI` | SUI | -| sUSDC | `0x854950aa624b1df59fe64e630b2ba7c550642e9342267a33061d59fb31582da5::scallop_usdc::SCALLOP_USDC` | USDC | -| sUSDT | `0xb1d7df34829d1513b73ba17cb7ad90c88d1e104bb65ab8f62f13e0cc103783d3::scallop_sb_usdt::SCALLOP_SB_USDT` | USDT | -| sWAL | `0x622345b3f80ea5947567760eec7b9639d0582adcfd6ab9fccb85437aeda7c0d0::scallop_wal::SCALLOP_WAL` | WAL | -| sDEEP | `0xeb7a05a3224837c5e5503575aed0be73c091d1ce5e43aa3c3e716e0ae614608f::scallop_deep::SCALLOP_DEEP` | DEEP | -| sETH | `0xb14f82d8506d139eacef109688d1b71e7236bcce9b2c0ad526abcd6aa5be7de0::scallop_sb_eth::SCALLOP_SB_ETH` | ETH | -| sSCA | `0x5ca17430c1d046fae9edeaa8fd76c7b4193a00d764a0ecfa9418d733ad27bc1e::scallop_sca::SCALLOP_SCA` | SCA | - -### gCoin (Unihouse Staked House Coins) — derivative_kind: `gCoin` - -| Token | Coin Type | Underlying | -| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -| gSUI | `0x2f2226a22ebeb7a0e63ea39551829b238589d981d1c6dd454f01fcc513035593::house::StakedHouseCoin<0x2::sui::SUI>` | SUI | -| gUP_USD | `0x2f2226a22ebeb7a0e63ea39551829b238589d981d1c6dd454f01fcc513035593::house::StakedHouseCoin<0x5de877a152233bdd59c7269e2b710376ca271671e9dd11076b1ff261b2fd113c::up_usd::UP_USD>` | UP_USD | - -### BFBTC — derivative_kind: `BFBTC` - -| Token | Coin Type | Underlying | -| ----- | ---------------------------------------------------------------------------------- | ---------- | -| BFBTC | `0x7438e8caf5c345fbd3772517380bf0ca432f53892dee65ee0dda3eb127993cd9::bfbtc::BFBTC` | BTC | - -## PSM Pool Coins - -These coins can be swapped 1:1 with USDB via `buildPSMSwapInTransaction` / `buildPSMSwapOutTransaction`: - -| Token | Coin Type | Decimals | -| ----- | -------------------------------------------------------------------------------- | -------- | -| USDC | `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC` | 6 | -| USDT | `0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT` | 6 | -| BUCK | `0xce7ff77a83ea0cb6fd39bd8748e2ec89a3f41e8efdc3f4eb123e0ca37b184db2::buck::BUCK` | 9 | - -## Saving Pool LP Types - -Pass these as the `lpType` parameter to saving pool methods (`buildDepositToSavingPoolTransaction`, etc.): - -| Token | LP Type | -| ----- | ---------------------------------------------------------------------------------- | -| sUSDB | `0x38f61c75fa8407140294c84167dd57684580b55c3066883b48dedc344b1cde1e::susdb::SUSDB` | - -## Common Reward Types - -These appear as keys in borrow/saving reward records: - -| Token | Coin Type | -| ----- | -------------------------------------------------------------------------------- | -| SUI | `0x2::sui::SUI` | -| SCA | `0x7016aae72cfc67f2fadf55769c0a7dd54291a583b63051a5ed71081cce836ac6::sca::SCA` | -| DEEP | `0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP` | -| XAUM | `0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM` | - -## Protocol Token - -| Token | Coin Type | Decimals | Notes | -| ----- | ------------------------------------------------------------------------------ | -------- | ------------------------------------------ | -| BUT | `0xbc858cb910b9914bee64fff0f9b38855355a040c49155a17b265d9086d256545::but::BUT` | 9 | Native protocol token; stakeable for deBUT | +Otherwise always resolve from live config. diff --git a/skill/bucket-sdk/references/query-cheatsheet.md b/skill/bucket-sdk/references/query-cheatsheet.md new file mode 100644 index 0000000..d316fe8 --- /dev/null +++ b/skill/bucket-sdk/references/query-cheatsheet.md @@ -0,0 +1,85 @@ +# Query Cheatsheet + +Use this file for read-path tasks and debugging checks. + +## Protocol and Config + +```ts +const config = await client.getConfig(); +const usdbType = await client.getUsdbCoinType(); +``` + +## Supported Types + +```ts +const collateralTypes = await client.getAllCollateralTypes(); +const oracleTypes = await client.getAllOracleCoinTypes(); +const psmTypes = Object.keys(await client.getAllPsmPoolObjects()); +const savingLpTypes = Object.keys(await client.getAllSavingPoolObjects()); +``` + +## Market State + +```ts +const usdbSupply = await client.getUsdbSupply(); +const allPrices = await client.getAllOraclePrices(); +const vaults = await client.getAllVaultObjects(); +const psmPools = await client.getAllPsmPoolObjects(); +const savingPools = await client.getAllSavingPoolObjects(); +const flashInfo = await client.getFlashMintInfo(); +``` + +## User State + +```ts +const positions = await client.getUserPositions({ address }); +const savings = await client.getUserSavings({ address }); +const accounts = await client.getUserAccounts({ address }); +``` + +## Rewards + +```ts +const borrowRewards = await client.getAccountBorrowRewards({ + address, + coinTypes: collateralTypes, +}); + +const savingRewards = await client.getAccountSavingPoolRewards({ + address, + lpTypes: savingLpTypes, +}); +``` + +## Position Pagination + +```ts +const page1 = await client.getAllPositions({ coinType, pageSize: 50, cursor: null }); +const page2 = page1.nextCursor + ? await client.getAllPositions({ coinType, pageSize: 50, cursor: page1.nextCursor }) + : null; +``` + +## Error Checks + +If `Unsupported collateral type`: +- compare input with `getAllCollateralTypes()` + +If `Unsupported PSM coin type`: +- compare input with `Object.keys(await client.getAllPsmPoolObjects())` + +If missing price: +- ensure type appears in `getAllOracleCoinTypes()` + +If pool balance issue: +- inspect `getAllPsmPoolObjects()` or `getAllSavingPoolObjects()` + +## Refresh Strategy + +After protocol upgrade or stale data suspicion: + +```ts +await client.refreshConfig(); +``` + +Then re-read supported types and retry. From fa027ddb582067b1f08ab735857e056b876f159b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E6=B2=92code=20=E6=88=91=E6=B2=92code?= <135327579+ZouBadCode@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:52:18 +0800 Subject: [PATCH 3/3] feat: update query-state script for improved usage instructions and add new query-state.mjs file --- skill/bucket-sdk/SKILL.md | 7 +- skill/bucket-sdk/scripts/query-state.mjs | 121 +++++++++++++++++++++++ skill/bucket-sdk/scripts/query-state.ts | 15 ++- 3 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 skill/bucket-sdk/scripts/query-state.mjs diff --git a/skill/bucket-sdk/SKILL.md b/skill/bucket-sdk/SKILL.md index 2528d14..8d4204d 100644 --- a/skill/bucket-sdk/SKILL.md +++ b/skill/bucket-sdk/SKILL.md @@ -113,7 +113,12 @@ Read only what you need: Use the bundled script when you need a quick live state snapshot: ```bash -npx tsx skill/bucket-sdk/scripts/query-state.ts +# Run in a project directory that has @bucket-protocol/sdk installed +# is wherever you store this skill, for example: +# .github/skills/bucket-sdk +# .agents/skills/bucket-sdk +# .claude/skills/bucket-sdk +node /scripts/query-state.mjs ``` It prints supply, prices, vault stats, PSM pools, saving pools, and supported collateral types. diff --git a/skill/bucket-sdk/scripts/query-state.mjs b/skill/bucket-sdk/scripts/query-state.mjs new file mode 100644 index 0000000..f335514 --- /dev/null +++ b/skill/bucket-sdk/scripts/query-state.mjs @@ -0,0 +1,121 @@ +/** + * Diagnostic script: query Bucket Protocol on-chain state. + * + * Usage (from a project that has @bucket-protocol/sdk installed): + * node /scripts/query-state.mjs + * + * Examples of : + * .github/skills/bucket-sdk + * .agents/skills/bucket-sdk + * .claude/skills/bucket-sdk + * + * Requires: @bucket-protocol/sdk, @mysten/sui + * + * Prints a summary of: + * - USDB total supply + * - Oracle prices for all supported collateral + * - Vault stats (TVL, collateral ratio, interest rate, max supply) + * - PSM pool balances and fee rates + * - Saving pool stats (rate, deposit cap, LP supply) + * - Flash mint info (fee rate) + */ + +import { createRequire } from 'node:module'; + +// Resolve SDK from the caller project (cwd), not from the skill folder location. +const requireFromCwd = createRequire(`${process.cwd()}/package.json`); +const { BucketClient } = requireFromCwd('@bucket-protocol/sdk'); + +function printLine(message = '') { + process.stdout.write(`${message}\n`); +} + +function isDefined(value) { + return value !== null && value !== undefined; +} + +async function main() { + printLine('Initializing BucketClient (mainnet)...'); + printLine(); + const client = await BucketClient.initialize({ network: 'mainnet' }); + + // --- USDB Supply --- + const supply = await client.getUsdbSupply(); + printLine(`USDB Total Supply: ${(Number(supply) / 1e6).toLocaleString()} USDB`); + printLine(); + + // --- Oracle Prices --- + printLine('=== Oracle Prices ==='); + const prices = await client.getAllOraclePrices(); + const sortedPrices = Object.entries(prices).sort(([, a], [, b]) => b - a); + for (const [coinType, price] of sortedPrices) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` ${shortName.padEnd(20)} $${price}`); + } + printLine(); + + // --- Vaults --- + printLine('=== Vaults ==='); + const vaults = await client.getAllVaultObjects(); + for (const [coinType, vault] of Object.entries(vaults)) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` [${shortName}]`); + printLine(` Min CR: ${vault.minCollateralRatio}`); + printLine(` Interest Rate: ${vault.interestRate}`); + printLine( + ` Max USDB: ${isDefined(vault.maxUsdbSupply) ? (Number(vault.maxUsdbSupply) / 1e6).toLocaleString() : 'unlimited'}`, + ); + printLine(` USDB Minted: ${(Number(vault.usdbSupply) / 1e6).toLocaleString()}`); + printLine(` Collateral: ${vault.collateralBalance}`); + printLine(` Positions: ${vault.positionTableSize}`); + } + printLine(); + + // --- PSM Pools --- + printLine('=== PSM Pools ==='); + const psmPools = await client.getAllPsmPoolObjects(); + for (const [coinType, pool] of Object.entries(psmPools)) { + const shortName = coinType.split('::').pop() ?? coinType; + printLine(` [${shortName}]`); + printLine(` Balance: ${pool.balance}`); + printLine(` Swap-In Fee: ${pool.feeRate.swapIn}`); + printLine(` Swap-Out Fee:${pool.feeRate.swapOut}`); + } + printLine(); + + // --- Saving Pools --- + printLine('=== Saving Pools ==='); + const savingPools = await client.getAllSavingPoolObjects(); + for (const [lpType, pool] of Object.entries(savingPools)) { + const shortName = lpType.split('::').pop() ?? lpType; + printLine(` [${shortName}]`); + printLine(` Saving Rate: ${pool.savingRate}`); + printLine(` LP Supply: ${pool.lpSupply}`); + printLine( + ` Deposit Cap: ${isDefined(pool.usdbDepositCap) ? (Number(pool.usdbDepositCap) / 1e6).toLocaleString() : 'none'}`, + ); + } + printLine(); + + // --- Flash Mint --- + printLine('=== Flash Mint ==='); + const flashMint = await client.getFlashMintInfo(); + printLine(` Fee Rate: ${flashMint.feeRate}`); + printLine(); + + // --- Supported Coin Types --- + printLine('=== Supported Collateral Types ==='); + const collTypes = await client.getAllCollateralTypes(); + for (const ct of collTypes) { + const shortName = ct.split('::').pop() ?? ct; + printLine(` ${shortName}`); + } + printLine(); + + printLine('Done.'); +} + +main().catch((err) => { + console.error('Error:', err); + process.exit(1); +}); diff --git a/skill/bucket-sdk/scripts/query-state.ts b/skill/bucket-sdk/scripts/query-state.ts index 53d4391..0436f39 100644 --- a/skill/bucket-sdk/scripts/query-state.ts +++ b/skill/bucket-sdk/scripts/query-state.ts @@ -1,8 +1,13 @@ /** * Diagnostic script: query Bucket Protocol on-chain state. * - * Usage (from project root, or any project that has @bucket-protocol/sdk installed): - * npx tsx skills/bucket-sdk/scripts/query-state.ts + * Usage (from a project that has @bucket-protocol/sdk installed): + * npx tsx /scripts/query-state.ts + * + * Examples of : + * .github/skills/bucket-sdk + * .agents/skills/bucket-sdk + * .claude/skills/bucket-sdk * * Requires: @bucket-protocol/sdk, @mysten/sui * @@ -15,7 +20,11 @@ * - Flash mint info (fee rate) */ -import { BucketClient } from '@bucket-protocol/sdk'; +import { createRequire } from 'node:module'; + +// Resolve SDK from the caller project (cwd), not from the skill folder location. +const requireFromCwd = createRequire(`${process.cwd()}/package.json`); +const { BucketClient } = requireFromCwd('@bucket-protocol/sdk'); function printLine(message = '') { process.stdout.write(`${message}\n`);