Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/slick-numbers-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@macalinao/clients-orca-whirlpools": patch
"@macalinao/clients-tribeca": patch
---

update package.json
17 changes: 17 additions & 0 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@
"@solana/kit": "*",
},
},
"clients/tribeca": {
"name": "@macalinao/clients-tribeca",
"version": "0.1.0",
"devDependencies": {
"@macalinao/coda": "workspace:^",
"@macalinao/eslint-config": "catalog:",
"@macalinao/tsconfig": "catalog:",
"@solana/kit": "catalog:",
"eslint": "catalog:",
"typescript": "catalog:",
},
"peerDependencies": {
"@solana/kit": "*",
},
},
"clients/voter-stake-registry": {
"name": "@macalinao/clients-voter-stake-registry",
"version": "0.2.2",
Expand Down Expand Up @@ -587,6 +602,8 @@

"@macalinao/clients-token-metadata": ["@macalinao/clients-token-metadata@workspace:clients/token-metadata"],

"@macalinao/clients-tribeca": ["@macalinao/clients-tribeca@workspace:clients/tribeca"],

"@macalinao/clients-voter-stake-registry": ["@macalinao/clients-voter-stake-registry@workspace:clients/voter-stake-registry"],

"@macalinao/coda": ["@macalinao/coda@workspace:packages/coda"],
Expand Down
2 changes: 2 additions & 0 deletions clients/orca-whirlpools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"description": "TypeScript client for Orca Whirlpools program",
"type": "module",
"sideEffects": false,
"author": "Ian Macalinao <[email protected]>",
"homepage": "https://coda.ianm.com",
"license": "Apache-2.0",
"keywords": [
"coda",
Expand Down
31 changes: 31 additions & 0 deletions clients/tribeca/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Dependencies
node_modules/
.pnp
.pnp.js

# Build output
dist/
*.tsbuildinfo

# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
bun.lockb

# Environment
.env
.env.local
.env.*.local

# IDE
.vscode/
.idea/
*.swp
*.swo
.DS_Store

# Cache
.turbo/
.eslintcache
89 changes: 89 additions & 0 deletions clients/tribeca/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# @macalinao/clients-tribeca

[![npm version](https://img.shields.io/npm/v/@macalinao/clients-tribeca.svg)](https://www.npmjs.com/package/@macalinao/clients-tribeca)

TypeScript client for Tribeca governance programs (Govern and Locked Voter), generated using Coda CLI with full ESM support.

## Installation

```bash
bun add @macalinao/clients-tribeca
```

## About Tribeca

Tribeca is a governance protocol on Solana that provides decentralized autonomous organization (DAO) functionality through two main programs:

- **Govern**: Core governance program for creating governors, proposals, and voting
- **Locked Voter**: Vote escrow system for token-weighted governance with time-locked voting power

## Programs Included

### Govern Program

- **Governor**: Manages proposals and voting parameters
- **Proposal**: Individual governance proposals with metadata
- **Vote**: Records individual voter decisions on proposals
- **ProposalMeta**: Additional metadata for proposals

### Locked Voter Program

- **Locker**: Manages vote escrows for a governance token
- **Escrow**: Individual user's locked tokens and voting power
- **Whitelist**: Programs authorized to interact with the locker

## Development

This client is generated from the Tribeca IDLs using Coda CLI:

```bash
# Generate the client from idls/
bun run codegen

# Build the TypeScript
bun run build
```

### Configuration

The `coda.config.mjs` file includes custom PDAs for both programs and links accounts to their corresponding PDA helpers.

## Usage

```typescript
import {
getCastVoteInstruction,
fetchGovernor,
fetchProposal,
getCreateEscrowInstruction,
fetchLocker,
} from "@macalinao/clients-tribeca";

// Governance example
const governor = await fetchGovernor(rpc, governorAddress);
const proposal = await fetchProposal(rpc, proposalAddress);

const voteInstruction = getCastVoteInstruction({
governor: governorAddress,
proposal: proposalAddress,
vote: voteAddress, // PDA automatically calculated
voter: voterPublicKey,
// ... other parameters
});

// Locked voter example
const locker = await fetchLocker(rpc, lockerAddress);

const escrowInstruction = getCreateEscrowInstruction({
locker: lockerAddress,
escrow: escrowAddress, // PDA automatically calculated
authority: authorityPublicKey,
// ... other parameters
});
```

## License

Copyright © 2025 Ian Macalinao

Licensed under the Apache License, Version 2.0
126 changes: 126 additions & 0 deletions clients/tribeca/coda.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
addPdasVisitor,
constantPdaSeedNodeFromString,
constantValueNode,
defineConfig,
numberTypeNode,
pdaLinkNode,
publicKeyTypeNode,
SYSTEM_PROGRAM_VALUE_NODE,
updateAccountsVisitor,
variablePdaSeedNode,
zeroableOptionTypeNode,
} from "@macalinao/coda";

export default defineConfig({
outputDir: "./src/generated",

// Add custom PDAs for Tribeca programs
visitors: [
addPdasVisitor({
lockedVoter: [
{
name: "locker",
docs: [
"Locker account that manages vote escrows for a specific base",
],
seeds: [
constantPdaSeedNodeFromString("utf8", "Locker"),
variablePdaSeedNode("base", publicKeyTypeNode()),
],
},
{
name: "escrow",
docs: ["Escrow account that holds locked tokens for a user"],
seeds: [
constantPdaSeedNodeFromString("utf8", "Escrow"),
variablePdaSeedNode("locker", publicKeyTypeNode()),
variablePdaSeedNode("authority", publicKeyTypeNode()),
],
},
{
name: "whitelist",
docs: [
"Whitelist entry for a program that can interact with the locker",
],
seeds: [
constantPdaSeedNodeFromString("utf8", "LockerWhitelistEntry"),
variablePdaSeedNode("locker", publicKeyTypeNode()),
variablePdaSeedNode("programId", publicKeyTypeNode()),
variablePdaSeedNode(
"owner",
zeroableOptionTypeNode(
publicKeyTypeNode(),
constantValueNode(
publicKeyTypeNode(),
SYSTEM_PROGRAM_VALUE_NODE,
),
),
),
],
},
],
govern: [
{
name: "governor",
docs: ["Governor account that manages proposals and voting"],
seeds: [
constantPdaSeedNodeFromString("utf8", "TribecaGovernor"),
variablePdaSeedNode("base", publicKeyTypeNode()),
],
},
{
name: "proposal",
docs: ["Proposal account for governance actions"],
seeds: [
constantPdaSeedNodeFromString("utf8", "TribecaProposal"),
variablePdaSeedNode("governor", publicKeyTypeNode()),
variablePdaSeedNode("index", numberTypeNode("u64")),
],
},
{
name: "vote",
docs: ["Vote account representing a voter's decision on a proposal"],
seeds: [
constantPdaSeedNodeFromString("utf8", "TribecaVote"),
variablePdaSeedNode("proposal", publicKeyTypeNode()),
variablePdaSeedNode("voter", publicKeyTypeNode()),
],
},
{
name: "proposalMeta",
docs: ["Proposal metadata account with additional information"],
seeds: [
constantPdaSeedNodeFromString("utf8", "TribecaProposalMeta"),
variablePdaSeedNode("proposal", publicKeyTypeNode()),
],
},
],
}),
updateAccountsVisitor({
// lockedVoter accounts
locker: {
pda: pdaLinkNode("locker"),
},
escrow: {
pda: pdaLinkNode("escrow"),
},
lockerWhitelistEntry: {
pda: pdaLinkNode("whitelist"),
},
// govern accounts
governor: {
pda: pdaLinkNode("governor"),
},
proposal: {
pda: pdaLinkNode("proposal"),
},
vote: {
pda: pdaLinkNode("vote"),
},
proposalMeta: {
pda: pdaLinkNode("proposalMeta"),
},
}),
],
});
31 changes: 31 additions & 0 deletions clients/tribeca/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { configs } from "@macalinao/eslint-config";

export default [
...configs.fast,
{
languageOptions: {
parserOptions: {
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ["src/generated/**/*.ts"],
rules: {
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/prefer-nullish-coalescing": "off",
},
},
{
files: [
"src/generated/instructions/*.ts",
"src/generated/types/*.ts",
"src/generated/errors/*.ts",
],
rules: {
"@typescript-eslint/no-unnecessary-condition": "off",
"no-constant-condition": "off",
"@typescript-eslint/no-empty-object-type": "off",
},
},
];
Loading