Organigram JS is the JavaScript/TypeScript client for the Organigram Protocol, a suite of smart contracts for running organizations on Ethereum-compatible blockchains. It deploys, reads and operates those contracts from any JavaScript environment, browser or Node.js, and is the library used under the hood by Organigram.ai and by @organigram/react.
pnpm add @organigram/js viem
viem is a peer dependency: Organigram JS never holds keys itself, it uses the viem clients you give it.
An organization is modelled as an organigram: a set of organs connected by procedures, optionally holding assets. Each of them is a smart contract, and each has a class in this library that loads its on-chain state, writes to it, and serializes it to JSON.
| Class | Role |
|---|---|
OrganigramClient | Entry point. Connects to the protocol on one chain, deploys contracts and loads them. |
Organigram | The whole organization: its organs, assets and procedures, as a draft or as deployed contracts. It has no contract of its own. |
Organ | A group: a registry of entries (members, documents), a list of permissions, and a balance of assets. |
Procedure | The rules by which the members of some organs may change other organs. |
NominationProcedure | A procedure where any one member of the deciders organ adopts or rejects a proposal alone. |
VoteProcedure | A procedure where the members of an organ vote. |
ERC20VoteProcedure | A procedure where votes are weighted by an ERC-20 token. |
Asset | An ERC-20 token, either a plain asset or company equity. |
OrganigramClient.load() connects to the OrganigramClient contract deployed on the chain of your viem public client, and reads the procedure types registered there. The public client is used for every read; the wallet client, when provided, signs the transactions. Without a wallet client, the library is read-only.
The client keeps loaded organs, procedures and assets in memory: loadOrgan(), loadProcedure() and loadAsset() return the cached object unless you pass { fresh: true }.
An organ stores three things:
PERMISSIONS (ADD_ENTRIES, WITHDRAW_ETHER, ADD_PERMISSIONS…). getPermissionsSet() turns a value back into names;In a governed organization, permissions are granted to procedures rather than to people, so that every change goes through a decision.
A procedure names three roles, each held by the members of an organ (or, for an ERC-20 vote, by the token holders): the proposers who may submit proposals, the moderators who may filter them when moderation is enabled, and the deciders who adopt or reject them. A proposal is a list of operations, calls to organs that the procedure has permission to make, plus a reference to its off-chain metadata.
propose() submits the proposal.presentProposal() or rejects it with blockProposal().nominate() or reject() for a nomination, vote() then count() once the vote is over for the vote procedures.applyProposal() retries the operations that were not processed yet.Every write also exists as a …BySig variant: the user signs an EIP-712 message and any relayer submits it, so users do not need gas.
organigram.deploy() deploys organs, assets and procedures in one transaction, then loads them back from the chain. Under the hood it calls client.deployOrganigram(), which you can call directly when you only need the new addresses. Contracts are deployed as clones at addresses predicted from a salt, which lets a draft reference contracts that do not exist yet, for example a procedure deciding on an organ deployed in the same batch. templates provides ready-made organigrams (sas, sarl, nonProfit, openSource…), and isTemplateSupportedOnChain() tells whether a chain has the contracts a template needs.
Contracts only store references. Metadata and documents live off-chain and are referenced by CID refs of the form og://workspace/<workspace>/<key>, built with formatCidRef() and read with parseCidRef(). Proposals must carry such a reference.
The encryption helpers (generateUserEncryptionKeyPair, wrapGroupKeyForRecipient, encryptBytes…) implement the end-to-end encryption of documents used by Organigram.ai: content keys encrypt documents, group keys wrap content keys, and each member's key pair unwraps group keys. They run on the Web Crypto API of the user's device. Keep private keys there: never send them to a server, never log them, and only export them to a storage you encrypt yourself.
Connect to the protocol with a browser wallet:
import { OrganigramClient } from '@organigram/js'import { createPublicClient, createWalletClient, custom, http } from 'viem'import { sepolia } from 'viem/chains'const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' })const publicClient = createPublicClient({ chain: sepolia, transport: http() })const walletClient = createWalletClient({ account, chain: sepolia, transport: custom(window.ethereum)})const client = await OrganigramClient.load({ publicClient, walletClient })
Deploy an organization from a template:
import { Organigram, getTemplate } from '@organigram/js'const organigram = await new Organigram({ ...getTemplate('nonProfit', client.chainId), organigramClient: client}).deploy()
Propose to add a member to an organ, then adopt the proposal through a nomination procedure:
import { NominationProcedure, Organ, Procedure, formatCidRef } from '@organigram/js'const procedure = (await client.loadProcedure( procedureAddress)) as NominationProcedureconst call = await Organ.populateTransaction(organAddress, walletClient, 'addEntries', [ { address: newMemberAddress }])const proposal = await procedure.propose({ cid: formatCidRef({ scopeType: 'workspace', scopeId: workspaceId }, 'add-member'), operations: [Procedure.createOperation(call)]})await procedure.nominate(proposal.key)
The procedure must hold the ADD_ENTRIES permission on the organ, and the connected account must belong to its proposers and deciders.
We are looking for TypeScript developers and testers to keep this project secure and up to date. Please open issues on GitHub, fork the repository and send pull requests.
Everything starts with an OrganigramClient, connected to the protocol on one chain through two viem clients: a public client to read, and a wallet client to sign. Without a wallet client, the library is read-only. The client deploys contracts, loads them, and keeps what it loaded in cache until you ask for a fresh read. Every write accepts TransactionOptions, to follow a transaction as soon as it is sent.
Main SDK entry point used to deploy and hydrate Organigram Protocol objects.
It keeps a public client, an optional wallet client, the registered procedure types for the current chain, and small in-memory caches for loaded organs, procedures, and assets.
constructor(input: { publicClient: PublicClient; address?: string; chainId?: string; procedureTypes?: ProcedureType[]; contract?: OrganigramContract; walletClient?: WalletClient; });
| Property | Type | Description |
|---|---|---|
address | string | Address of the OrganigramClient contract. |
assets | Asset[] | Assets loaded so far, kept in cache. |
chainId | string | Chain the client is connected to. |
contract | OrganigramContract | viem contract instance of the OrganigramClient contract. |
organs | Organ[] | Organs loaded so far, kept in cache. |
procedures | Procedure[] | Procedures loaded so far, kept in cache. |
procedureTypes | ProcedureType[] | Procedure types registered on this chain. |
publicClient | PublicClient | Client used for every read. |
walletClient | WalletClient | Client that signs transactions. Without it, the client is read-only. |
Deploy a single ERC-20 asset clone.
deployAsset(input: { name: string; symbol: string; initialSupply?: number; salt?: string; options?: TransactionOptions; }): Promise<string>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { name: string; symbol: string; initialSupply?: number; salt?: string; options?: TransactionOptions; } | Token name and symbol, supply in whole tokens before conversion to wei, optional deterministic clone salt and transaction controls. |
Returns
| Type | Description |
|---|---|
Promise<string> | The address of the deployed asset contract. |
Deploy several assets in one batch transaction.
deployAssets(assets: AssetInput[], options?: TransactionOptions): Promise<string[]>;
Parameters
| Name | Type | Description |
|---|---|---|
assets | AssetInput[] | Assets to deploy. |
options | TransactionOptions | Optional transaction controls. |
Returns
| Type | Description |
|---|---|
Promise<string[]> | The deployed asset addresses in deployment order. |
Deploy a fresh Organigram client contract together with its linked library.
static deployClient(input: { publicClient: PublicClient; walletClient: WalletClient; }): Promise<OrganigramClient>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { publicClient: PublicClient; walletClient: WalletClient; } | Clients used to broadcast deployments and wait for receipts. |
Returns
| Type | Description |
|---|---|
Promise<OrganigramClient> | A ready-to-use SDK instance pointing at the newly deployed client. |
Deploy a single organ clone and hydrate the resulting SDK object.
When no permissions are provided, the connected wallet is granted the full admin bitmask by default so the organ remains operable after deployment.
deployOrgan(input?: DeployOrganInput): Promise<Organ>;
Parameters
| Name | Type | Description |
|---|---|---|
input | DeployOrganInput | Optional organ metadata, permissions, entries, and transaction options. |
Deploy a full organigram, including its organs, assets, and procedures.
deployOrganigram(input: DeployOrganigramInput): Promise<DeployOrganigramResult>;
Parameters
| Name | Type | Description |
|---|---|---|
input | DeployOrganigramInput | Batch deployment input for the whole organigram. |
Returns
| Type | Description |
|---|---|
Promise<DeployOrganigramResult> | The deployed organ, asset, and procedure addresses, and the input updated with them. Use Organigram.deploy() to get a loaded Organigram. |
Deploy several organs in one batch transaction.
deployOrgans(deployOrgansInput: DeployOrganInput[]): Promise<Organ[]>;
Parameters
| Name | Type | Description |
|---|---|---|
deployOrgansInput | DeployOrganInput[] | Organ definitions to deploy. |
Deploy a single procedure clone from one registered procedure type.
deployProcedure(input: DeployProcedureInput): Promise<Procedure>;
Parameters
| Name | Type | Description |
|---|---|---|
input | DeployProcedureInput | Procedure type, role organs, optional metadata, and initialization args. |
Deploy several procedures in one batch transaction.
deployProcedures(deployProceduresInput: DeployProcedureInput[]): Promise<Procedure[]>;
Parameters
| Name | Type | Description |
|---|---|---|
deployProceduresInput | DeployProcedureInput[] | Procedure definitions to deploy. |
Estimate the gas a full organigram deployment would use, without a wallet.
estimateDeployOrganigramGas(input: DeployOrganigramInput, account: string): Promise<bigint>;
Parameters
| Name | Type | Description |
|---|---|---|
input | DeployOrganigramInput | Batch deployment input for the whole organigram. |
account | string | Address the deployment would be sent from. |
Returns
| Type | Description |
|---|---|
Promise<bigint> | The estimated gas, or 0n when nothing remains to deploy. |
Infer the registered procedure type of a deployed procedure clone.
getProcedureType(procedureAddress: string): Promise<ProcedureType | null>;
Parameters
| Name | Type | Description |
|---|---|---|
procedureAddress | string | Address of the deployed procedure instance. |
Connect the SDK to an already deployed Organigram client contract.
static load(input: { address?: string; publicClient: PublicClient; walletClient?: WalletClient; }): Promise<OrganigramClient>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { address?: string; publicClient: PublicClient; walletClient?: WalletClient; } | Address override plus the viem clients used for reads and writes. |
Load one deployed asset and keep it in the client cache.
loadAsset(address: string, input?: { fresh?: boolean; initial?: Asset; }): Promise<Asset>;
Parameters
| Name | Type | Description |
|---|---|---|
address | string | Asset contract address. |
input | { fresh?: boolean; initial?: Asset; } | fresh reads the chain even when the asset is cached; initial holds fallback metadata merged into the loaded asset. |
Attempt to load one deployed contract as an organ or procedure.
loadContract(address: string, input?: { fresh?: boolean; }): Promise<Organ | Procedure | null>;
Parameters
| Name | Type | Description |
|---|---|---|
address | string | Contract address to inspect. |
input | { fresh?: boolean; } | fresh reads the chain even when the contract is cached. |
Load a heterogeneous list of deployed contract addresses into an organigram.
loadContracts(contractAddresses: string[]): Promise<Organigram>;
Parameters
| Name | Type | Description |
|---|---|---|
contractAddresses | string[] | Addresses to resolve as organs, procedures, or assets. |
Load one deployed organ and keep it in the client cache.
loadOrgan(address: string, input?: { fresh?: boolean; initial?: OrganInput; }): Promise<Organ>;
Parameters
| Name | Type | Description |
|---|---|---|
address | string | Organ contract address. |
input | { fresh?: boolean; initial?: OrganInput; } | fresh reads the chain even when the organ is cached; initial holds fallback metadata merged into the loaded organ. |
Hydrate every deployed object referenced by an organigram definition.
Undeployed placeholders are preserved as-is, while deployed organs, procedures, and assets are refreshed from chain state.
loadOrganigram(organigram: Organigram, input?: { fresh?: boolean; }): Promise<Organigram>;
Parameters
| Name | Type | Description |
|---|---|---|
organigram | Organigram | Organigram definition to hydrate. |
input | { fresh?: boolean; } | fresh: false reuses the organs, procedures and assets already in the client cache instead of reading them again. |
Load one deployed procedure and keep it in the client cache.
loadProcedure(address: string, input?: { fresh?: boolean; initial?: ProcedureInput; }): Promise<Procedure>;
Parameters
| Name | Type | Description |
|---|---|---|
address | string | Procedure contract address. |
input | { fresh?: boolean; initial?: ProcedureInput; } | fresh reads the chain even when the procedure is cached; initial holds fallback metadata merged into the loaded procedure. |
Load metadata for one deployed procedure implementation.
static loadProcedureType(input: { addr: string; cid?: string; }, publicClient: PublicClient): Promise<ProcedureType>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { addr: string; cid?: string; } | Address and optional CID used to identify the procedure type. |
publicClient | PublicClient | Read-only client used for interface checks. |
Read the procedure registry and resolve every supported procedure type.
static loadProcedureTypes(input: { publicClient: PublicClient; address?: string; }): Promise<ProcedureType[]>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { publicClient: PublicClient; address?: string; } | Optional client contract address and the public client used to query it. |
Batch deployment input for a full organigram.
| Property | Type | Description |
|---|---|---|
assets | AssetInput[] | Assets to deploy. |
organs | DeployOrganInput[] | Organs to deploy. |
procedures | DeployProcedureInput[] | Procedures to deploy. |
Options shared by every write.
| Property | Type | Description |
|---|---|---|
nonce | number | Transaction nonce, to send several transactions at once. |
Called with the transaction as soon as it is sent, before it is mined.
onTransaction?: (tx: OrganigramTransaction, description: string) => void;
An organ to deploy: the same shape as everywhere else, plus transaction options.
export type DeployOrganInput = OrganInput & { options?: TransactionOptions;};
A procedure to deploy, plus transaction options and raw initialization arguments. Its typeName must be a known procedure type.
export type DeployProcedureInput = ProcedureInput & { typeName: ProcedureTypeName; options?: TransactionOptions; args?: unknown[];};
The input is copied with its new addresses: class instances come back as plain objects.
export type DeployOrganigramResult = readonly [ organs: string[], assets: string[], procedures: string[]] & { organigram: DeployOrganigramInput;};
The viem clients the SDK reads and writes with.
export type ContractClients = { publicClient: PublicClient; walletClient?: WalletClient | null;};
A viem contract instance bound to the SDK clients.
export type OrganigramContract = GetContractReturnType<Abi, PublicClient | { public: PublicClient; wallet: WalletClient;}>;
A sent transaction, with a wait() that resolves once it is mined.
export type OrganigramTransaction = { hash: Hex; wait: () => Promise<OrganigramTransactionReceipt>;};
The receipt of a mined transaction.
export type OrganigramTransactionReceipt = TransactionReceipt & { gasPrice?: bigint | null;};
Add a 20% margin plus 25,000 gas to a gas estimate.
bufferEstimatedGas: (estimatedGas: bigint) => bigint
Send a contract call with a buffered gas estimate, and return it as an OrganigramTransaction.
createContractWriteTransaction: <TAbi extends Abi | readonly unknown[]>(input: { address: string; abi: TAbi; functionName: string; args?: unknown[]; clients: ContractClients; nonce?: number; value?: bigint;}) => Promise<OrganigramTransaction>
Return the address of the account a wallet client signs with.
getWalletAddress: (walletClient: WalletClient) => Promise<Address>
An Organigram gathers the organs, procedures and assets of one organization. Start from a template with getTemplate(), or from your own data, attach a client, and deploy everything in one transaction with organigram.deploy(). Contracts are clones at addresses predicted from a salt, so that a draft can reference contracts that do not exist yet.
A whole organization: its organs, procedures and assets, as a draft or as deployed contracts.
The organigram itself has no contract. Create one from a template or from data, attach an OrganigramClient, then call deploy().
const organigram = await new Organigram({ ...getTemplate('nonProfit', client.chainId), organigramClient: client}).deploy()
constructor(input?: OrganigramInput | keyof typeof templates | string[]);
| Property | Type | Description |
|---|---|---|
assets | Asset[] | Assets of the organization. |
chainId | string | Chain the organigram is deployed on. |
description | string | Free description. |
edgeType | OrganigramEdgeType | Line style of the diagram links. |
id | string | Identifier of the organigram. |
name | string | Display name. |
nodePositions | OrganigramNodePositions | Positions of the diagram nodes. |
organigramClient | OrganigramClient | null | Client used to deploy and load the organigram. |
organs | Organ[] | Organs of the organization. |
procedures | Procedure[] | Procedures connecting the organs. |
publicClient | PublicClient | null | Client used for reads, when no organigramClient is attached. |
slug | string | URL-friendly name. |
walletClient | WalletClient | null | Client that signs transactions, when no organigramClient is attached. |
workspaceId | string | null | Workspace the organigram belongs to in the Organigram app. |
Deploy every contract of the organigram in one transaction, then read them back from chain.
Requires an attached organigramClient with a wallet client.
deploy(): Promise<Organigram>;
Change the name, description or diagram layout.
editDetails(input: { name?: string; description?: string; edgeType?: OrganigramEdgeType; nodePositions?: OrganigramNodePositions; contractAddresses?: string[]; }): void;
Read every deployed organ, procedure and asset of the organigram from chain.
load: (input?: { walletClient?: WalletClient | null; publicClient?: PublicClient | null; }) => Promise<Organigram>;
Replace the assets.
setAssets(assets: Asset[]): void;
Replace the organs.
setOrgans(organs: Organ[]): void;
Replace the procedures.
setProcedures(procedures: Procedure[]): void;
Convert the organigram into plain JSON.
toJson: () => OrganigramJson;
Line style of the links of an organigram.
export type OrganigramEdgeType = (typeof organigramEdgeTypes)[number];
The data of an organigram, such as a template from getTemplate().
export type OrganigramInput = { id?: string | null; slug?: string | null; name?: string | null; description?: string | null; edgeType?: string | null; nodePositions?: unknown; chainId?: string | null; organs: OrganInput[]; procedures: ProcedureInput[]; assets: AssetInput[]; organigramClient?: OrganigramClient | null; walletClient?: WalletClient | null; publicClient?: PublicClient | null; contractAddresses?: string[] | null; workspaceId?: string | null;};
An organigram as plain JSON, to store or send it.
export type OrganigramJson = { id: string; slug: string; name: string; description: string; edgeType: OrganigramEdgeType; nodePositions: OrganigramNodePositions; chainId: string; organs: OrganJson[]; procedures: ProcedureJson[]; assets: AssetJson[]; workspaceId?: string | null;};
Position of one node in the organigram diagram.
export type OrganigramNodePosition = { x: number; y: number;};
Positions of the nodes in the organigram diagram, by contract address.
export type OrganigramNodePositions = Record<string, OrganigramNodePosition>;
The three roles of a procedure: who proposes, who moderates, who decides.
export type ProcedureRoleTypeName = 'proposers' | 'moderators' | 'deciders';
Chain used by templates when none is given.
const defaultChainId: string
Line style used when none is set.
const defaultOrganigramEdgeType: OrganigramEdgeType
Line styles available to draw the links of an organigram.
const organigramEdgeTypes: readonly ["default", "straight", "step", "smoothstep"]
Name of a template.
export type TemplateName = keyof typeof templates;
Return a copy of a template, with new salts and addresses for the given chain.
getTemplate: (templateName: TemplateName, chainId: string) => OrganigramInput
Tell whether a chain has every protocol contract a template needs.
isTemplateSupportedOnChain: (templateName: TemplateName, chainId: string) => boolean
Give every contract of an organigram a new salt and address, and update the references between them.
renewSaltsAndAddresses: (organigram: OrganigramInput, chainId: string) => OrganigramInput
Ready-made organigrams, from company forms (sas, sarl…) to registers.
An organ is a group: a registry of entries, each a member, a document or both, a list of permissions, and a balance of assets. Each change requires a permission from PERMISSIONS. In a governed organization, those permissions belong to procedures rather than to people, so that every change goes through a decision.
A group of the organization: a registry of members and documents, a list of permissions, and a balance of assets.
Every change to an organ must come from an address holding the matching permission. In a governed organization, that address is a procedure, so that each change goes through a decision.
constructor(input: OrganInput);
| Property | Type | Description |
|---|---|---|
address | string | Contract address, or a predicted address while it is a draft. |
balance | string | Ether balance, in wei. |
chainId | string | Chain the organ lives on. |
cid | string | Reference to the off-chain metadata of the organ. |
contract | OrganigramContract | viem contract instance, once loaded. |
description | string | Free description. |
entries | OrganEntry[] | Members and documents registered in the organ. |
forwarder | string | Trusted forwarder relaying gasless transactions. |
INTERFACE | string | ERC-165 interface identifier of organ contracts. |
isDeployed | boolean | Whether the contract exists on chain. |
name | string | Display name. |
organigramId | string | Organigram the organ belongs to. |
permissions | OrganPermission[] | Addresses allowed to act on the organ, with their permission flags. |
publicClient | PublicClient | Client used for reads. |
salt | string | undefined | Salt that determines the clone address. |
walletClient | WalletClient | Client that signs transactions. |
Add members or documents to the registry.
addEntries: (entries: OrganEntryInput[], options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Grant permissions to an address.
addPermission: (permission: OrganPermission, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Read the permission flags an address holds on an organ.
static checkAddressPermissions(organAddress: string, addressToCheck: string, clients: ContractClients): Promise<number>;
Read the ether balance of an organ, in wei.
static getBalance(address: string, clients: ContractClients): Promise<bigint>;
Tell whether a contract is an organ.
static isOrgan(address: string, clients: ContractClients): Promise<boolean>;
Read an organ from chain: its entries, permissions and metadata.
static load(address: string, clients: ContractClients, initialOrgan?: OrganInput): Promise<Organ>;
Read the metadata reference and registry sizes of an organ.
static loadData(address: string, clients: ContractClients): Promise<OrganContractData>;
Read every entry of an organ.
static loadEntries(address: string, clients: ContractClients, data?: OrganContractData): Promise<OrganEntry[]>;
Read one entry of an organ, by index.
static loadEntry(address: string, index: string, clients: ContractClients): Promise<OrganEntry>;
Find the entry of an address in an organ, if it is a member.
static loadEntryForAccount(address: string, account: string, clients: ContractClients): Promise<OrganEntry | undefined>;
Read one permission of an organ, by index.
static loadPermission(address: string, index: string, clients: ContractClients): Promise<OrganPermission>;
Read every permission of an organ.
static loadPermissions(address: string, clients: ContractClients, data?: OrganContractData): Promise<OrganPermission[]>;
Encode a call to an organ function, to use it as a proposal operation with Procedure.createOperation().
const call = await Organ.populateTransaction(organAddress, walletClient, 'addEntries', [ { address: memberAddress }])const operation = Procedure.createOperation(call)
static populateTransaction(address: string, walletClient: WalletClient, functionName: OrganFunctionName | string, ...args: unknown[]): Promise<{ to: string; data: string; functionName: string; }>;
Read the whole organ again from chain.
reload(): Promise<Organ>;
Read the metadata reference again from chain.
reloadData(): Promise<Organ>;
Read the entries again from chain.
reloadEntries(): Promise<Organ>;
Read the permissions again from chain.
reloadPermissions(): Promise<Organ>;
Remove entries from the registry, by index.
removeEntries: (indexes: string[], options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Revoke every permission of an address.
removePermission: (permission: string, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Replace one entry of the registry.
replaceEntry: (index: number, entry: OrganEntryInput, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Move permissions from one address to another.
replacePermission: (oldPermissionAddress: string, newOrganPermission: OrganPermission, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Convert the organ into plain JSON.
toJson: () => OrganJson;
Replace the reference to the off-chain metadata of the organ.
updateCid: (cid: string, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Send ERC-20 tokens held by the organ.
withdrawERC20: (token: string, to: string, amount: string | number | bigint, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Send an ERC-721 token held by the organ.
withdrawERC721: (token: string, to: string, tokenId: string | number | bigint, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
Send ether held by the organ.
withdrawEther: (to: string, value: string | number | bigint, options?: TransactionOptions) => Promise<OrganigramTransactionReceipt>;
One entry of an organ registry: a member, a document, or both.
| Property | Type | Description |
|---|---|---|
address | string | Ethereum address of the member, or the zero address. |
cid | string | Reference to a document, or an empty string. |
index | string | Position in the registry, starting at 1. |
name | string | null | Display name. |
An entry to add to an organ: an address, a document reference, or both.
| Property | Type | Description |
|---|---|---|
address | string | Ethereum address of the member. |
cid | string | Reference to a document. |
The data of an organ, deployed or still a draft.
| Property | Type | Description |
|---|---|---|
address | string | null | Contract address, or a predicted address while it is a draft. |
balance | string | null | Ether balance, in wei. |
chainId | string | null | Chain the organ lives on. |
cid | string | null | Reference to the off-chain metadata of the organ. |
description | string | null | Free description. |
entries | Array<{ index: string; address: string; cid: string; name?: string | null; }> | null | Members and documents registered in the organ. |
forwarder | string | null | Trusted forwarder relaying gasless transactions. |
isDeployed | boolean | null | Whether the contract exists on chain. |
name | string | null | Display name. |
organigramId | string | null | Organigram the organ belongs to. |
permissions | OrganPermission[] | null | Addresses allowed to act on the organ, with their permission flags. |
publicClient | PublicClient | null | Client used for reads. |
salt | string | null | Salt that determines the clone address. |
walletClient | WalletClient | null | Client that signs transactions. |
An organ as plain JSON, to store or send it.
| Property | Type | Description |
|---|---|---|
address | string | Contract address, or a predicted address while it is a draft. |
balance | string | Ether balance, in wei. |
chainId | string | Chain the organ lives on. |
cid | string | Reference to the off-chain metadata of the organ. |
description | string | Free description. |
entries | OrganEntry[] | Members and documents registered in the organ. |
isDeployed | boolean | Whether the contract exists on chain. |
name | string | Display name. |
organigramId | string | Organigram the organ belongs to. |
permissions | OrganPermission[] | Addresses allowed to act on the organ, with their permission flags. |
salt | string | null | Salt that determines the clone address. |
The permissions one address holds on an organ.
| Property | Type | Description |
|---|---|---|
permissionAddress | string | Address granted the permissions, usually a procedure. |
permissionValue | number | Bit field of PERMISSIONS flags. |
The organ functions a proposal operation can call.
| Name | Value | Description |
|---|---|---|
addEntries | "addEntries" | Add entries. |
addPermission | "addPermission" | Grant permissions to an address. |
removeEntries | "removeEntries" | Remove entries. |
removePermission | "removePermission" | Revoke the permissions of an address. |
replaceEntry | "replaceEntry" | Replace one entry. |
replacePermission | "replacePermission" | Move permissions to another address. |
withdrawERC20 | "withdrawERC20" | Send ERC-20 tokens. |
withdrawERC721 | "withdrawERC721" | Send an ERC-721 token. |
withdrawEther | "withdrawEther" | Send ether. |
List the names of the permissions in a permission value.
getPermissionsSet: (permissions: number) => string[]
Bit flags of the permissions an address can hold on an organ. Combine them with |.
PERMISSIONS.ADD_ENTRIES | PERMISSIONS.REMOVE_ENTRIES
A procedure lets the members of some organs change other organs. Proposers submit a proposal, a list of operations built with Procedure.createOperation(). With moderation, a moderator presents or blocks it. Deciders then adopt or reject it, alone in a NominationProcedure, by vote in a VoteProcedure, or by token-weighted vote in an ERC20VoteProcedure, and adoption runs the operations. Every action also exists as a signed variant: the user signs with a sign… method, and any account submits the signature with the matching …BySig method, so that users need no gas.
The rules by which the members of some organs may change other organs.
A proposal is a list of operations. Proposers submit it with propose(). With moderation, a moderator presents it with presentProposal() or blocks it with blockProposal(). Deciders then adopt or reject it, depending on the procedure type, and adoption runs its operations. Every action also has a signed variant (sign… then …BySig), so that a relayer submits it and users need no gas.
constructor(input: ProcedureInput);
| Property | Type | Description |
|---|---|---|
address | string | Contract address, or a predicted address while it is a draft. |
chainId | string | Chain the procedure lives on. |
cid | string | Reference to the off-chain metadata of the procedure. |
contract | OrganigramContract | viem contract instance, once loaded. |
data | string | Parameters specific to the procedure type, as a JSON string, such as the vote duration. |
deciders | string | Organ whose members adopt or reject proposals, or a single address. |
description | string | Free description. |
forwarder | string | Trusted forwarder relaying gasless transactions. |
INTERFACE | string | ERC-165 interface identifier of procedure contracts. |
isDeployed | boolean | Whether the contract exists on chain. |
metadata | string | Off-chain metadata, as a JSON string. |
moderators | string | Organ whose members may present or block proposals, when moderation is enabled. |
name | string | Display name. |
OPERATIONS_FUNCTIONS | ProcedureProposalOperationFunction[] | Functions a proposal operation can call, with what a form needs to build them. |
organigramId | string | Organigram the procedure belongs to. |
proposals | ProcedureProposal[] | Proposals submitted so far. |
proposers | string | Organ whose members may submit proposals, or a single address. |
publicClient | PublicClient | Client used for reads. |
salt | string | Salt that determines the clone address. |
type | ProcedureType | Registered procedure type this procedure is a clone of. |
typeName | ProcedureTypeName | Procedure type: nomination, vote or erc20Vote. |
walletClient | WalletClient | Client that signs transactions. |
withModeration | boolean | Whether proposals must be presented by a moderator before the decision. |
Settle a proposal: for a vote, count the ballots once it is over, then run or close it.
applyProposal(proposalKey: string, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Settle a proposal, with an application signed by another account.
applyProposalBySig(input: SignedProposalActionInput & { signature: string; }, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Block a proposal as a moderator, before its decision.
blockProposal(proposalKey: string, reason: string, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Block a proposal signed by a moderator.
blockProposalBySig(input: SignedBlockProposalInput & { signature: string; }, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Build an operation that makes an organ call a contract outside the organization.
static createExternalCallOperation(input: ExternalCallOperationInput): ProcedureProposalOperation;
Turn a contract call, such as the result of Organ.populateTransaction(), into a proposal operation.
static createOperation(input: { to: string; data: string; value?: number | string | bigint; index?: number | string; }): ProcedureProposalOperation;
The viem clients of the procedure.
protected getClients(): ContractClients;
Read the next signature nonce of an account.
getNonce(account: string): Promise<bigint>;
EIP-712 domain of the signatures of this procedure.
getTypedDataDomain(): { name: string; version: string; chainId: bigint; verifyingContract: `0x${string}`; };
Tell whether a contract is a procedure.
static isProcedure(address: string, clients: ContractClients): Promise<boolean>;
Read a procedure from chain, with its proposals.
static load(address: string, clients: ContractClients, initialProcedure?: ProcedureInput): Promise<Procedure>;
Read the roles, metadata reference and proposal count of a procedure.
static loadData(address: string, clients: ContractClients): Promise<ProcedureContractData>;
Read one proposal of a procedure.
static loadProposal(address: string, proposalKey: string, clients: ContractClients): Promise<ProcedureProposal>;
Read every proposal of a procedure.
static loadProposals(address: string, clients: ContractClients, data?: ProcedureContractData): Promise<ProcedureProposal[]>;
Normalize an operation read from chain.
static parseOperation(rawOperation: unknown): ProcedureProposalOperation;
Present a proposal to the deciders, as a moderator.
presentProposal(proposalKey: string, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Present a proposal signed by a moderator.
presentProposalBySig(input: SignedProposalActionInput & { signature: string; }, options?: TransactionOptions): Promise<OrganigramTransactionReceipt>;
Submit a proposal.
propose(input: { cid: string; operations: ProcedureProposalOperation[]; options?: TransactionOptions; }): Promise<ProcedureProposal>;
Parameters
| Name | Type | Description |
|---|---|---|
input | { cid: string; operations: ProcedureProposalOperation[]; options?: TransactionOptions; } | Reference to the proposal metadata, which must be a CID reference, and its operations. |
Submit a proposal signed by another account.
proposeBySig(input: SignedProposalInput & { signature: string; }): Promise<OrganigramTransaction>;
Read the roles and metadata reference again from chain.
reloadData(): Promise<Procedure>;
Read one proposal again from chain.
reloadProposal(proposalKey: string): Promise<Procedure>;
Read every proposal again from chain.
reloadProposals(): Promise<Procedure>;
Sign the application of a proposal, for applyProposalBySig().
signApplyProposal(input: SignedProposalActionInput): Promise<string>;
Sign the block of a proposal, for blockProposalBySig().
signBlockProposal(input: SignedBlockProposalInput): Promise<string>;
Sign the presentation of a proposal, for presentProposalBySig().
signPresentProposal(input: SignedProposalActionInput): Promise<string>;
Sign a proposal, so that another account submits it with proposeBySig().
The signer pays no gas: any account can submit the signature with the matching …BySig method.
signProposal(input: SignedProposalInput): Promise<string>;
Convert the procedure into plain JSON.
toJson: () => ProcedureJson;
A call to a contract outside the organization, made by an organ.
| Property | Type | Description |
|---|---|---|
data | string | Encoded call. |
index | string | number | Position of the operation in the proposal. |
organAddress | string | Organ making the call. It must allow this call in its execution whitelist. |
target | string | Contract called. |
value | string | bigint | number | Ether sent with the call, in wei. |
One decoded parameter of an operation, to display or edit it.
| Property | Type | Description |
|---|---|---|
action | OperationParamAction | What the parameter is used for. |
parser | unknown | Function turning the form value into the call argument. |
type | OperationParamType | Kind of the parameter. |
value | unknown | Decoded value. |
The data of a procedure, deployed or still a draft.
| Property | Type | Description |
|---|---|---|
address | string | null | Contract address, or a predicted address while it is a draft. |
chainId | string | null | Chain the procedure lives on. |
cid | string | null | Reference to the off-chain metadata of the procedure. |
data | string | null | Parameters specific to the procedure type, as a JSON string, such as the vote duration. |
deciders | string | Organ whose members adopt or reject proposals, or a single address. |
description | string | null | Free description. |
forwarder | string | null | Trusted forwarder relaying gasless transactions. |
isDeployed | boolean | null | Whether the contract exists on chain. |
metadata | string | null | Off-chain metadata, as a JSON string. |
moderatorMode | ERC20VoteRoleMode | null | Whether moderators are organ members, token holders, or nobody. |
moderators | string | null | Organ whose members may present or block proposals, when moderation is enabled. |
name | string | null | Display name. |
organigramId | string | null | Organigram the procedure belongs to. |
proposals | ProcedureProposal[] | null | Proposals submitted so far. |
proposerMode | ERC20VoteRoleMode | null | Whether proposers are organ members, token holders, or nobody. |
proposers | string | null | Organ whose members may submit proposals, or a single address. |
publicClient | PublicClient | null | Client used for reads. |
requireMemberMajority | boolean | null | Whether a majority of the deciders organ must also approve, besides the token-weighted vote. |
salt | string | null | Salt that determines the clone address. |
type | ProcedureType | Registered procedure type this procedure is a clone of. |
typeName | string | Procedure type: nomination, vote or erc20Vote. |
voterMode | ERC20VoteRoleMode | null | Whether voters are organ members or token holders. |
walletClient | WalletClient | null | Client that signs transactions. |
withModeration | boolean | null | Whether proposals must be presented by a moderator before the decision. |
A proposal submitted to a procedure, and where it stands.
| Property | Type | Description |
|---|---|---|
adopted | boolean | Whether the deciders adopted it. |
applied | boolean | Whether it is settled: operations run if adopted, closed if rejected. |
blocked | boolean | Whether a moderator blocked it. |
blockReason | string | Why a moderator blocked it. |
cid | string | Reference to its off-chain metadata. |
creator | string | Address that submitted it. |
key | string | Identifier of the proposal in its procedure. |
metadata | ProposalMetadata | Off-chain metadata, once loaded. |
operations | ProcedureProposalOperation[] | Calls made once adopted. |
presented | boolean | Whether it reached the deciders, after moderation if enabled. |
transactionHash | string | Hash of the transaction that submitted it. |
One call a proposal makes once adopted.
Build it with Procedure.createOperation() rather than by hand.
| Property | Type | Description |
|---|---|---|
data | string | Encoded call. |
description | string | Explanation shown to the user. |
function | ProcedureProposalOperationFunction | The function called, when it is a known one. |
functionSelector | string | Four-byte selector of the function called. |
index | string | Position in the proposal. |
params | OperationParam[] | Decoded parameters, to display them. |
processed | boolean | Whether the call has run. |
target | string | Contract called. The zero address calls the procedure itself. |
value | string | Ether sent with the call, in wei. |
A function a proposal operation can call, with what a form needs to build the call.
| Property | Type | Description |
|---|---|---|
abi | unknown | ABI fragment, for functions outside the organ contract. |
funcSig | string | Four-byte function selector. |
key | OperationKey | Function name. |
label | string | Display label. |
params | OperationParamType[] | Kinds of its parameters, in order. |
signature | string | Solidity signature. |
tags | OperationTag[] | Keywords describing the function. |
target | 'organ' | 'self' | Whether the call targets an organ or the procedure itself. |
A procedure implementation registered on a chain, which procedures are cloned from.
| Property | Type | Description |
|---|---|---|
address | string | Address of the implementation contract. |
fields | { [key: string]: ProcedureTypeField; } | Parameters specific to the type, by name. |
key | string | Procedure type name. |
metadata | { cid?: string; label?: string; description?: string; } | Label, description and metadata reference of the type. |
A parameter of a procedure type, as shown in a form, such as the vote duration.
| Property | Type | Description |
|---|---|---|
defaultValue | string | Value used when none is given. |
description | string | Explanation shown to the user. |
label | string | Display label. |
name | string | Key of the parameter in the procedure data. |
type | 'string' | 'number' | 'boolean' | 'roleMode' | 'moderatorRoleMode' | Input kind. |
What a proposal says, stored off-chain: title, description and attachments.
| Property | Type | Description |
|---|---|---|
cid | string | Reference to an attached file. |
description | string | Description. |
discussion | string | Link to a discussion. |
file | string | Attached file name. |
subtitle | string | Subtitle. |
title | string | Title. |
A proposal block to sign, so that another account submits it.
Extends SignedProposalActionInput.
| Property | Type | Description |
|---|---|---|
reason | string | Why the proposal is blocked. |
An action on a proposal to sign, so that another account submits it.
| Property | Type | Description |
|---|---|---|
deadline | bigint | number | Unix time, in seconds, after which the signature is refused. |
nonce | bigint | Current signature nonce of the signer, from getNonce(). |
proposalKey | string | Proposal the action applies to. |
A proposal to sign, so that another account submits it.
| Property | Type | Description |
|---|---|---|
cid | string | Reference to the proposal metadata. |
deadline | bigint | number | Unix time, in seconds, after which the signature is refused. |
nonce | bigint | Current signature nonce of the signer, from getNonce(). |
operations | ProcedureProposalOperation[] | Operations of the proposal. |
The roles an account holds in a procedure.
export type AccountInOrgans = { moderators?: boolean; proposers?: boolean; deciders?: boolean;};
The state of the vote on one proposal.
export type Election = { proposalKey: string; start: string; votesCount: string; hasVoted: boolean; approvals?: string; objections?: string; eligibleVotes?: string; approved?: boolean;};
The function an operation calls, as listed in Procedure.OPERATIONS_FUNCTIONS.
export type OperationKey = 'addEntries' | 'removeEntries' | 'replaceEntry' | 'addPermission' | 'removePermission' | 'replacePermission' | 'updateMetadata' | 'withdrawEther' | 'withdrawERC20' | 'withdrawERC721' | 'externalCall' | string;
What an operation parameter is used for in a form.
export type OperationParamAction = 'select' | 'create' | 'update' | 'delete' | 'withdraw' | 'deposit' | 'transfer' | 'block';
Kind of a parameter of an operation, used to build its form.
export type OperationParamType = 'cid' | 'entry' | 'entries' | 'address' | 'bytes' | 'addresses' | 'index' | 'indexes' | 'organ' | 'oldPermissionAddress' | 'newPermissionAddress' | 'permissionAddress' | 'permissionValue' | 'proposal' | 'proposals' | 'amount' | 'tokenId';
Keyword describing what an operation does, used to filter and label it.
export type OperationTag = 'cid' | 'entries' | 'permissions' | 'coins' | 'collectibles' | 'erc721' | 'erc20' | 'erc1155' | 'ether' | 'add' | 'replace' | 'remove' | 'deposit' | 'withdraw' | 'transfer';
A procedure as plain JSON, to store or send it.
export type ProcedureJson = { isDeployed: boolean; address: string; deciders: string; typeName: ProcedureTypeName; name: string; description: string; cid: string; salt?: string | null; chainId: string; data: string; metadata?: string; proposers: string; moderators: string; withModeration: boolean; proposerMode?: ERC20VoteRoleMode; moderatorMode?: ERC20VoteRoleMode; voterMode?: ERC20VoteRoleMode; requireMemberMajority?: boolean; forwarder: string; proposals?: ProcedureProposal[]; args?: unknown[]; type: ProcedureType; organigramId?: string | null;};
A procedure in which any one member of the deciders adopts or rejects a proposal alone.
constructor(procedureInput: ProcedureInput);
| Property | Type | Description |
|---|---|---|
contract | OrganigramContract | viem contract instance, once loaded. |
INTERFACE | string | ERC-165 interface identifier of nomination procedures. |
typeName | ProcedureTypeName | Always nomination. |
Read a nomination procedure from chain, with its proposals.
static load(address: string, clients: ContractClients, initialProcedure?: ProcedureInput): Promise<NominationProcedure>;
Adopt a proposal as a decider, which runs its operations.
nominate(proposalKey: string, options?: TransactionOptions): Promise<void>;
Adopt a proposal with an adoption signed by a decider.
nominateBySig(input: { proposalKey: string; nonce: bigint; deadline: bigint | number; signature: string; }): Promise<void>;
Reject a proposal as a decider.
reject(proposalKey: string, options?: TransactionOptions): Promise<void>;
Sign the adoption of a proposal, for nominateBySig().
The signer pays no gas: any account can submit the signature with the matching …BySig method.
signNomination(input: { proposalKey: string; nonce: bigint; deadline: bigint | number; }): Promise<string>;
A procedure in which the members of the deciders organ vote on each proposal.
The vote opens when a proposal is presented. Once it is over, anyone calls applyProposal() to count the ballots and settle the proposal.
constructor(input: VoteProcedureInput);
| Property | Type | Description |
|---|---|---|
contract | OrganigramContract | viem contract instance, once loaded. |
elections | Election[] | State of the vote on each proposal. |
INTERFACE | string | ERC-165 interface identifier of vote procedures. |
majoritySize | string | Share of the ballots that must approve, in thousandths of a percent. |
quorumSize | string | Share of the voters who must vote, in thousandths of a percent. |
typeName | ProcedureTypeName | Always vote. |
voteDuration | string | Duration of the vote, in seconds. |
Tell whether a proposal passed, once its vote is over.
count(proposalKey: string): Promise<boolean>;
Read a vote procedure from chain, with its proposals and elections.
static load(address: string, clients: ContractClients, initialProcedure?: ProcedureInput): Promise<VoteProcedure>;
Read the state of the vote on one proposal.
static loadElection(address: string, proposalKey: string, clients: ContractClients, voteDuration?: bigint, contract?: OrganigramContract, blockTimestamp?: bigint): Promise<Election>;
Read the state of the vote on every proposal.
static loadElections(address: string, clients: ContractClients, proposalsLength?: number): Promise<Election[]>;
Sign a vote, for voteBySig().
The signer pays no gas: any account can submit the signature with the matching …BySig method.
signVote(input: { proposalKey: string; approval: boolean; nonce: bigint; deadline: bigint | number; }): Promise<string>;
Convert the procedure into plain JSON.
toJson: () => ProcedureJson;
Vote for or against a proposal, as a decider.
vote(proposalKey: string, choice: 'for' | 'against', options?: TransactionOptions): Promise<void>;
Cast a vote signed by a decider.
voteBySig(input: { proposalKey: string; approval: boolean; nonce: bigint; deadline: bigint | number; signature: string; }): Promise<void>;
The data of a vote procedure.
export type VoteProcedureInput = ProcedureInput & { quorumSize: string; voteDuration: string; majoritySize: string; elections: Election[];};
A vote procedure in which each ballot weighs the token balance of the voter.
Ballots weigh the balances held just before the vote opened, so tokens moved during the vote do not count twice.
constructor(input: ERC20VoteProcedureInput);
| Property | Type | Description |
|---|---|---|
contract | OrganigramContract | viem contract instance, once loaded. |
erc20 | string | Token whose balances weigh the votes. |
INTERFACE | string | ERC-165 interface identifier of ERC-20 vote procedures. |
moderatorMode | ERC20VoteRoleMode | Whether moderators are organ members, token holders, or nobody. |
proposerMode | ERC20VoteRoleMode | Whether proposers are organ members, token holders, or nobody. |
requireMemberMajority | boolean | Whether a majority of the deciders organ must also approve, besides the token-weighted vote. |
typeName | ProcedureTypeName | Always erc20Vote. |
voterMode | ERC20VoteRoleMode | Whether voters are organ members or token holders. |
Read the token balance of an account, or of the connected wallet.
erc20Balance(account?: string): Promise<bigint>;
Read an ERC-20 vote procedure from chain, with its proposals and elections.
static load(address: string, clients: ContractClients, initialProcedure?: ProcedureInput): Promise<ERC20VoteProcedure>;
Convert the procedure into plain JSON.
toJson: () => ProcedureJson;
Vote for or against a proposal, with the weight of your tokens.
vote(proposalKey: string, choice: 'for' | 'against', options?: TransactionOptions): Promise<void>;
The data of an ERC-20 vote procedure.
export type ERC20VoteProcedureInput = Omit<VoteProcedureInput, 'type' | 'typeName'> & { erc20: string; proposerMode?: ERC20VoteRoleMode; moderatorMode?: ERC20VoteRoleMode; voterMode?: ERC20VoteRoleMode; requireMemberMajority?: boolean;};
Everything needed to encode the initialization of a procedure clone.
| Property | Type | Description |
|---|---|---|
args | unknown[] | Parameters specific to the procedure type, as hex strings. |
cid | string | Reference to the procedure metadata. |
deciders | string | Deciders organ or address. |
forwarder | string | Trusted forwarder relaying gasless transactions. |
moderatorMode | ERC20VoteRoleMode | Whether moderators are organ members, token holders, or nobody. |
moderators | string | Moderators organ or address. |
options | TransactionOptions | Transaction options. |
proposerMode | ERC20VoteRoleMode | Whether proposers are organ members, token holders, or nobody. |
proposers | string | Proposers organ or address. |
requireMemberMajority | boolean | Whether a majority of the deciders organ must also approve, besides the token-weighted vote. |
typeName | ProcedureTypeName | Procedure type. |
voterMode | ERC20VoteRoleMode | Whether voters are organ members or token holders. |
withModeration | boolean | Whether moderation is enabled. |
Who holds a role in an ERC-20 vote: the members of an organ, the token holders, or nobody.
export type ERC20VoteRoleMode = 'organ' | 'token' | 'disabled';
Encoded call data.
export type PopulatedTransactionData = { data: string;};
Name of a procedure type.
export type ProcedureTypeName = 'erc20Vote' | 'nomination' | 'vote';
Return the SDK class of a procedure type.
getProcedureClass: (typeName: string) => Promise<typeof import("./erc20Vote").ERC20VoteProcedure | typeof import("./vote").VoteProcedure | typeof import("./nomination").NominationProcedure>
Return the procedure types registered on a chain.
getProcedureTypes: (chainId?: string) => Partial<Record<ProcedureTypeName, ProcedureType>>
Assets are ERC-20 tokens held by organs: plain assets, or company equity whose transfers a procedure approves.
An ERC-20 token held by organs: a plain asset or company equity.
constructor(input: AssetInput);
| Property | Type | Description |
|---|---|---|
address | string | Contract address, or a predicted address while it is a draft. |
chainId | string | Chain the asset lives on. |
decisionProcedure | string | null | Procedure that approves transfers of this equity token. |
description | string | Free description. |
image | string | null | Logo URL. |
initialSupply | number | Supply minted at deployment, in whole tokens. |
isDeployed | boolean | Whether the contract exists on chain. |
kind | 'asset' | 'equity' | asset for a plain token, equity for company shares whose transfers a procedure approves. |
name | string | Token name. |
organigramId | string | null | Organigram the asset belongs to. |
salt | string | null | Salt that determines the clone address. |
symbol | string | Token symbol. |
userBalance | string | Balance of the connected wallet, in the smallest unit. |
Hydrate an asset from chain state.
static load: (address: string, clients: ContractClients, initialAsset?: AssetInput) => Promise<(Asset & { userBalance: string; }) | undefined>;
Convert the asset into a JSON-safe structure.
toJson(): AssetJson;
The data of an asset, deployed or still a draft.
| Property | Type | Description |
|---|---|---|
address | string | null | Contract address, or a predicted address while it is a draft. |
chainId | string | null | Chain the asset lives on. |
decisionProcedure | string | null | Procedure authorized to settle this equity token's transfers. |
description | string | null | Free description. |
image | string | null | Logo URL. |
initialSupply | number | null | Supply minted at deployment, in whole tokens. |
isDeployed | boolean | Whether the contract exists on chain. |
kind | 'asset' | 'equity' | null | asset for a plain token, equity for company shares whose transfers a procedure approves. |
name | string | null | Token name. |
organigramId | string | null | Organigram the asset belongs to. |
salt | string | null | Salt that determines the clone address. |
symbol | string | null | Token symbol. |
userBalance | string | null | Balance of the connected wallet, in the smallest unit. |
An asset as plain JSON, to store or send it.
| Property | Type | Description |
|---|---|---|
address | string | Contract address, or a predicted address while it is a draft. |
chainId | string | Chain the asset lives on. |
decisionProcedure | string | null | Procedure authorized to settle this equity token's transfers. |
image | string | null | Logo URL. |
initialSupply | number | Supply minted at deployment, in whole tokens. |
isDeployed | boolean | Whether the contract exists on chain. |
kind | 'asset' | 'equity' | asset for a plain token, equity for company shares whose transfers a procedure approves. |
name | string | Token name. |
organigramId | string | null | Organigram the asset belongs to. |
salt | string | null | Salt that determines the clone address. |
symbol | string | Token symbol. |
userBalance | string | Balance of the connected wallet, in the smallest unit. |
Default supply minted for a new asset, in whole tokens.
const ERC20_INITIAL_SUPPLY = 10000000
Contracts only store references. Metadata and documents live off-chain, and are referenced by CID references of the form og://workspace/<workspace>/<key>. Each version of a file is described by a manifest. Encrypted files use three levels of keys: a content key encrypts one file, a group key shared by the members of an access group wraps content keys, and the key pair of each member unwraps group keys. These functions run on the Web Crypto API of the user's device: keep private keys there, never send them to a server or log them.
The group whose members can decrypt a file.
| Property | Type | Description |
|---|---|---|
epoch | number | Group key generation, increased when membership changes. |
scopeId | string | Identifier of that workspace, organization, organ or procedure. |
scopeType | AccessGroupScopeType | What the group is scoped to. |
Describes one version of an encrypted file: where its ciphertext is and how to get its key.
| Property | Type | Description |
|---|---|---|
accessGroup | EncryptedCidAccessGroup | Group whose key unwraps the content key. |
contentType | ScopeEnvelopeContentType | What the file holds. |
createdAt | string | ISO creation date. |
encryptedContent | { cid: string; algorithm: typeof ENCRYPTION_ALGORITHM; iv: string; size: number; mime?: string; name?: string; } | CID, algorithm, initialization vector, size, type and name of the ciphertext. |
kind | typeof ENCRYPTED_CID_KIND | typeof FILE_VERSION_MANIFEST_KIND | Manifest format. |
logicalKey | string | Stable name of the file. |
previousManifestCid | string | CID of the manifest of the previous version. |
retentionState | ScopeEnvelopeRetentionState | Lifecycle state of this version. |
scopeEnvelope | ScopeEnvelopeCheckpoint | Workspace checkpoint this version belongs to. |
scopeRef | ScopeEnvelopeReference | Workspace the file belongs to. |
signature | string | Signature of the author over the manifest. |
signedByAddress | string | Address of the author. |
version | 1 | Manifest format version. |
wrappedContentKey | WrappedContentKey | Content key, encrypted with the group key. |
An encryption public key read from a Sign-In with Ethereum message.
| Property | Type | Description |
|---|---|---|
address | string | Address that signed in. |
keyVersion | number | Version of the key pair. |
kind | typeof ENCRYPTION_PUBLIC_KEY_SIWE_RESOURCE_KIND | Resource format. |
publicKey | JsonWebKey | Public key, as a JSON Web Key. |
A CID reference split into its parts by parseCidRef().
| Property | Type | Description |
|---|---|---|
logicalKey | string | Stable name of the file within its workspace, whatever its version. |
manifestCid | string | Pins the reference to one immutable file-version manifest when present. |
scopeRef | ScopeEnvelopeReference | Workspace the file belongs to. |
Describes one version of a file stored in clear on IPFS.
| Property | Type | Description |
|---|---|---|
accessGroup | EncryptedCidAccessGroup | Group the file is shared with, if any. |
contentType | ScopeEnvelopeContentType | What the file holds. |
createdAt | string | ISO creation date. |
kind | typeof FILE_VERSION_MANIFEST_KIND | Manifest format. |
logicalKey | string | Stable name of the file. |
previousManifestCid | string | CID of the manifest of the previous version. |
publicContent | { cid: string; size: number; mime?: string; name?: string; } | CID, size, type and name of the content. |
retentionState | ScopeEnvelopeRetentionState | Lifecycle state of this version. |
scopeEnvelope | ScopeEnvelopeCheckpoint | Workspace checkpoint this version belongs to. |
scopeRef | ScopeEnvelopeReference | Workspace the file belongs to. |
signature | string | Signature of the author over the manifest. |
signedByAddress | string | Address of the author. |
version | 1 | Manifest format version. |
The public encryption key of a member, used to wrap a group key for them.
| Property | Type | Description |
|---|---|---|
address | string | Ethereum address of the member. |
keyVersion | number | Version of the key pair. |
publicKey | JsonWebKey | Public key, as a JSON Web Key. |
A signed summary of every file of a workspace at one point in time.
| Property | Type | Description |
|---|---|---|
epoch | number | Access group generation at that time. |
membershipHash | string | Hash of the members who had access. |
rootHash | string | Hash of every file entry, from computeScopeEnvelopeRoot(). |
The current version of one file in a workspace checkpoint.
| Property | Type | Description |
|---|---|---|
contentType | ScopeEnvelopeContentType | What the file holds. |
currentManifestCid | string | CID of the manifest of its current version. |
logicalKey | string | Stable name of the file. |
previousManifestCid | string | CID of the manifest of the previous version. |
retentionState | ScopeEnvelopeRetentionState | Lifecycle state of this version. |
updatedAt | string | ISO date of the last change. |
version | number | Version number, starting at 1. |
The workspace a CID reference belongs to.
| Property | Type | Description |
|---|---|---|
scopeId | string | Workspace identifier. |
scopeType | ScopeEnvelopeScopeType | Kind of scope, always workspace. |
The encryption key pair of the current user, as kept on their device.
| Property | Type | Description |
|---|---|---|
keyPair | CryptoKeyPair | Web Crypto key pair. |
keyVersion | number | Version of the key pair. |
publicKey | JsonWebKey | Public key, as a JSON Web Key. |
A content key encrypted with a group key.
| Property | Type | Description |
|---|---|---|
algorithm | typeof ENCRYPTION_ALGORITHM | Wrapping algorithm. |
ciphertext | string | Encrypted content key, in base64. |
iv | string | Initialization vector, in base64. |
A group key encrypted for one member, which only their private key can unwrap.
| Property | Type | Description |
|---|---|---|
algorithm | typeof GROUP_KEY_ALGORITHM | Wrapping algorithm. |
ciphertext | string | Encrypted group key, in base64. |
ephemeralPublicKey | JsonWebKey | One-time public key used for the key agreement. |
iv | string | Initialization vector, in base64. |
recipientAddress | string | Ethereum address of the member. |
recipientKeyVersion | number | Version of the member key pair used. |
What an access group is scoped to: its members share one group key.
export type AccessGroupScopeType = 'workspace' | 'organization' | 'organ' | 'procedure' | 'certifiedProof';
What a stored file holds, such as an organ entry or a proposal.
export type EncryptedCidContentType = 'entry' | 'proposal' | 'organMetadata' | 'procedureMetadata' | 'certifiedProof' | 'file' | string;
One version of a stored file, public or encrypted.
export type FileVersionManifest = PublicFileVersionManifest | EncryptedCidManifest;
What the file behind a CID reference holds.
export type ScopeEnvelopeContentType = EncryptedCidContentType;
Lifecycle of a file version: current, replaced by a newer one, revoked or archived.
export type ScopeEnvelopeRetentionState = 'current' | 'superseded' | 'revoked' | 'archived';
Scope of a CID reference. Only workspaces are supported.
export type ScopeEnvelopeScopeType = 'workspace';
Copy bytes into a standalone ArrayBuffer.
bytesToArrayBuffer: (value: ArrayBuffer | Uint8Array) => ArrayBuffer
Decode UTF-8 bytes into a string.
bytesToText: (value: ArrayBuffer | Uint8Array) => string
Hash every file entry of a workspace into the root hash of a checkpoint.
computeScopeEnvelopeRoot: (items: Record<string, ScopeEnvelopeItem>) => Promise<string>
Create a key version from a date, as a Unix timestamp in seconds.
createEncryptionKeyVersion: (timestamp?: number) => number
Build the message a user signs to register an encryption public key.
createEncryptionPublicKeyMessage: (address: string, publicKey: JsonWebKey, keyVersion: number) => string
Encode an encryption public key as a Sign-In with Ethereum resource.
createEncryptionPublicKeySiweResource: (address: string, publicKey: JsonWebKey, keyVersion: number) => string
Describe a new version of an encrypted file.
createFileVersionManifest: (input: { contentType: ScopeEnvelopeContentType; scopeRef: ScopeEnvelopeReference; logicalKey: string; encryptedCid: string; encryptedContentIv: string; encryptedContentSize: number; wrappedContentKey: WrappedContentKey; previousManifestCid?: string | null; retentionState?: ScopeEnvelopeRetentionState; scopeEnvelope?: ScopeEnvelopeCheckpoint; mime?: string; name?: string; signature?: string | null; signedByAddress?: string | null; createdAt?: Date | string;}) => FileVersionManifest
Describe a new version of a file stored in clear.
createPublicFileVersionManifest: (input: { contentType: ScopeEnvelopeContentType; scopeRef: ScopeEnvelopeReference; logicalKey: string; publicCid: string; publicContentSize: number; previousManifestCid?: string | null; retentionState?: ScopeEnvelopeRetentionState; scopeEnvelope?: ScopeEnvelopeCheckpoint; mime?: string; name?: string; signature?: string | null; signedByAddress?: string | null; createdAt?: Date | string;}) => PublicFileVersionManifest
Create a workspace checkpoint.
createScopeEnvelopeCheckpoint: (input: { epoch: number; membershipHash: string; rootHash: string;}) => ScopeEnvelopeCheckpoint
Describe the current version of one file for a workspace checkpoint.
createScopeEnvelopeItem: (input: { logicalKey: string; currentManifestCid: string; contentType: ScopeEnvelopeContentType; version?: number; retentionState?: ScopeEnvelopeRetentionState; previousManifestCid?: string; updatedAt?: Date | string;}) => ScopeEnvelopeItem
Build the message a member signs to vouch for a workspace checkpoint.
createScopeEnvelopeSignatureMessage: (input: { scopeRef: ScopeEnvelopeReference; checkpoint: ScopeEnvelopeCheckpoint; items: Record<string, ScopeEnvelopeItem>; previousEnvelopeCid?: string | null;}) => string
Decrypt bytes encrypted by encryptBytes().
decryptBytes: (encryptedBytes: ArrayBuffer | Uint8Array, key: CryptoKey, iv: string) => Promise<Uint8Array>
Encrypt bytes with AES-GCM, and return the ciphertext with its initialization vector.
encryptBytes: (bytes: ArrayBuffer | Uint8Array, key: CryptoKey) => Promise<{ encryptedBytes: Uint8Array; iv: string;}>
Export the private half of a user key pair as a JSON Web Key.
Only store the result encrypted, for example in a passkey vault.
exportUserPrivateKey: (keyPair: CryptoKeyPair) => Promise<JsonWebKey>
Export the public half of a user key pair as a JSON Web Key, to publish it.
exportUserPublicKey: (keyPair: CryptoKeyPair) => Promise<JsonWebKey>
Build a CID reference, og://workspace/<workspace>/<key>, optionally pinned to one version.
formatCidRef({ scopeType: 'workspace', scopeId: workspaceId }, 'bylaws')
formatCidRef: (scopeRef: ScopeEnvelopeReference, logicalKey: string, manifestCid?: string) => string
Generate the AES key that encrypts one file.
generateContentKey: () => Promise<CryptoKey>
Generate the AES key shared by the members of an access group.
generateGroupKey: () => Promise<CryptoKey>
Generate the ECDH P-256 key pair a user decrypts their group keys with.
Keep the private key on the user's device: never send it to a server or log it.
generateUserEncryptionKeyPair: () => Promise<CryptoKeyPair>
Return the Web Crypto API, and throw where it is unavailable.
getCrypto: () => Crypto
Generate a random 12-byte initialization vector for AES-GCM.
getRandomIv: () => Uint8Array
Import a user public key from a JSON Web Key, keeping it exportable.
importExtractableUserPublicKey: (publicKey: JsonWebKey) => Promise<CryptoKey>
Import a user private key from a JSON Web Key.
importUserPrivateKey: (privateKey: JsonWebKey) => Promise<CryptoKey>
Tell whether a string is a CID reference.
isCidRef: (value?: string | null) => boolean
Tell whether a value is the manifest of an encrypted file.
isEncryptedCidManifest: (value: unknown) => value is EncryptedCidManifest
Tell whether a value is a file-version manifest, public or encrypted.
isFileVersionManifest: (value: unknown) => value is FileVersionManifest
Tell whether a key version is already a valid Unix timestamp in seconds.
isValidEncryptionKeyVersion: (keyVersion: number) => boolean
Turn a key version into Unix seconds, accepting milliseconds, or return null if it is invalid.
normalizeEncryptionKeyVersion: (keyVersion: number) => number | null
Split a CID reference into its parts, or return null if it is not one.
parseCidRef: (value?: string | null) => ParsedCidRef | null
Find the encryption public key of an address among Sign-In with Ethereum resources.
parseEncryptionPublicKeySiweResource: (resources: string[] | undefined, address: string) => EncryptionPublicKeySiweResource | null
Decrypt a content key with a group key.
unwrapContentKey: (wrappedContentKey: WrappedContentKey, groupKey: CryptoKey) => Promise<CryptoKey>
Decrypt a group key with the private key of its recipient.
unwrapGroupKey: (wrappedGroupKey: WrappedGroupKey, recipientPrivateKey: CryptoKey) => Promise<CryptoKey>
Encrypt a content key with a group key.
wrapContentKey: (contentKey: CryptoKey, groupKey: CryptoKey) => Promise<WrappedContentKey>
Encrypt a group key for one member, with their public key.
wrapGroupKeyForRecipient: (groupKey: CryptoKey, recipient: RecipientEncryptionKey) => Promise<WrappedGroupKey>
kind of manifests written before file versioning, still read for compatibility.
const ENCRYPTED_CID_KIND: "organigram.encrypted-cid.v1"
Symmetric algorithm used for content and content keys: AES-256-GCM.
const ENCRYPTION_ALGORITHM: "A256GCM"
kind of the encryption public key a user publishes in a Sign-In with Ethereum message.
const ENCRYPTION_PUBLIC_KEY_SIWE_RESOURCE_KIND: "organigram.encryption-public-key.v1"
kind of a file-version manifest, public or encrypted.
const FILE_VERSION_MANIFEST_KIND: "organigram.file-version-manifest.v1"
Algorithm used to wrap a group key for one member: ECDH on P-256, then AES-256-GCM.
const GROUP_KEY_ALGORITHM: "ECDH-P256+A256GCM"
The protocol contracts are deployed once per chain. These functions tell which chains are supported, where the contracts are, and at which address a new clone will be deployed.
Return the block explorer URL of a chain.
getChainExplorerBaseUrl: (chainId: string) => string | undefined
Return the viem chain definition of a chain id.
getConfiguredChain: (chainId: string) => Chain | undefined
Default network: Anvil when local deployments are loaded, Ethereum mainnet otherwise. Pass a chain id explicitly to use any other network.
getDefaultChainId: () => string
Returns
| Type | Description |
|---|---|
string | The default chain id. |
Return the address of a protocol contract on a chain, and throw if it is not deployed there.
getDeployment: (chainId: string | number | bigint | null | undefined, deploymentName: ProtocolDeploymentName) => string
URL of the Organigram app: NEXT_PUBLIC_HOST_URL, or the current page origin in a browser.
getHostUrl: (hostUrl?: string | undefined) => URL | null
List the chains the protocol is deployed on.
getSupportedChainIds: () => string[]
Tell whether the app runs on a local host name.
isLocalHost: (hostUrl?: string) => boolean
Tell whether the protocol is deployed on a chain.
isSupportedChainId: (chainId: string | number | bigint | null | undefined) => boolean
Addresses of the protocol contracts on each supported chain, by chain id.
const deployedAddresses: ProtocolDeployments
Name of a protocol contract.
export type ContractName = 'Organ' | 'Asset' | 'EquityToken' | 'ERC20VoteProcedure' | 'VoteProcedure' | 'NominationProcedure' | 'OrganigramClient';
Predict the address of a clone deployed by the OrganigramClient.
The client binds each salt to the account deploying the clone, so only an address predicted with deployer is the address the clone will have. Without it, the result is merely a unique placeholder for a draft.
predictContractAddress: (input: { type: Omit<ContractName, "OrganigramClient">; chainId: string; salt: string; deployer?: string;}) => string
Small helpers used across the library and the Organigram app.
Uppercase the first letter of a string.
capitalize: (s: string) => string
Generate a random 32-byte hex string, for example a salt.
createRandom32BytesHexId: () => `0x${string}`
A JSON.stringify replacer that writes bigints as strings ending in n.
handleJsonBigInt: (_key: string, value: unknown) => unknown
Parse a number, or return the fallback if the result is not finite.
parseFiniteNumber: (value: number | string | null | undefined, fallback: number) => number
Edit this page
On this page:
© 2026 Organigram SAS
All Rights Reserved.