SDK documentation

Getting started

The SDK can be used read and write cap table data. To use the SDK you need to connect with

Test URL
More info
Links
https://ceramic-clay.3boxlabs.com

Ceramic is used to save changeable and personal (not sensetive) information. agdgdg

https://goerli-rollup.arbitrum.io/rpc

Ethereum is used to hold information about all captables status and balances.

brokDev
https://api.thegraph.com/subgraphs/name/broklab/captable_dev_11
brokStage
https://api.thegraph.com/subgraphs/name/broklab/captable_stage_10

The Graph is used to index blockchain data to make it easy and efficient to query. It continously indexes the blockchain so expect real time data.

test test test test test test test test test test test junk
did:key:z6MkjCcGLsuHuaRDw7tESJKTyAZW7dWde33JxdpgLJjX2PFR

Your wallet is used as an identifier.

DONT USE Private keys and mnemonics with funds

This way of initalizing identifier with private key or mnemonic will change. Probably we will accept some signer function. This is not suited for browser enviroments.

You must also pick a BRØK enviroment.

  • brokLocal - Local ceramic, local graph, local blockchain
  • brokDev - Ceramic: Clay testnetwork, Graph: Hosted services on Arbitrum Goerli, Ethereum: Arbitrum Goerli
  • brokStage - Ceramic: Clay testnetwork, Graph: Hosted services on Arbitrum Goerli, Ethereum: Arbitrum Goerli
  • brokProd - Ceramic: Mainnetwork, Graph: Hosted services on Arbitrum Nitro, Ethereum: Arbitrum Nitro
const sdk = await SDK.init({
ceramicUrl: 'https://ceramic-clay.3boxlabs.com',
ethereumRpc: 'https://goerli-rollup.arbitrum.io/rpc',
secret: 'test test test test test test test test test test test junk',
theGraphUrl:
'https://api.thegraph.com/subgraphs/name/broklab/captable_dev_11',
env: 'brokDev',
});

This returns an SDK class instance with the following methods.

createCapTable(input: CreateCapTableInput): Promise<string>;
getCapTable(capTableAddress: EthereumAddress): Promise<CapTable>;
getCapTableList(skip?: number, limit?: number): Promise<CapTableGraphQL[]>;
transfer(capTableAddress: CapTableEthereumId, transfers: TransferInput[]): Promise<(OperationResult & TransferRequest)[]>;
deleteCapTable(capTableAddress: CapTableEthereumId): Promise<boolean>;
updateShareholder(capTableAddress: CapTableEthereumId, shareholder: Partial<Shareholder>): Promise<Shareholder>;
kapitalforhoyselseNyeAksjer(capTableAddress: CapTableEthereumId, transfers: IssueInput[]): Promise<(OperationResult & IssueRequest)[]>;
splitt(capTableAddress: CapTableEthereumId, issues: IssueRequest[]): Promise<(OperationResult & IssueRequest)[]>;
kapitalnedsettelseReduksjonAksjer(capTableAddress: CapTableEthereumId, redeems: RedeemRequest[]): Promise<(OperationResult & RedeemRequest)[]>;
spleis(capTableAddress: CapTableEthereumId, redeems: RedeemRequest[]): Promise<(OperationResult & RedeemRequest)[]>;
issueEcumbrance(shareholderCeramicID: CeramicID, encumbrance: Encumbrance): Promise<Shareholder>;
editEcumbrance(shareholderCeramicID: CeramicID, encumbrance: Partial<Encumbrance>): Promise<Shareholder>
deleteEcumbrance(shareholderCeramicID: CeramicID): Promise<Shareholder>

For more information about each type, see here

Access as fagsystem

If you want access as a Fagsystem, we need to get your test public address and DID id. Contact us.

You can test queries here:

Publish cap table

You must publish with current shareholder structure.

You must be a fagsystem to do this.

You can publish organisations or persons, type information is provided.

const indentifier = await sdk.createCapTable({
name: "Hoved orginisasjonen AS",
orgnr: "123 123 123",
shareholders : [
{ // Org
name: 'Fiske AS',
organizationIdentifier: '123456789',
organizationIdentifierType: 'EUID',
amount: '500',
countryCode: 'NO',
postalcode: '05555',
partition: 'ordinære',
},
{ // Person
name: 'Fiske AS',
birthDate: '22-01-1977',
amount: '500',
countryCode: 'NO',
postalcode: '05555',
partition: 'ordinære',
},
],
});
// for example indentifier = "0x59525c939ce8068ec2a18b0cd6b5151a850a4ff1"

Be sure to catch any errors thrown. In success it will give you back and indentifier which is the Ethereum address for the smart contract.

Get cap table

When you have an address for a cap table you want to read.

const capTable = await sdk.getCapTable("0x2c8ba63f2e2f42f7c897d8ebeebb5d04acc0725b");

This returns a cap table object

CapTable {
ethAddress: '0x2c8ba63f2e2f42f7c897d8ebeebb5d04acc0725b',
name: 'GRUNN MUSIKALSK TIGER AS',
orgnr: '310790834',
ceramicID: 'k2t6wyfsu4pfyq3yhkhlcpk0fyxkret5wc5wlml3yph6kgmk0zrp6bxzl17isg',
totalShares: '80000.0',
shareholders: [
{
balances: [Array],
ethAddress: '0x1d8639b7a2fccf2983cb52155d93049656646212',
name: 'Ola Nordmann',
countryCode: 'NO',
postalcode: '8313',
birthDate: '1942-04-21',
ceramicID: 'kjzl6cwe1jw145i19n2nw2rs2lzhg8bmsia3jd21ypjnm4si7uqn7l52m03nn0y'
},
...
]
}

Get list of cap tables

When you want to get list of cap tables

const list = await sdk.getCapTableList();
// You can provide skip and limit to traverse. i.e. Skip 10, then get 30 cap tables
// const list = await sdk.getCapTableList(10, 30);

This query returns

Not normalized data

This data is directly from TheGraph. Later we will normalize this so that getCapTable() and getCapTableList() returns exactly the same information, where all amounts and data are normalized.

Name is persisted on blockchain and Ceramic. This will probably change.

// returns
[
CapTableGraphQL {
id: '0x2c8ba63f2e2f42f7c897d8ebeebb5d04acc0725b',
name: 'GRUNN MUSIKALSK TIGER AS',
orgnr: '310790834',
fagsystem: '0xb977651ac2f276c3a057003f9a6a245ef04c7147',
symbol: '310790834',
status: 'APPROVED',
partitions: [ 'ordinære' ],
owner: '0xb977651ac2f276c3a057003f9a6a245ef04c7147',
minter: '0xb977651ac2f276c3a057003f9a6a245ef04c7147',
controllers: [ '0xb977651ac2f276c3a057003f9a6a245ef04c7147' ],
totalSupply: '80000000000000000000000',
fagsystemDid: 'did:key:z6Mktx33qNK6heU2hoGHBJNRhWCem7NTFp7QERt7wk3aXWim',
tokenHolders: [
{
id: '0x2c8ba63f2e2f42f7c897d8ebeebb5d04acc0725b-0x1d8639b7a2fccf2983cb52155d93049656646212',
address: '0x1d8639b7a2fccf2983cb52155d93049656646212',
balances: [Array]
},
{
id: '0x2c8ba63f2e2f42f7c897d8ebeebb5d04acc0725b-0x2c3d0351022f4939468bb3fb6edac16393430d38',
address: '0x2c3d0351022f4939468bb3fb6edac16393430d38',
balances: [Array]
},
...
]
},
...
]

Transfer

When fagsystem wants to transfer. You must be a fagsystem identifier to do this.

// two transfers
const transferResult = await sdk.transfer(identifier, [
{ // exisiting shareholder
from: shareholderA.ethAddress,
to: shareholderB.ethAddress,
amount: '100',
partition: 'ordinære',
},
{ // New shareholder
from: shareholderB.ethAddress,
amount: '300',
partition: 'ordinære',
name: "Kari O'Connor",
birthDate: '01-01-1988',
countryCode: 'NO',
postalcode: '0655',
},
]);

This query returns

// returns
transferResult [
{
to: '0x97a74543a2ef334d582004b623932d1440d5c583',
amount: '1',
from: '0x1d8639b7a2fccf2983cb52155d93049656646212',
partition: 'ordinære',
success: true,
message: 'Deployed to blockchain.'
},
{
to: '0xcd92d12da6771d7eb72bf699d2694b2fde3ad52d',
amount: '1',
from: '0x1d8639b7a2fccf2983cb52155d93049656646212',
partition: 'ordinære',
success: true,
message: 'Deployed to blockchain.'
}
]

Update shareholder

When fagsystem wants to update shareholder information. You must be a fagsystem identifier to do this.

const updatedShareholder = await sdk.updateShareholder(identifier, {
name: 'Kari Nordmann',
ethAddress: shareholderToUpdate.ethAddress,
});

This query returns

// returns
updatedShareholder {
name: 'Kari Nordmann',
amount: '7000',
birthDate: '1942-04-21',
partition: 'ordinære',
ethAddress: '0x1d8639b7a2fccf2983cb52155d93049656646212',
postalcode: '8313',
countryCode: 'NO',
ceramicID: 'kjzl6cwe1jw145i19n2nw2rs2lzhg8bmsia3jd21ypjnm4si7uqn7l52m03nn0y',
balances: [ { amount: '2582000000000000000000', partition: 'ordinære' } ]
}

Debug

Set env variable debug to brok* (ie. debug=brok* node index.js)

Smart contracts

Artifacts, interfaces and deployments can be gotten from @brok/captable

You can see addresses for each enviroment here