npm package: @sage-protocol/sdk
Description: Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).
Latest version: 0.3.1

# Sage Protocol SDK

Backend-agnostic helpers for interacting with Sage Protocol contracts, IPFS, and governance systems.

```bash
npm i @sage-protocol/sdk
```

## Quick Start

```js
import sdk from '@sage-protocol/sdk';

const provider = sdk.getProvider({ rpcUrl: 'https://base-sepolia.publicnode.com' });

// Discover SubDAOs
const subdaos = await sdk.subdao.discoverSubDAOs({
  provider,
  factoryAddress: '0x89Fd9FfD04503A62c52E6769401AB928abbeD5cA',
  fromBlock: 0,
});

// Fetch SubDAO info
const info = await sdk.subdao.getSubDAOInfo({ provider, subdao: subdaos[0].subdao });
```

**CommonJS**
```js
const sdk = require('@sage-protocol/sdk');
```

## Module Overview

| Module | Description |
|--------|-------------|
| `getProvider()` | Minimal ethers v6 RPC helper |
| `governance` | Governor metadata, proposals, voting |
| `timelock` | Queue operations, scheduling |
| `factory` | SubDAO creation and forking |
| `library` | Manifest listings, ownership |
| `lineage` | Fork ancestry, per-library fees |
| `prompt` | Prompt metadata, usage counters |
| `ipfs` | Upload, discovery, worker APIs |
| `subdao` | Discovery, staking, user stats |
| `token` | SXXX balances, allowances |
| `treasury` | Reserve snapshots, withdrawals |
| `reputation` | Author metrics, leaderboard, achievements |
| `boost` | Merkle/Direct boost helpers |
| `subgraph` | GraphQL queries |
| `services` | High-level SubgraphService + IPFSService |
| `adapters` | Normalized governance adapters |
| `errors` | `SageSDKError` codes |

## Services

### SubgraphService

```js
import { services } from '@sage-protocol/sdk';

const subgraphService = new services.SubgraphService({
  url: 'https://api.studio.thegraph.com/query/your-subgraph',
  timeout: 10000,
  retries: 3,
  cache: { enabled: true, ttl: 30000 },
});

const subdaos = await subgraphService.getSubDAOs({ limit: 50 });
const proposals = await subgraphService.getProposals({
  governor: '0xGovernor',
  states: ['ACTIVE', 'PENDING'],
});
```

### IPFSService

```js
import { services } from '@sage-protocol/sdk';

const ipfsService = new services.IPFSService({
  workerBaseUrl: 'https://api.sageprotocol.io',
  gateway: 'https://ipfs.io',
  signer: yourSigner, // Optional for uploads
});

// Fetch (parallel gateway race)
const content = await ipfsService.fetchByCID('QmTest123...');

// Upload
const cid = await ipfsService.upload(
  { title: 'My Prompt', content: '...' },
  { name: 'prompt.json', warm: true }
);
```

## Common Operations

### Governance

```js
// Compute proposal ID
const idHex = sdk.governance.computeProposalIdHex({ targets, values, calldatas, description });

// Preflight simulation
const pre = await sdk.governance.simulatePropose({ provider, governor, targets, values, calldatas, description, sender });

// Get votes
const votes = await sdk.governance.getVotesLatestMinusOne({ provider, governor, account: user });

// Self-delegate
const tx = await sdk.governance.buildDelegateSelfTx({ provider, governor, account: user });
```

### Auction Admin Updates

`SageAuctionHouse` live-rule setters are timelocked. Queueing a change does **not** update live config immediately.

```js
// Queue a reserve-price change
const queueTx = sdk.auction.buildSetReservePriceTx({
  auctionHouse: AUCTION_HOUSE,
  reservePrice: 5n * 10n ** 16n,
});

// After PARAMETER_CHANGE_DELAY has elapsed, execute it
const executeTx = sdk.auction.buildExecuteReservePriceUpdateTx({
  auctionHouse: AUCTION_HOUSE,
});

// The owner can cancel a queued change before execution
const cancelTx = sdk.auction.buildCancelReservePriceUpdateTx({
  auctionHouse: AUCTION_HOUSE,
});
```

The same queue/execute/cancel pattern applies to `timeBuffer`, `minBidIncrementPercentage` / `minBidIncrementBps`, and `duration`.

### Governance Boost Admin + Creation Helpers

Direct boost creation now requires an explicit non-zero `minVotes` value. The SDK validates this before encoding calldata.

```js
const createTx = sdk.boost.buildDirectCreateTx({
  manager: BOOST_MANAGER,
  governor: GOVERNOR,
  proposalId: 42n,
  perVoter: 5n * 10n ** 6n,
  maxVoters: 100n,
  minVotes: 1n,
});
```

Queued protocol rake changes on `GovernanceBoostManager` now have dedicated SDK builders:

```js
const queueTx = sdk.boost.buildDirectQueueProtocolRakeChangeTx({
  manager: BOOST_MANAGER,
  rakeBps: 250,
  protocolTreasury: TREASURY,
});

const executeTx = sdk.boost.buildDirectExecuteProtocolRakeChangeTx({
  manager: BOOST_MANAGER,
});

const cancelTx = sdk.boost.buildDirectCancelProtocolRakeChangeTx({
  manager: BOOST_MANAGER,
});
```

`buildDirectSetProtocolRakeTx(...)` is retained as a legacy alias for the queueing entrypoint.

### SubDAO Creation

```js
// Create operator SubDAO (team-controlled)
const res = await sdk.subdao.createOperatorSubDAO({
  signer,
  factoryAddress: FACTORY,
  operator: '0xSafeOrEOA',
  name: 'My SubDAO',
  description: 'Team controlled',
  burnAmount: 1500n * 10n**18n,
  sxxx: SXXX,
});
```

Note: if you call the factory's operator-creation functions directly (e.g., `createSubDAOOperator*`), you must pass a non-zero `operatorAdmin` (it may be the same as `operatorExecutor`).

### Library Fork Fees

```js
// Get fork fee for a library
const fee = await sdk.lineage.getLibraryForkFee({ provider, registry, subdao });

// Get full library info
const info = await sdk.lineage.getLibraryInfo({ provider, registry, subdao });
```

## React Hooks

Requires `react` and `swr` peer dependencies:

```js
import { services, hooks } from '@sage-protocol/sdk';

function SubDAOList() {
  const { data, error, isLoading } = hooks.useSubDAOs(subgraphService, { limit: 50 });

  if (isLoading) return <div>Loading...</div>;
  return <ul>{data.map(s => <li key={s.id}>{s.name}</li>)}</ul>;
}

function PromptViewer({ cid }) {
  const { data } = hooks.useFetchCID(ipfsService, cid);
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
```

| Hook | Description |
|------|-------------|
| `useSubDAOs` | Fetch SubDAOs from subgraph |
| `useProposals` | Fetch proposals from subgraph |
| `useFetchCID` | Fetch IPFS content by CID |
| `useUpload` | Upload content to IPFS |

## Error Handling

```js
import { serviceErrors } from '@sage-protocol/sdk';

try {
  const data = await subgraphService.getSubDAOs({ limit: 50 });
} catch (error) {
  if (error instanceof serviceErrors.SubgraphError) {
    console.error(`[${error.code}]:`, error.message);
  }
}
```

## Environment Variables

```bash
# Private transaction relay
SAGE_PRIVATE_RPC=https://builder.your-relay.example/rpc

# Explorer API (for ABI resolution)
NEXT_PUBLIC_ETHERSCAN_API_KEY=YourKey
```

## Design Principles

- Pure data in/out; no console prompts or environment coupling
- Minimal ABI fragments maintained alongside contracts
- Composable modules - import only what you need
- Edge runtime compatible (uses `fetch()`)

## Documentation

- [Full Docs](https://docs.sageprotocol.io)

## License

Apache 2.0