From 1b77ac1e17e70964b9f964154c8b36a5a61176bf Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 05:40:11 +0100 Subject: [PATCH 1/6] feat(sdk): add Stacks server-side transaction builder functions --- packages/sdk/src/index.ts | 82 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 2cdb765..337db72 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -21,7 +21,10 @@ import { principalCV, AnchorMode, PostConditionMode, + makeContractCall, + broadcastTransaction, } from "@stacks/transactions"; +import type { StacksTransactionWire, TxBroadcastResult } from "@stacks/transactions"; /** * Open Leather wallet to call create-circle @@ -95,3 +98,82 @@ export function callTriggerPayout( onCancel: () => console.log("trigger-payout cancelled"), }); } + +export async function buildCreateCircleTx(opts: { + senderKey: string; + name: string; + contributionMicroSTX: number; + members: string[]; + fee?: number; + nonce?: number; +}): Promise { + const tx = await makeContractCall({ + contractAddress: STACKS_CONTRACT_ADDRESS, + contractName: STACKS_CONTRACT_NAME, + functionName: "create-circle", + functionArgs: [ + stringAsciiCV(opts.name.slice(0, 50)), + uintCV(opts.contributionMicroSTX), + listCV(opts.members.slice(0, 10).map((m) => principalCV(m))), + ], + senderKey: opts.senderKey, + network: STACKS_NETWORK, + anchorMode: AnchorMode.Any, + fee: opts.fee, + nonce: opts.nonce, + }); + return tx; +} + +export async function buildContributeTx(opts: { + senderKey: string; + circleId: number; + fee?: number; + nonce?: number; +}): Promise { + const tx = await makeContractCall({ + contractAddress: STACKS_CONTRACT_ADDRESS, + contractName: STACKS_CONTRACT_NAME, + functionName: "contribute", + functionArgs: [uintCV(opts.circleId)], + senderKey: opts.senderKey, + network: STACKS_NETWORK, + anchorMode: AnchorMode.Any, + postConditionMode: PostConditionMode.Allow, + fee: opts.fee, + nonce: opts.nonce, + }); + return tx; +} + +export async function buildTriggerPayoutTx(opts: { + senderKey: string; + circleId: number; + fee?: number; + nonce?: number; +}): Promise { + const tx = await makeContractCall({ + contractAddress: STACKS_CONTRACT_ADDRESS, + contractName: STACKS_CONTRACT_NAME, + functionName: "trigger-payout", + functionArgs: [uintCV(opts.circleId)], + senderKey: opts.senderKey, + network: STACKS_NETWORK, + anchorMode: AnchorMode.Any, + postConditionMode: PostConditionMode.Allow, + fee: opts.fee, + nonce: opts.nonce, + }); + return tx; +} + +export async function broadcastTx(opts: { + transaction: StacksTransactionWire; +}): Promise { + const result = await broadcastTransaction({ + transaction: opts.transaction, + network: STACKS_NETWORK, + }); + return result; +} + From d6b88aff715c67abd91a3673fa091aedaaaf3842 Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 05:40:46 +0100 Subject: [PATCH 2/6] feat(sdk): add Celo transaction parameter builder functions --- packages/sdk/src/index.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 337db72..318ad6f 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -177,3 +177,38 @@ export async function broadcastTx(opts: { return result; } +export function buildCeloCreateCircleParams(opts: { + name: string; + contributionWei: bigint; + roundDurationDays: number; + gracePeriodDays: number; + penaltyFee: bigint; + members: string[]; +}) { + return { + address: SUSUCHAIN_CELO_ADDRESS as `0x${string}`, + abi: SUSUCHAIN_CELO_ABI, + functionName: "createCircle" as const, + args: [ + opts.name, + opts.contributionWei, + BigInt(opts.roundDurationDays), + BigInt(opts.gracePeriodDays), + opts.penaltyFee, + opts.members as `0x${string}`[], + ], + }; +} + +export function buildCeloContributeParams(opts: { + circleId: number; + valueWei: bigint; +}) { + return { + address: SUSUCHAIN_CELO_ADDRESS as `0x${string}`, + abi: SUSUCHAIN_CELO_ABI, + functionName: "contribute" as const, + args: [BigInt(opts.circleId)], + value: opts.valueWei, + }; +} From 70d42b214281e02d9cde5debe18769ec26933c82 Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 05:41:08 +0100 Subject: [PATCH 3/6] chore(sdk): mark @stacks/connect as optional peer dependency --- packages/sdk/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/sdk/package.json b/packages/sdk/package.json index f59f87b..4a9c3bd 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -38,6 +38,11 @@ "@stacks/transactions": "^7.0.0", "@stacks/connect": "^8.0.0" }, + "peerDependenciesMeta": { + "@stacks/connect": { + "optional": true + } + }, "devDependencies": { "tsup": "^8.0.2", "typescript": "^5.0.0" From f5f6857f4098e0a74cdee6227ec0fdab18895a05 Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 05:41:41 +0100 Subject: [PATCH 4/6] test(sdk): validate new transaction builder exports in CJS and ESM --- packages/sdk/test-cjs.js | 26 +++++++++++++++++++++++++- packages/sdk/test-esm.mjs | 26 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/sdk/test-cjs.js b/packages/sdk/test-cjs.js index ffe6b08..fd64ded 100644 --- a/packages/sdk/test-cjs.js +++ b/packages/sdk/test-cjs.js @@ -1,4 +1,13 @@ -const { SUSUCHAIN_CELO_ADDRESS, STACKS_CONTRACT_NAME } = require("./dist/index.js"); +const { + SUSUCHAIN_CELO_ADDRESS, + STACKS_CONTRACT_NAME, + buildCreateCircleTx, + buildContributeTx, + buildTriggerPayoutTx, + broadcastTx, + buildCeloCreateCircleParams, + buildCeloContributeParams, +} = require("./dist/index.js"); if (SUSUCHAIN_CELO_ADDRESS !== "0x20B421Db767D3496E4489Db5C3122C1fD4625525") { throw new Error("Invalid Celo contract address exported in CommonJS module"); @@ -7,4 +16,19 @@ if (STACKS_CONTRACT_NAME !== "susuchain") { throw new Error("Invalid Stacks contract name exported in CommonJS module"); } +const builders = { + buildCreateCircleTx, + buildContributeTx, + buildTriggerPayoutTx, + broadcastTx, + buildCeloCreateCircleParams, + buildCeloContributeParams, +}; + +for (const [name, fn] of Object.entries(builders)) { + if (typeof fn !== "function") { + throw new Error(`Expected ${name} to be a function, got ${typeof fn}`); + } +} + console.log("CommonJS exports validated successfully."); diff --git a/packages/sdk/test-esm.mjs b/packages/sdk/test-esm.mjs index 7d9e892..6421ad2 100644 --- a/packages/sdk/test-esm.mjs +++ b/packages/sdk/test-esm.mjs @@ -1,4 +1,13 @@ -import { SUSUCHAIN_CELO_ADDRESS, STACKS_CONTRACT_NAME } from "./dist/index.mjs"; +import { + SUSUCHAIN_CELO_ADDRESS, + STACKS_CONTRACT_NAME, + buildCreateCircleTx, + buildContributeTx, + buildTriggerPayoutTx, + broadcastTx, + buildCeloCreateCircleParams, + buildCeloContributeParams, +} from "./dist/index.mjs"; if (SUSUCHAIN_CELO_ADDRESS !== "0x20B421Db767D3496E4489Db5C3122C1fD4625525") { throw new Error("Invalid Celo contract address exported in ES Module"); @@ -7,4 +16,19 @@ if (STACKS_CONTRACT_NAME !== "susuchain") { throw new Error("Invalid Stacks contract name exported in ES Module"); } +const builders = { + buildCreateCircleTx, + buildContributeTx, + buildTriggerPayoutTx, + broadcastTx, + buildCeloCreateCircleParams, + buildCeloContributeParams, +}; + +for (const [name, fn] of Object.entries(builders)) { + if (typeof fn !== "function") { + throw new Error(`Expected ${name} to be a function, got ${typeof fn}`); + } +} + console.log("ES Module exports validated successfully."); From f535138a87dda84eb1fbf7bb06c0e0e05e48e4f0 Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 05:42:30 +0100 Subject: [PATCH 5/6] docs(sdk): add server-side transaction builder usage documentation --- packages/sdk/README.md | 78 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 1637c0e..66c97c9 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -16,12 +16,14 @@ npm install susuchain-sdk viem @stacks/network @stacks/transactions @stacks/conn - **Multi-Chain ABI & Addresses**: Instantly access Solidity ABIs and mainnet contract addresses for both Celo and Stacks. - **Stacks Browser Helpers**: Pre-packaged wallet triggers to easily call `create-circle`, `contribute`, and `trigger-payout` using the Leather wallet. +- **Stacks Server-Side Builders**: Construct and sign Stacks transactions with a private key for backend or scripting environments. +- **Celo Transaction Param Builders**: Generate ready-to-use contract call parameter objects for viem wallet clients. ## Usage This SDK natively supports both **ES Modules (ESM)** and **CommonJS (CJS)** module systems. -### 📦 Importing the SDK +### Importing the SDK #### Using ES Modules (import) ```typescript @@ -33,7 +35,7 @@ import { SUSUCHAIN_CELO_ADDRESS, STACKS_CONTRACT_NAME } from 'susuchain-sdk'; const { SUSUCHAIN_CELO_ADDRESS, STACKS_CONTRACT_NAME } = require('susuchain-sdk'); ``` -### 🟡 Celo Integration (Viem) +### Celo Integration (Viem) You can easily interact with the SusuChain smart contract on Celo using `viem`: @@ -59,7 +61,39 @@ async function getCircleDetails(circleId: number) { } ``` -### 🟠 Stacks Integration (Leather Wallet) +### Celo Server-Side Transactions + +Build contract call parameters and pass them to a viem wallet client: + +```typescript +import { createWalletClient, http } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { celo } from 'viem/chains'; +import { buildCeloCreateCircleParams, buildCeloContributeParams } from 'susuchain-sdk'; + +const account = privateKeyToAccount('0x...'); +const wallet = createWalletClient({ account, chain: celo, transport: http() }); + +// Create a savings circle +const createParams = buildCeloCreateCircleParams({ + name: 'My Circle', + contributionWei: 1000000000000000000n, // 1 CELO + roundDurationDays: 30, + gracePeriodDays: 3, + penaltyFee: 0n, + members: ['0xAbc...', '0xDef...'], +}); +const hash = await wallet.writeContract(createParams); + +// Contribute to a circle +const contributeParams = buildCeloContributeParams({ + circleId: 0, + valueWei: 1000000000000000000n, +}); +const txHash = await wallet.writeContract(contributeParams); +``` + +### Stacks Integration (Leather Wallet) Trigger Stacks smart contract interactions directly inside any web app: @@ -82,6 +116,27 @@ callContribute(0, (data) => { }); ``` +### Stacks Server-Side Transactions + +Build, sign, and broadcast Stacks transactions from Node.js: + +```typescript +import { buildCreateCircleTx, buildContributeTx, broadcastTx } from 'susuchain-sdk'; + +// Build and sign a create-circle transaction +const tx = await buildCreateCircleTx({ + senderKey: 'your-private-key-hex', + name: 'Backend Circle', + contributionMicroSTX: 5_000_000, + members: ['SP2T02...', 'SP3...'], + fee: 2000, +}); + +// Broadcast the signed transaction +const result = await broadcastTx({ transaction: tx }); +console.log('Broadcast result:', result); +``` + ## Exported Constants ### Celo @@ -93,6 +148,23 @@ callContribute(0, (data) => { - `STACKS_CONTRACT_NAME`: The contract name (`"susuchain"`). - `STACKS_NETWORK`: The Stacks network configuration object (Mainnet). +## Exported Functions + +### Browser Helpers (Stacks) +- `callCreateCircle(name, contributionMicroSTX, members, onFinish)`: Open Leather wallet to create a circle. +- `callContribute(circleId, onFinish)`: Open Leather wallet to contribute. +- `callTriggerPayout(circleId, onFinish)`: Open Leather wallet to trigger payout. + +### Server-Side Builders (Stacks) +- `buildCreateCircleTx(opts)`: Build and sign a `create-circle` transaction. +- `buildContributeTx(opts)`: Build and sign a `contribute` transaction. +- `buildTriggerPayoutTx(opts)`: Build and sign a `trigger-payout` transaction. +- `broadcastTx(opts)`: Broadcast a signed transaction to the Stacks network. + +### Parameter Builders (Celo) +- `buildCeloCreateCircleParams(opts)`: Returns viem-compatible params for `createCircle`. +- `buildCeloContributeParams(opts)`: Returns viem-compatible params for `contribute`. + ## Tracking This release satisfies clean ES Modules and CommonJS packaging guidelines in alignment with issue #27. From 35e3e980e053403144ce952a4d9ed7b90dc25f47 Mon Sep 17 00:00:00 2001 From: Celo Composer Date: Thu, 4 Jun 2026 10:57:11 +0100 Subject: [PATCH 6/6] fix(sdk): remove deprecated anchorMode from server-side contract call options --- packages/sdk/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 318ad6f..57eabd6 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -118,7 +118,6 @@ export async function buildCreateCircleTx(opts: { ], senderKey: opts.senderKey, network: STACKS_NETWORK, - anchorMode: AnchorMode.Any, fee: opts.fee, nonce: opts.nonce, }); @@ -138,7 +137,6 @@ export async function buildContributeTx(opts: { functionArgs: [uintCV(opts.circleId)], senderKey: opts.senderKey, network: STACKS_NETWORK, - anchorMode: AnchorMode.Any, postConditionMode: PostConditionMode.Allow, fee: opts.fee, nonce: opts.nonce, @@ -159,7 +157,6 @@ export async function buildTriggerPayoutTx(opts: { functionArgs: [uintCV(opts.circleId)], senderKey: opts.senderKey, network: STACKS_NETWORK, - anchorMode: AnchorMode.Any, postConditionMode: PostConditionMode.Allow, fee: opts.fee, nonce: opts.nonce,