Scallop DeepBook Kit (Dart) | Scallop DeepBook 工具包(Dart)

A Dart/Flutter toolkit for interacting with DeepBook V3 Margin Pools on the Sui blockchain, built on the sui_dart SDK.

一個在 Sui 區塊鏈上與 DeepBook V3 Margin Pools 互動的 Dart/Flutter 工具套件, 建構於 sui_dart SDK 之上。

Features | 功能特色

  • DeepBook V3 Margin integration — supply, withdraw, referrals, balances.
  • Pool analyticsDeepBookMarginPool reads pool parameters and computes borrow/supply APR, utilization, and kinks (via devInspect, no signing needed).
  • On-chain discoverygetOnChainMarginPools() enumerates margin pools from the on-chain dynamic-fields table.
  • Flutter-friendly — pure Dart, no native plugins; works on mobile & desktop (gRPC; see Platform note).
  • Built on sui_dart — your org's Sui SDK (Transaction v2 builder, gRPC, Ed25519, BCS).

Installation | 安裝

dart pub add scallop_deepbook_kit
# Flutter projects: flutter pub add scallop_deepbook_kit

Or add it to your pubspec.yaml directly:

dependencies:
  scallop_deepbook_kit: ^1.1.1
Use an unreleased version (git / path)
dependencies:
  scallop_deepbook_kit:
    git:
      url: https://github.com/scallop-io/scallop-deepbook-kit-dart.git
  # or, for local development:
  # scallop_deepbook_kit:
  #   path: ../scallop-deepbook-kit-dart

Then run dart pub get (or flutter pub get).

Quick Start | 快速開始

import 'package:scallop_deepbook_kit/scallop_deepbook_kit.dart';

Future<void> main() async {
  // Initialize the toolkit. The private key may be a `suiprivkey…` bech32 string,
  // a hex string (with or without 0x), or base64. Raw key material defaults to Ed25519.
  final toolkit = DeepBookMarginToolkit(ToolkitConfig(
    network: 'testnet',                  // 'testnet' | 'mainnet'
    privateKey: '<YOUR_PRIVATE_KEY>',
    // supplierCapId: '0x…',            // optional: reuse an existing cap
    // grpcHost: 'fullnode.mainnet.sui.io', // optional: custom gRPC host (no scheme)
  ));
  // ... and `await toolkit.dispose();` when finished, to close the gRPC channel.

  // Create the Supplier Cap if one does not already exist.
  await toolkit.initialize();

  // Create a supply referral (optional).
  final referralId = await toolkit.createSupplyReferral('SUI');

  // Supply 0.1 SUI to the margin pool.
  await toolkit.supplyToMarginPool('SUI', 0.1, referralId: referralId);

  // Read balances.
  final balance = await toolkit.getBalance('SUI');
  print('Supplied: ${balance.userSupplyAmount} SUI');
  print('Wallet:   ${balance.walletBalance} SUI');

  // Withdraw all supplied SUI (omit the amount to withdraw everything).
  await toolkit.withdrawFromMarginPool('SUI');

  // Withdraw accumulated referral fees.
  if (referralId != null) {
    await toolkit.withdrawReferralFees('SUI', referralId);
  }
}

Flutter tip: never hard-code a private key in your app. Load it from secure storage (e.g. flutter_secure_storage) or your backend, and pass it to ToolkitConfig.

Pool analytics (no signing) | 池參數與年化(免簽名)

final pool = DeepBookMarginPool(network: 'mainnet');

// Single pool
final sui = await pool.getPoolParameters('SUI');
print('supply APR:   ${sui.supplyApr}');     // normalized fraction, e.g. 0.045 = 4.5%
print('borrow APR@hi:${sui.borrowAprOnHighKink}');
print('utilization:  ${sui.utilizationRate}');

// Batch (one devInspect + batched object reads)
final many = await pool.getPoolsParameters(['SUI', 'USDC', 'DEEP']);
for (final p in many) {
  print('${p.type}: util=${p.utilizationRate}, supplyAPR=${p.supplyApr}');
}

You can also pass a custom DeepBookConfig (e.g. with a custom marginPools map) — see example/margin_pool_demo.dart.

Wallet usage (build, then sign yourself) | 錢包用法(自行簽名)

Two ways to transact, depending on who holds the key:

  • DeepBookMarginToolkit — you give it the private key; it builds, signs, and executes for you (great for a Flutter app with an embedded wallet in secure storage).
  • DeepBookMarginPool build* helpers — read with the pool, build an unsigned tx, then sign + execute with your own wallet/signer. The private-key toolkit is never required.
final pool = DeepBookMarginPool(network: 'mainnet');
final account = SuiAccount.fromPrivateKey(keyFromSecureStorage); // your wallet/signer
final address = account.getAddress();

// Discover the user's SupplierCap(s) (matches by type suffix — upgrade-safe).
final caps = await pool.getSupplierCapIds(address);

// Build an unsigned supply tx (mint a cap if the user has none). The supply coin
// is resolved from the amount automatically (SUI from gas, else from the wallet).
final tx = Transaction()..setSender(address);
final cap = caps.isEmpty ? pool.buildMintSupplierCap(tx) : tx.object(caps.first);
await pool.buildSupply(tx, 'SUI', cap, 0.1, owner: address);
if (caps.isEmpty) tx.transferObjects([cap], address);

// Sign + execute with your account (or hand `tx` to any wallet/signer).
final result = await signAndExecuteTransaction(pool.suiClient, account, tx);

Other builders: buildWithdraw(tx, coinKey, cap, {amount}) (returns the coin to transfer/merge), buildMintSupplyReferral, buildWithdrawReferralFees. Need the coin argument alone? use the exported coinWithBalance(client, tx, owner:, coinType:, amount:). Full example: example/wallet_flow_demo.dart.

Discover margin pools on-chain | 鏈上探索保證金池

final pools = await getOnChainMarginPools(); // defaults to mainnet
pools.forEach((key, pool) => print('$key -> ${pool.address} (${pool.type})'));

API Reference | API 參考

DeepBookMarginToolkit

Method Returns Description
DeepBookMarginToolkit(ToolkitConfig config) Construct from network + private key.
initialize() Future<String> Create the Supplier Cap if needed; returns its id.
createSupplierCap() Future<String?> Mint a new Supplier Cap.
createSupplyReferral(coin) Future<String?> Mint a supply referral for coin.
supplyToMarginPool(coin, amount, {referralId}) Future<bool> Supply amount (human units).
withdrawFromMarginPool(coin, {amount}) Future<bool> Withdraw amount, or all if omitted.
withdrawReferralFees(coin, referralId) Future<bool> Withdraw accrued referral fees.
getBalance(coin) Future<MarginBalance> userSupplyAmount + walletBalance.
getSupplierCapId() String? Current Supplier Cap id.
getAddress() String Wallet address.

ToolkitConfig: network, privateKey, supplierCapId?, grpcHost?, supplierCapPackageId?, dbConfig?. Also dispose() to close the gRPC channel.

DeepBookMarginPool

Reads: getPoolParameters(coinKey, {supplierCapId})MarginPoolParams; getPoolsParameters(coinKeys, {supplierCapId})List<MarginPoolParams>; getSupplierCapIds([owner])Future<List<String>> (the owner's SupplierCap ids).

Tx builders (unsigned; sign + execute yourself): buildMintSupplierCap(tx) → cap; buildSupply(tx, coinKey, cap, amount, {owner, referralId}) (resolves the coin); buildWithdraw(tx, coinKey, cap, {amount}) → coin; buildMintSupplyReferral(tx, coinKey); buildWithdrawReferralFees(tx, coinKey, referralId). Public fields: marginPoolContract, dbConfig, suiClient. dispose() closes the channel (only if it owns it).

Also exported

MarginPoolContract, getOnChainMarginPools, DeepBookConfig, Coin/Pool/MarginPool/DeepbookPackageIds/PythConfig, the testnet*/mainnet* constant maps, FLOAT_SCALAR, marginPoolParamKeys, MarginBalance, and the wallet-flow helpers signAndExecuteTransaction(client, account, tx), coinWithBalance(client, tx, owner:, coinType:, amount:), and GrpcExecResult.

Supported networks & coins | 支援的網路與幣種

  • Networks: testnet, mainnet (or supply custom packageIds via DeepBookConfig).
  • Margin-pool coin keys: mainnet SUI, USDC, DEEP, WAL, SUIUSDE, XBTC, USDSUI; testnet SUI, DBUSDC, DEEP, DBTC. All package ids, coin types, and pool addresses are the current DeepBook V3 values.

Implementation notes | 實作說明

Transactions are built over gRPC: a coin of a given balance is resolved with splitCoins(gas) for SUI, or listCoins + merge + split otherwise; the clock is tx.object(SUI_CLOCK_OBJECT_ID); Option<ID> referrals use tx.pure.option('id', …); write txs are built server-side via simulateTransaction(doGasSelection: true) (the fullnode resolves gas and returns canonical signable bytes — no JSON-RPC build); 1e9-scaled rate math uses BigInt with double for display.

Note on sui_dart's gRPC wrappers: sui_dart 0.4.1's high-level simulateTransaction/executeTransaction build a readMask that omits command_outputs and the full effects, so they return no Move-call return values. This package therefore calls the raw generated services with a correct FieldMask (see src/utils/grpc_exec.dart). Writes are built server-side via simulateTransaction(doGasSelection: true) (the fullnode resolves gas and returns canonical signable bytes) — no JSON-RPC client is used.

Platform | 平台

gRPC uses native HTTP/2 — works on Flutter mobile & desktop (iOS, Android, macOS, Windows, Linux). Flutter Web is not supported by raw gRPC (it needs a grpc-web proxy). Call toolkit.dispose() / pool.dispose() to release the gRPC channel when done.

Verification status | 驗證狀態

  • dart analyze — clean (no issues).
  • dart test — offline unit tests pass (math, conversion, constants, config, key parsing, Move-call BCS encoding).
  • Live read paths over gRPCgetPoolParameters/getPoolsParameters (mainnet + testnet APR/utilization) and getOnChainMarginPools covered by test/live_grpc_test.dart (run with RUN_LIVE_TESTS=1 dart test test/live_grpc_test.dart; skipped by default so the offline suite stays fast). All pass against real fullnodes.
  • Live write & wallet flows — the private-key flow (initialize/supply/withdraw) and the wallet build-then-sign flow (getSupplierCapIdsbuildSupply → sign/execute → withdraw) verified on testnet (tool/write_flow_check.dart, tool/wallet_flow_check.dart).

License | 授權

MIT — see LICENSE.

Libraries

scallop_deepbook_kit
Scallop DeepBook Kit