# Brønnøysund Captable developer documentation (beta) # Introduction There are some 321 000 limited liability companies in Norway - less than 1000 have their shareholding listed in a securities register. While every company is obliged to keep an updated cap table, the vast majority of companies report shareholding only for tax purposes once a year. Many people believe in a local business or a start-up, but few have the energy and insights to invest. What energy might be released if more people were able to take part in financing ideas they believe in. By providing infrastructure, we hope to establish a platform that makes ownership transparent and lower the risks of engaging with small and mediums sized enterprises. Doing so is part of a broad effort to make capital more efficient, for example, by making shares liquid, allowing their use as collateral and link loans, mortgages, and payments direct to shares and share transactions. In the process, it is quite possible to imagine a greatly simplified public reporting where regulators may themselves access the required data - and a greatly simplified corporate governance involving share loyalty programs, the payment of dividends and voting. In short, the platform may serve to open and democratizing the unlisted markets for new groups of investors. Norwegian limited liability companies must have a share capital of at least NOK 30,000 assigned to one or more shares, each of identical nominal value. The total share capital, the number of shares, and their nominal value is stated in the company's articles of association. All limited liability companies shall have a register of shareholders unless the company's shares are registered in a securities register. The cap table shall contain an overview of the company's shareholders, and it will typically determine who may exercise shareholder rights, including the right to vote at the general meeting and the right to receive dividends. The cap table is, in principle, public - insight should not be denied. --- ## What is a cap table? Upon listing a shareholder in the shareholders' register, the company shall notify the shareholder thereof. The shareholders' register shall be updated in accordance with established rules in the Companies Act (§ 4-7) to reflect changes of ownership or pledging of shares. Shares can be sold or given away without payment unless otherwise stated by law, articles of association or agreement between the shareholders. In the case of a sale, the price is usually calculated based on market value. Transfers of ownership below market value are referred to as "gift sale" and may trigger a tax liability. When shareholders sell or otherwise realize shares, gains will be taxable and losses deductible. The Companies Act contains rules on the consent of acquiring shares, and rules on pre-emption rights for the other shareholders. An agreement to transfer shares shall be reported to the board of the limited company by the person acquiring the shares. The agreement should, as a minimum, list all the parties, the number of shares to be transferred, and at what price. Transfers in BrregCapTable will be reported automatically. The new shareholder must be notified by the company that she has been included in the shareholders' register and what is listed. :::success Companies and shareholders that rely on BrregCapTable may need not keep a separate cap table nor report its details to the government as everything is automated. ::: ### Shareholder agreements Shareholder agreements are normally entered into between shareholders of a company and regulate the relationship between them. Shareholders are not obliged to enter into such an agreement, but it may be useful. A shareholder agreement obliges only the shareholders who have signed the agreement. There are no requirements as to how the agreement should look or what it should contain. Examples of conditions that can be regulated in a shareholder agreement are rules relating to ownership, demands for dividends, non-compete clauses, impartiality, and work/employment requirements. ### Conflict between shareholders It is not uncommon for conflicts between shareholders to arise regarding the organization and running of a company. Since the causes of conflict may be difficult to spot in advance, it may make sense to * Avoid a setup where two owners hold 50% of the shares each and hence become incapable of making majority decisions in cases of conflict * Enter into shareholder agreements that clarify how the relationship between shareholders in the event of disagreement. In cases where the shareholders no longer manage to cooperate with each other, the district court may, in response to a lawsuit from a shareholder or from the company, decide on the redemption or release of a shareholder's shares. Such lawsuits must be regarded as last resort, and there must be weighty reasons. # Smart contracts ## Captable contract Captable is a smart contract protocol following the ERC1400 standard. The implementation heavily utilizes and are interoperatble[Consensys 1400 implementation](https://github.com/ConsenSys/ERC1400). ### Create Captable ![](https://i.imgur.com/zaWQ4Px.png) ### Captable extensions There are mainly four ways to extend or hook into the Captable protocol. * **Pre Transfer Hooks** * *IERC1400TokensSender* * This is called when transferring tokens. It will be called based on who is the sender of the tokens. It means that the owner of a token within an ERC1400 protocol can instruct the protocol to call a smart contract when transferring tokens. This called smart contract (under senders control) has the power (on behalf of its token ownership) to use information in the transactions and decide if it should continue. * ![IERC1400TokensSender](https://i.imgur.com/3eVWfTV.png) * Interface: https://gitlab.com/brreg1/captable/-/blob/cd170126634892f8b2edd5fdd2a0c30e280619b2/contracts/token/ERC1400Raw/IERC1400TokensSender.sol * *IERC1400TokensValidator* * Works much the same as TokensSender. The big difference is that it's not sender specific. It's Captable specific. This means, on each transfer, it will call a smart contract defined by the Captable itself. * Brreg will use this for Authentication (Beta). So on each transfer, it will call a smart contract defined by this interface, which in turn check if the receiving address has been attested by an auth oracle. * Interface: https://gitlab.com/brreg1/captable/-/blob/master/contracts/token/ERC1400Raw/IERC1400TokensValidator.sol * Example implementation: https://gitlab.com/brreg1/captable/-/blob/b545e8aa5056e458ea64b892fe8544e40e20728d/contracts/tokenExtension/ERC1400BrregValidator.sol * ![IERC1400TokensValidator](https://i.imgur.com/qY6hBTj.png) * **Post Transfer Hooks** * *IERC1400TokensRecipient* * This is called when transferring tokens. If the receiver of the tokens is a smart contract which implements IERC1400TokensRecipient interface. The tokensReceived function on this interface will be called from Captable. * ![](https://i.imgur.com/fboX47S.png) * Interface: https://gitlab.com/brreg1/captable/-/blob/cd170126634892f8b2edd5fdd2a0c30e280619b2/contracts/token/ERC1400Raw/IERC1400TokensRecipient.sol * Example: https://gitlab.com/brreg1/captable/-/blob/cd170126634892f8b2edd5fdd2a0c30e280619b2/contracts/PropertyCDP.sol #### CDP Property Trade ![](https://i.imgur.com/xLYMuYw.png) In this example, a property owner collateralizes his property. This token of ownership but dependent on collateralization can then be utilized in a system for exchange. This example heavily utilizes hooks so that independent entities can exchange tokens. ![](https://i.imgur.com/jYSiOt5.jpg) ## Que Que works as a filter for the registry. This is where Brreg receives issues for new registrations. Then verifies and process them into the registry. The Captable template automatically inserts the captable into que. https://gitlab.com/brreg1/captable/-/blob/master/contracts/CapTableQue.sol ## Registry Registry is where approved Captables go. This is the public registery that all services should use and follow. https://gitlab.com/brreg1/captable/-/blob/master/contracts/CapTableRegistry.sol ## Multisig For shared ownership. Will be extended upon in the future. https://gitlab.com/brreg1/captable/-/blob/master/contracts/MultiSigWallet.sol ## Deployment addresses AUTH_ORACLE='0x4A6Ecc8631990741263b38EEB434405C04CDc723' ERC1820='0x7C2F9F4A231F37BA7321D56B19909c8FE5dFd144' QUE='0xD6fD724617D63bc7d8347770f1495706aff622b0' REGISTRY='0x894f201a7b7E5B42e0840C9797fd42C6 PROPERTY_PLATTFORM='0xEC0712a5c12cFEE4F39b1D7E0903bf6098b8c54D' PROPERTY_REGISTRY='0xf9Bcfd9F56F4D9061dF42FB011DC04958eAcD32d' TRADE_REGISTRY='0xBd9F1aaa4aCB569996352376262b7Dec770B1683' MORTGAGE_REGISTRY='0xA4f5f570700DE2Bee9b773422CD04A9439AA20Df' ## Deploy everything yourself 1. AuthOracle-Contracts 1. `npm run deploy::brreg` 2. Kopier ned følgende addresser > REACT_APP_AUTH_ORACLE='0x123' 2. AuthOracle 1. Endre .env.production sin auth oracle addresse 5. Push changes, CI will deploy new version in Vercel https://vercel.com/robertosnap/auth-oracle 3. CapTable-Contracts 1. Change buidler.config.js object. Deploy property. Under networkId (brreg er 1733917133) add key => value with authOracle: '0x123', 8. ![](https://i.imgur.com/9QyIMQ1.png) 9. `npx buidler deploy --network brreg` 10. Copy down addresses > REACT_APP_ERC1820='0x123' > REACT_APP_QUE='0x123' > REACT_APP_REGISTRY='0x123' 4. Forvalt 1. Change .env.production with addresses copied from AuthOracle og CapTable deploy. Overwrite what is there. 2. Push changes, CI will deploy new version in Gitlab: https://gitlab.com/blockchangers/cloudless/aksjelisten/pages 5. Eierskifte-Contracts 6. In this repo, there is a test that deploys the system. But we need to update this test file with the new addresses: 7. test/__PropertyRegistry__.ts :88 copy in addresses under networkId for erc1820, Que, AuthOracle 8. `npx buidler test --network brreg` 9. Copy down > REACT_APP_PROPERTY_PLATTFORM='0x123' > REACT_APP_PROPERTY_REGISTRY='0x123' > REACT_APP_TRADE_REGISTRY='0x123' > REACT_APP_MORTGAGE_REGISTRY='0x123' 9. Eierskifte-web 10. Change .env.production with addresses copied from AuthOracle, CapTable, Eierskifte-contracts deploy. Overskriv de som allerede er der. 2. Push changes, CI will deploy new version in Gitlab: https://gitlab.com/blockchangers 9. Visma-Boardroom 10. Change .env.production with addresses copied from AuthOracle, CapTable deploy. Overskriv de som allready er der. 2. Push changes, CI will deploy new version in Gitlab: https://gitlab.com/blockchangers # Apps ![Backend frontend oversukt](https://i.imgur.com/mmxyuE6.png) ## Brønnøysund * [Auth Oracle (open source)](https://gitlab.com/blockchangers/cloudless/auth-oracle-contracts) - Smart contract proejct for AuthOracle. * [Auth Oracle App (closed source)](https://gitlab.com/blockchangers/cloudless/auth-oracle) - Next.js stack. Frontend and backend for un-permission and permission interaction with Auth Oracle. The closed API for business lookup also resides here within the backend application. * [Captable (open source)](https://gitlab.com/brreg1/captable) - Smart contract project for CapTable and CapTable extensions. * [Forvalt App (open source)](https://gitlab.com/blockchangers/cloudless/aksjelisten) - Brønnøysund frontend application to manage a registry of Captables. ## Visma * [Visma Boardroom App (open source)](https://gitlab.com/visma1/forvalt) - A frontend application for users to interact with multiple Captables. ## OBOS * [Property trade App (closed source)](https://gitlab.com/blockchangers/kunder/obos/eierskifte-web) - A frontend application for all participants in a property trade to transact with another. * [Property trade (closed source)](https://gitlab.com/blockchangers/kunder/obos/eierskifte-web) - Smart contract proejct for property Trade. ### Other If you have created an application and want it listed here, contact Jon at blockchangers.com # Integrate your app ## Integrate frontend ### Setup :::info Want to just get going? [Jump to Quikstart]() ::: As Brreg Captable is a service facilitated by blockchain technology, end-users will interact with your service in ways that differ from a regular client-server approach. Instead of credentials authenticating the user and giving the user the correct access, end users are expected to use a browser with blockchain wallet functionality. This functionality is available in * Google Chrome, Firefox, Brave and Microsoft Edge when installing the [Metamask plugin](https://metamask.io/) * The Opera web browser As a frontend developer, you must download this plugin and use it when developing frontend applications. #### Metamask In the top-right menu of MetaMask, you can select the network that you are currently connected to. Among several popular defaults, you'll find Custom RPC. Use it and set 1. Network Name to Brreg (it's not important what you call it, just for your own reference) 2. New RPC URL to https://u1ps4u882p:zGyIQRNUcAMSaxI79_LhovZLakJ8127sDGDABVhdgAE@u1txh1ent0-u1ieecy018-rpc.us1-azure.kaleido.io Since your seed phrase is the power to control all your accounts, it is probably worth keeping at least one seed phrase for development, separate from any that you use for storing real value. One easy way to manage multiple seed phrases with MetaMask is with multiple browser profiles, each of which can have its own clean extension installations. :::info Note that users of your application will have to connect Metamask to the Brreg network, too, while BrregCapTable remains in development as a beta. ::: ##### Metamask / web3 details There are settings you should keep in mind when interacting with Metamask: * What is the current network? * What is the current account? ```javascript= ethereum.networkVersion ethereum.selectedAddress `" > When you're ready to request the user log in, you can call this simple function. ```javascript= ethereum.enable(); `" > Since it returns a promise, if you're in an `async` function, you may log in like this. ```javascript= const accounts = await ethereum.enable() const account = accounts[0] // We currently only ever provide a single account, // but the array gives us some room to grow. `" :::info If the networkVersion is not **1733917133**, the user is not connected to the Brreg Network. Guide the user to correcting this. ::: #### User provider package Instead of handling all this Ethereum....web3...metamask things ourselves, let us add the package [web3Modal](https://github.com/Web3Modal/web3modal) which can handle it for us. ```javascript= npm install --save web3modal # OR yarn add web3modal `" Then add this to your js/ts app ```javascript= import Web3Modal from "web3modal"; const web3Modal = new Web3Modal({ network: "mainnet", // optional cacheProvider: true, // optional providerOptions: {} // required }); const provider = await web3Modal.connect(); `" Now you got a provider to interact with Brreg network. This provider will respond to request for Block numbers, transactions request, and so on. But we want to interact with smart contracts easily. To do this effortlessly, we include a library like [ethers.js](https://github.com/ethers-io/ethers.js/) or [web3.js](https://github.com/ethereum/web3.js/). #### Provider library We use something called Buidler.dev and Typechain to generate typescript definitions from smart contracts. This will then type check our input and response variables as well as list and suggest functions available in your smart contracts when developing. This requires an older version of Ethers, so let's install `" npm install --save ethers@4.0.47 # OR yarn add ethers@4.0.47 `" Then let's create a TS file so that we can effortlessly get an ethers web3 provider ```typescript= // utils/web3.ts import Web3Modal, { IProviderOptions } from "web3modal"; import { ethers } from "ethers"; import { JsonRpcSigner, Web3Provider } from "ethers/providers"; export const getWeb3 = async (): Promise<JsonRpcSigner> => { const web3ModalProvider = await getNativeProvider(); const web3provider = new ethers.providers.Web3Provider(web3ModalProvider as Web3Provider); return await web3provider.getSigner(); }; export const getNativeProvider = async () => { const providerOptions: IProviderOptions = {}; const web3Modal = new Web3Modal({ cacheProvider: true, providerOptions, return await web3Modal.connect(); }; export const TX_OVERRIDE = () => { return { gasPrice: ethers.utils.parseUnits("0.0", "gwei"), gasLimit: 7999999, }; }; `" #### Interact with smart contract Now that we got our provider setup, we need to give the provider an interface to the smart contract. You can get interfaces for Captable here: https://gitlab.com/brreg1/captable/-/releases download the tar.gz or zip and put files ./contracts ```typescript= // utils/contracts.ts import { getWeb3 } from "./web3"; import { CapTableFactory } from "../contracts/CapTableFactory"; import { CapTable } from "../contracts/CapTable"; export const getCapTable = async (capTableAddress: string) => { return CapTableFactory.connect(capTableAddress, await getWeb3()); }; export const useCapTable = ( capTableAddress: string ): [CapTable | undefined, boolean, string] => { const [contract, setContract] = useState<CapTable>(); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); useEffect(() => { getCapTable(capTableAddress) .catch((err) => handleError(err, setError)) .then((_contract) => { setLoading(false); setContract(_contract); }); }, [capTableAddress, error]); return [contract, loading, error]; }; const handleError = (error: any, handler: (err: string) => void) => { if (error) { if (error.hasOwnProperty("message")) { handler(error.message); } else { handler(error); } } else { handler("Udefined error"); } return undefined; }; `" ### Quickstart 1. Install ```javascript= npm install --save web3modal ethers@4.0.47 # OR yarn add web3modal ethers@4.0.47 ``` 2. Create folder utils 3. Create TS file contracts.ts inside utils. [contents](#Interact-with-smart-contract) 4. Create TS file web3.ts inside utils. [contents](#Provider-library) 5. Create folder contracts 6. Downlaod from [Gitlab Captable](https://gitlab.com/brreg1/captable/-/releases) to /contracts/ folder 7. Run it ```typescript= // run.ts import { getCapTable } from '../../utils/contracts'; export const run = async () => { const [capTable] = getCapTable(address) if(capTable){ const owner = await capTable.owner() console.log("owner =", owner) } } run() `" ## Integrating backend If you are creating a backend application and then don't have a provider within Metamask etc. you can connect directly to the node with ethers library. ```typescript= const privateKey = process.env.PRIVATE_KEY || "set env"; // 0xbb1c879cb7f5129ba026DfE1E5f30979D7978A65 const wallet = new ethers.Wallet(privateKey); const provider = process.env.NODE_ENV === "production" ? new ethers.providers.JsonRpcProvider({ url: process.env.PROVIDER_URL || "set env", user: process.env.PROVIDER_USER || "set env", password: process.env.PROVIDER_PASS || "set env", }) : new ethers.providers.JsonRpcProvider({ url: process.env.PROVIDER_URL || "set env, }); const signer = wallet.connect(provider); const authOracle = new AuthOracleFactory(signer).attach( process.env.AUTH_ORACLE_ADDRESS || "set env" ); `"