diff --git a/docs/api/classes/PinataAdapter.md b/docs/api/classes/PinataAdapter.md index 16e455c2..8f2de277 100644 --- a/docs/api/classes/PinataAdapter.md +++ b/docs/api/classes/PinataAdapter.md @@ -1,19 +1,22 @@ # Class: PinataAdapter -PinataAdapter +A Colony SDK IPFS adapter for Pinata (https://pinata.cloud) -A Colony SDK IPFS adapter for Pinata (https://pinata.cloud). In order to use this, sign up for Pinata (if you haven't already) and generate a token. Then either supply this token when instantiating the class (example below) or provide it via the environment variable `COLONY_IPFS_PINATA_TOKEN` (when using NodeJS). Then provide an instance of this class to the [ColonyNetwork](ColonyNetwork.md) or [ColonyEventManager](ColonyEventManager.md) classes (depending on your needs). +In order to use this, sign up for Pinata (if you haven't already) and generate a token. Then either supply this token when instantiating the class (example below) or provide it via the environment variable `COLONY_IPFS_PINATA_TOKEN` (when using NodeJS). Then provide an instance of this class to the [ColonyNetwork](ColonyNetwork.md) or [ColonyEventManager](ColonyEventManager.md) classes (depending on your needs). -**`Remarks`** - -DO NOT CHECK IN YOUR PINATA TOKEN INTO VERSION CONTROL AND **DO NOT EMBED IT INTO YOUR FRONTEND BUNDLE**. +:::danger Tokens are sensitive data +Do not check in your Pinata token into version control and **DO NOT EMBED IT INTO YOUR FRONTEND BUNDLE**. +::: **`Example`** ```typescript import { ColonyNetwork, PinataAdapter } from '@colony/sdk'; -const pinataAdapter = new PinataAdapter('YOUR_PINANTA_JWT_TOKEN'); -const colonyNetwork = new ColonyNetwork({ ipfsAdapter: pinataAdapter }); +const pinataAdapter = new PinataAdapter('[YOUR_PINANTA_JWT_TOKEN]'); +// Immediately executing async function +(async function() { + const colonyNetwork = ColonyNetwork.init(signerOrProvider, { ipfsAdapter: pinataAdapter }); +})(); ``` ## Implements diff --git a/docs/start.md b/docs/getting-started/index.md similarity index 95% rename from docs/start.md rename to docs/getting-started/index.md index c70fe131..b9024825 100644 --- a/docs/start.md +++ b/docs/getting-started/index.md @@ -1,5 +1,5 @@ --- -sidebar_position: 0 +sidebar_position: 1 description: A stupidly short guide to get started with Colony development --- @@ -37,7 +37,6 @@ For browser based projects, consider using a build system like [esbuild](https:/ ::: ```javascript -// index.js import { providers } from 'ethers'; import { ColonyNetwork, toEth } from '@colony/sdk'; @@ -50,7 +49,7 @@ const start = async () => { // This will try to connect the page to MetaMask await provider.send('eth_requestAccounts', []); // Create a new connection to the Colony Network contracts using the MetaMask "wallet" - const colonyNetwork = new ColonyNetwork(provider.getSigner()); + const colonyNetwork = await ColonyNetwork.init(provider.getSigner()); // Connect to the MetaColony (this could be replaced with your own colony using `colonyNetwork.getColony(COLONY_ADDRESS)`) const metaColony = await colonyNetwork.getMetaColony(); // Get the CLNY funding for the MetaColony (CLNY is it's native token) @@ -72,7 +71,7 @@ Include the resulting bundle in an HTML file and open it in you favorite browser const { providers, Wallet } = require('ethers'); const { ColonyNetwork } = require('@colony/sdk'); -const provider = new providers.JsonRpcProvider('https://rpc.gnosischain.com/'); +const provider = new providers.JsonRpcProvider('https://xdai.colony.io/rpc2/'); const wallet = Wallet.createRandom().connect(provider); // Get the Colony's XDAI funding in the ROOT pot (id 1) diff --git a/docs/getting-started/your-first-transaction.md b/docs/getting-started/your-first-transaction.md new file mode 100644 index 00000000..931407af --- /dev/null +++ b/docs/getting-started/your-first-transaction.md @@ -0,0 +1,93 @@ +--- +description: In this guide we look at a more involved example. We create a team within a colony and inspect the results of this transaction. + +sidebar_position: 0 +--- + +# Creating your first transaction + +In this example we're going through the process of creating a team (domain) within a colony using only Colony SDK. It is meant to run inside a browser with the MetaMask extension installed. If you need a template (with build system) to start from, take a look at [colonyStarter](https://github.com/JoinColony/colonyStarter). + +## Connecting to an existing colony + +For this example we assume that you want to connect to a Colony that already exists and the MetaMask account we are using has the appropriate permissions (*Architecture* role in the Root team). + +```typescript +import { providers } from 'ethers'; +import { ColonyNetwork } from '@colony/sdk'; + +// If MetaMask is installed there will be an `ethereum` object on the `window` +// NOTE: Make sure MetaMask is connected to Gnosis chain (see https://docs.gnosischain.com/tools/wallets/metamask) +const provider = new providers.Web3Provider(window.ethereum); + +// We are calling a bunch of async functions so we are creating this wrapper function +const start = async () => { + // This will try to connect the page to MetaMask + await provider.send('eth_requestAccounts', []); + // Create a new connection to the Colony Network contracts using the MetaMask "wallet" + const colonyNetwork = await ColonyNetwork.init(provider.getSigner()); + // Connect to a colony (replace the address with the address of the colony you'd like to use) + // This is the devdemo colony (https://xdai.colony.io/colony/devdemo) + const colony = await colonyNetwork.getColony('0x364B3153A24bb9ECa28B8c7aCeB15E3942eb4fc5'); +}; + +start(); +``` + +## Creating the team's metadata object + +Let's prepare some metadata for the colony details. We created a [`DomainMetadata`](../api/interfaces/DomainMetadata.md) object and stored it under the IPFS hash [`QmTwksWE2Zn4icTvk5E7QZb1vucGNuu5GUCFZ361r8gKXM`](https://gateway.pinata.cloud/ipfs/QmTwksWE2Zn4icTvk5E7QZb1vucGNuu5GUCFZ361r8gKXM): + +```json +{ + "version": 2, + "name": "domain", + "data": { + "domainName": "A-Team", + "domainColor": 0, + "domainPurpose": "Pass Butter" + } +} +``` + +:::info +Storing data on chain is expensive. Metadata is stored on IPFS and our solution to enrich on-chain data with additional information and only used in very few methods around Colony. **We also provide ways to automatically create and store metadata for your transaction.** See [Metadata](../guides/metadata.md) for more information. +::: + +## Creating the team + +Let's imagine we continue in our async function `start` from above: + +```typescript +const [{ domainId }, receipt, getMetadata] = await colony.createTeam('QmTwksWE2Zn4icTvk5E7QZb1vucGNuu5GUCFZ361r8gKXM').tx(); +``` + +You can see that calling the `tx()` function on the [`TxCreator`](../api/classes/TxCreator.md) returns a tuple with three entries: + +### Event data + +The first entry is the Ethereum event data, emitted by the contract transaction, already parsed by ethers, so that you can directly access it on the object. To find out what event data is returned by a transaction you can either rely on the TypeScript types or look up the relevant [Event data](../api/classes/Colony.md#event-data-3) section in the documentation of the corresponding method. This entry exists on all methods that emit events on contracts (almost all of them). + +### Contract receipt + +The second entry is a receipt object. This is the `ethers` `ContractReceipt` (see [the ethers docs](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionReceipt)) that was issues during the transaction. + +### Metadata getter function + +The third entry is a function that can be called to get that metadata that was created or attached to the transaction events. This is usually not very interesting in this context as we just stored the metadata. Note that this is only available in very few functions that have metadata attached to them. Here's how you'd use this function: + +```typescript +const { domainName, domainColor, domainPurpose } = await getMetadata(); +``` + +Read more about metadata within Colony [here](../guides/metadata.md). + +## Where to go from here? + +Congrats on creating your first transaction with Colony SDK! This is just the beginning! + +Make sure you're making yourself familiar with [how transactions work in Colony SDK](../guides/transactions.md) and then feel free to check out the [Colony API docs](../api/classes/Colony.md). There's lots to explore there! + +:::tip Examples! Examples! Examples! +Yes, we have plenty of examples for you to explore on how to do all sorts of things in Colony SDK. Want to create a motion or decision? Want to see how reputation works? Check out our [browser examples](https://github.com/JoinColony/colonySDK/tree/main/examples/browser/src) or if you prefer to run things on the server side, we also have [NodeJS based examples](https://github.com/JoinColony/colonySDK/tree/main/examples/node). By the way, we have deployed the browser based examples [here](https://joincolony.github.io/colonySDK/) for you to try them immediately. +::: diff --git a/docs/guides/colony-creation.md b/docs/guides/colony-creation.md index d79e3129..f10492b6 100644 --- a/docs/guides/colony-creation.md +++ b/docs/guides/colony-creation.md @@ -1,7 +1,7 @@ --- description: A guide on how to create a colony programmatically. The deployment of a colony requires a handful of transactions for it to be up and running and fully usable. This guide explains how to go through the whole process using Colony SDK -sidebar_position: 1 +sidebar_position: 2 --- # Creating a colony @@ -14,7 +14,7 @@ Even though deploying a Colony is technically just a matter of issuing one trans For a full example see [here](https://github.com/JoinColony/colonySDK/blob/main/examples/node/create.ts). :::info -These examples assume that the user executing the transactions has funds in their wallet to pay for gas. If you'd like to use gasless transactions instead, use `forceMeta()` instead of `force()`. +These examples assume that the user executing the transactions has funds in their wallet to pay for gas. If you'd like to use gasless transactions instead, use `metaTx()` instead of `tx()`. ::: ## Step 1 (optional) - Creating a token @@ -57,7 +57,7 @@ const colony = await colonyNetwork.getColony(colonyAddress); const { token } = colony; ``` -## Step 4 (optional) - Deploy the token authority +## Step 4 (optional) - Deploy the token authority and set the owner The token authority is a contract that glues the token and the colony together and makes it possible for the colony to manage and move the token. The token authority can be deployed using the `deployAuthority` method on the `Token`. After that, another transaction is needed to set the token's `authority` to the one that was just deployed. If the token does not support the `setAuthority` method, this step should be skipped. @@ -67,10 +67,11 @@ const [{ tokenAuthorityAddress }] = await token .deployAuthority([colonyAddress]) .tx(); // Set the token's authority to the freshly deployed one -await token.setAuthority(tokenAuthorityAddress).force(); +await token.setAuthority(tokenAuthorityAddress).tx(); +// Set the token's owner (the colony), to have permissions to execute authorized functions (like `mint`) +await colony.token.setOwner(colony.address).tx(); ``` - ## Step 5 - Install the `OneTxPayment` extension As mentioned earlier, this step is technically optional as well but if the colony is supposed to be used productively, a form of payment extension is needed. Currently only the `OneTxPayment` extension is supported. Install it like so: @@ -91,7 +92,6 @@ const [{ user, setTo, role }] = await colony Here we install the extension using the `installExtension` method. This extension is an own contract that was deployed in this transaction. To get its address, we re-initialize the extensions on the colony using `updateExtensions`. After that, `oneTx` will be available on `colony.ext`. Finally, we assign the **Administration** and **Funding** roles of the colony's `Root` team to the extension that we just deployed. The OneTxPayment extension needs these permissions to function properly. - ## That's it! We have successfully deployed a colony that can be used from the dApp as well. Explore what's possible within a colony using Colony SDK [here](../api/classes/Colony.md). diff --git a/docs/guides/metadata.md b/docs/guides/metadata.md new file mode 100644 index 00000000..520fd116 --- /dev/null +++ b/docs/guides/metadata.md @@ -0,0 +1,20 @@ +--- +description: A guide on how to handle IPFS metadata in Colony. We explore how to use a different IPFS adapter to let Colony SDK do the heavy lifting. + +sidebar_position: 2 +--- + +# Metadata within Colony + +Storing data on chain is expensive. Metadata is stored on IPFS and our solution to enrich on-chain data with additional information and only used in very few methods around Colony. We also provide ways to automatically create and store metadata for your transaction. + +Metadata is stored on IPFS and needs to be formatted in a certain way. There are multiple ways of handling metadata: + +## Manual creation of the data as JSON object + +To create the metadata objects manually you can use the `@colony/colony-event-metadata-parser`, package which can de(serialize) the data for you in the required format. Read more about it [here](https://github.com/JoinColony/ColonyEventMetadataParser). Once you have the stringified data, you'd upload it to IPFS using your preferred upload and pinning method. + +## Let Colony SDK take care of it + +For this an upload/pin compatible [`IpfsAdapter`](../api/interfaces/IpfsAdapter.md) has to be used (like the [`PinataIpfsAdapter`](../api/classes/PinataAdapter.md)). With that you can provide the metadata as a JavaScript object to the relevant method and Colony SDK will take care of proper serialization and pinning/uploading it to IPFS. + diff --git a/docs/guides/transactions.md b/docs/guides/transactions.md index b50a66fa..c71564f9 100644 --- a/docs/guides/transactions.md +++ b/docs/guides/transactions.md @@ -1,7 +1,7 @@ --- description: A guide on how to create transactions within Colony. You can create motions and even gasless MetaTransactions in a very straightforward and concise way. -sidebar_position: 0 +sidebar_position: 1 --- # How to create transactions diff --git a/docs/index.md b/docs/index.md index 601b5873..0c2264d0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,6 +11,8 @@ The Colony SDK is a community project aiming to provide a quick and easy way to The goal is to simplify the complexity of the contract's functions to serve the most popular functions using an easy-to-understand programming interface while providing sane defaults and fallbacks. We also provide various examples for various applications to get you up and building with Colony in no time! -If you're impatient to start building, check out the Quickstart page. If you're already thinking that the feature set of Colony SDK might be too limiting for your use case, you might want to check out its bigger sibling, [ColonyJS](https://docs.colony.io/colonyjs), the almighty Colony API reference implementation (in TypeScript). +If you're impatient to start building, check out the [Getting Started](getting-started/index.md) pages. + +If you're already thinking that the feature set of Colony SDK might be too limiting for your use case, you might want to check out its bigger sibling, [ColonyJS](https://docs.colony.io/colonyjs), the almighty Colony API reference implementation (in TypeScript). The Colony SDK is under continuous development, with new features constantly being added, and should cover most common use cases. diff --git a/examples/node/create.ts b/examples/node/create.ts index 78a9b9b5..62fa802e 100644 --- a/examples/node/create.ts +++ b/examples/node/create.ts @@ -42,6 +42,7 @@ const start = async () => { // Set the token's authority to the freshly deployed one if (colony.token instanceof ColonyToken) { await colony.token.setAuthority(tokenAuthorityAddress).tx(); + await colony.token.setOwner(colony.address).tx(); } // Install OneTxPayment extension const [{ extensionId, version }] = await colony diff --git a/src/index.ts b/src/index.ts index 6846cd65..8c7a6a0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export { MotionState, NetworkClientOptions, Tokens } from '@colony/colony-js'; export type { AnnotationMetadata, ColonyMetadata, + DecisionMetadata, DomainMetadata, MetadataType, } from '@colony/colony-event-metadata-parser'; diff --git a/src/ipfs/PinataAdapter.ts b/src/ipfs/PinataAdapter.ts index 23d106aa..fe79f0b4 100644 --- a/src/ipfs/PinataAdapter.ts +++ b/src/ipfs/PinataAdapter.ts @@ -6,19 +6,23 @@ const COLONY_IPFS_PINATA_TOKEN = : undefined; /** - * PinataAdapter + * A Colony SDK IPFS adapter for Pinata (https://pinata.cloud) * - * A Colony SDK IPFS adapter for Pinata (https://pinata.cloud). In order to use this, sign up for Pinata (if you haven't already) and generate a token. Then either supply this token when instantiating the class (example below) or provide it via the environment variable `COLONY_IPFS_PINATA_TOKEN` (when using NodeJS). Then provide an instance of this class to the [[ColonyNetwork]] or [[ColonyEventManager]] classes (depending on your needs). + * In order to use this, sign up for Pinata (if you haven't already) and generate a token. Then either supply this token when instantiating the class (example below) or provide it via the environment variable `COLONY_IPFS_PINATA_TOKEN` (when using NodeJS). Then provide an instance of this class to the [[ColonyNetwork]] or [[ColonyEventManager]] classes (depending on your needs). * - * @remarks DO NOT CHECK IN YOUR PINATA TOKEN INTO VERSION CONTROL AND **DO NOT EMBED IT INTO YOUR FRONTEND BUNDLE**. + * :::danger Tokens are sensitive data + * Do not check in your Pinata token into version control and **DO NOT EMBED IT INTO YOUR FRONTEND BUNDLE**. + * ::: * * @example * ```typescript * import { ColonyNetwork, PinataAdapter } from '@colony/sdk'; - * const pinataAdapter = new PinataAdapter('YOUR_PINANTA_JWT_TOKEN'); - * const colonyNetwork = new ColonyNetwork({ ipfsAdapter: pinataAdapter }); + * const pinataAdapter = new PinataAdapter('[YOUR_PINANTA_JWT_TOKEN]'); + * // Immediately executing async function + * (async function() { + * const colonyNetwork = ColonyNetwork.init(signerOrProvider, { ipfsAdapter: pinataAdapter }); + * })(); * ``` - * */ class PinataAdapter implements IpfsAdapter { private token: string;