diff --git a/.github/actions/prepare/action.yaml b/.github/actions/prepare/action.yaml index cb21d4c63eb..9f290012d6e 100644 --- a/.github/actions/prepare/action.yaml +++ b/.github/actions/prepare/action.yaml @@ -6,7 +6,7 @@ runs: steps: - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Allow modern Yarn run: corepack enable shell: bash diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 1f0113846df..bee16ac201f 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -14,7 +14,7 @@ jobs: publish: strategy: matrix: - package: [core, cli, plugin-tutorial] + package: [core, cli] include: - package: core path: 'package.json' @@ -22,9 +22,6 @@ jobs: - package: cli path: 'cli/package.json' workspace: '@iota-wiki/cli' - - package: plugin-tutorial - path: 'plugins/tutorial/package.json' - workspace: '@iota-wiki/plugin-tutorial' uses: ./.github/workflows/publish.reusable.yaml with: path: ${{ matrix.path }} diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index f384e406ff6..058996ebdd6 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -10,7 +10,7 @@ jobs: tag: strategy: matrix: - package: [core, cli, plugin-tutorial] + package: [core, cli] include: - package: core path: 'package.json' @@ -18,9 +18,6 @@ jobs: - package: cli path: 'cli/package.json' workspace: '@iota-wiki/cli' - - package: plugin-tutorial - path: 'plugins/tutorial/package.json' - workspace: '@iota-wiki/plugin-tutorial' uses: ./.github/workflows/tag.reusable.yaml with: path: ${{ matrix.path }} diff --git a/README.md b/README.md index f9a0d5dbfec..2dad7cde9c6 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ To preview the Wiki locally, use the following steps. For more detailed scripts, | Script | Explanation | |---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `prepare` | Prepare the environment by checking out submodules and building local packages needed for the Wiki build. | +| `prepare` | Prepare the environment by checking out submodules build. | | `start` | Start a development server serving the Wiki, with hot reloading on changes. | | `start:section:{section}` | Start a development server serving only a section of the Wiki, with hot reloading on changes. Available sections are `build`, `get-started`, `learn`, and `maintain`. | | `build` | Build the Wiki. To build for production, checkout the latest version of external documentation by running `yarn checkout:remote` and set the `MODE` environment variable to `production`. | diff --git a/cli/src/commands/default.tsx b/cli/src/commands/default.tsx index 265ce925eea..ca373d30fbc 100644 --- a/cli/src/commands/default.tsx +++ b/cli/src/commands/default.tsx @@ -21,11 +21,6 @@ const DefaultComponent: FC = (props) => { label: 'Check the current directory for broken links.', value: 'check', }, - { - label: - 'Configure the tutorial settings to properly list it on the IOTA Wiki.', - value: 'configure', - }, ]; const onSelect = (item) => { @@ -38,9 +33,6 @@ const DefaultComponent: FC = (props) => { if (item.value === 'check') { props.command.cli.run(['check']); } - if (item.value === 'configure') { - props.command.cli.run(['tutorial', 'configure']); - } }; return ( diff --git a/cli/src/commands/tutorial/configure.tsx b/cli/src/commands/tutorial/configure.tsx deleted file mode 100644 index c7a8318904a..00000000000 --- a/cli/src/commands/tutorial/configure.tsx +++ /dev/null @@ -1,533 +0,0 @@ -import React, { FC, useEffect, useState } from 'react'; -import { Command } from 'clipanion'; -import { - render, - Box, - Text, - useFocus, - useFocusManager, - useInput, - Newline, - useApp, -} from 'ink'; -import TextInput from 'ink-text-input'; -import SelectInput from 'ink-select-input'; -import MultiSelect, { ListedItem } from 'ink-multi-select'; -import fs from 'fs'; -import axios from 'axios'; -import Spinner from 'ink-spinner'; -import { parse } from '@babel/parser'; -import { - Statement, - Expression, - ObjectExpression, - PatternLike, - memberExpression, - arrayExpression, - assignmentExpression, - identifier, - objectExpression, - objectProperty, - expressionStatement, - stringLiteral, -} from '@babel/types'; -import generator from '@babel/generator'; -import { type UserOptions as TutorialOptions } from '@iota-wiki/plugin-tutorial'; -import prettier from 'prettier'; - -interface InputComponentProps { - label: string; - value: string; - onChange: (value: string) => void; -} - -const InputComponent: FC = (props) => { - const { isFocused } = useFocus(); - - return ( - - - {props.label}: - - - - ); -}; - -interface SelectComponentProps { - label: string; - items: ListedItem[]; - value: ListedItem[]; - onChange: (items: ListedItem[]) => void; -} - -const SelectComponent: FC = (props) => { - const { isFocused } = useFocus(); - - const onSelect = (item) => { - props.onChange([...props.value, item]); - }; - - const onUnselect = (item) => { - props.onChange(props.value.filter((o) => o !== item)); - }; - - return ( - - - {props.label}: - {props.value && ( - - {props.value - .map((item) => item.label) - .sort() - .join(', ')} - - )} - - - - - - ); -}; - -interface SubmitComponentItem { - label: string; - value: () => void; -} - -export interface SubmitComponentProps { - label: string; - items: Array; -} - -const SubmitComponent: FC = (props) => { - const { isFocused } = useFocus(); - - return ( - - {props.label}: - item.value()} - /> - - - ); -}; - -export interface Tag { - label: string; - value: string; - description: string; - color: string; -} - -type TagCategories = Map>; - -interface SetupComponentProps { - defaultOptions: Partial; - addPlugin: (options: TutorialOptions) => void; -} - -const SetupComponent: FC = (props) => { - const { focusNext } = useFocusManager(); - const [options, setOptions] = useState< - Partial | undefined - >(); - const [loaded, setLoaded] = useState(false); - const [availableTags, setAvailableTags] = useState< - TagCategories | undefined - >(); - const [tagsByCategory, setTagsByCategory] = useState< - TagCategories | undefined - >(); - - const getOptions = async () => { - const git = await import('isomorphic-git'); - - // TODO First check if a sidebar with valid content exist, else: - const files = await fs.promises.readdir('docs'); - const route = files[0].replace(/\.[^/.]+$/, ''); - - const dir = await git.findRoot({ - fs, - filepath: process.cwd(), - }); - - const source = await git.getConfig({ - fs, - dir, - path: 'remote.origin.url', - }); - - setOptions(Object.assign({ route, source }, props.defaultOptions)); - }; - - const getAvailableTags = async () => { - const { data } = await axios.get>>( - 'https://raw.githubusercontent.com/iota-community/iota-wiki/feat/tuto-section/content/tutorials/tags.json', - ); - - setAvailableTags(new Map(Object.entries(data))); - }; - - useEffect(() => { - getAvailableTags(); - getOptions(); - }, []); - - useEffect(() => { - if (availableTags) { - const tagsByCategory = !options.tags - ? new Map() - : new Map( - Array.from(availableTags, ([category, tags]) => { - return [ - category, - tags.filter((tag) => options.tags.includes(tag.value)), - ]; - }), - ); - setTagsByCategory(tagsByCategory); - } - }, [availableTags]); - - useEffect(() => { - setLoaded(!!options && !!tagsByCategory); - }, [options, tagsByCategory]); - - useEffect(() => { - if (loaded) focusNext(); - }, [loaded]); - - useInput((_, key) => { - if (key.escape) process.exit(); - if (key.return) focusNext(); - }); - - const onChangeTags = (category: string) => (tags: Array) => { - const newTagsByCategory = tagsByCategory.set(category, tags); - const newTags = Array.from(newTagsByCategory.values()) - .flat() - .map((tag) => tag.value); - - setTagsByCategory(newTagsByCategory); - setOptions({ ...options, tags: newTags }); - }; - - const onChangeOption = (option: keyof typeof options) => (value) => { - setOptions({ ...options, [option]: value }); - }; - - const addPlugin = () => { - // TODO: Handle invalid or missing required options. - const normalizedOptions = Object.assign< - TutorialOptions, - Partial - >( - { - title: '', - description: '', - tags: [], - }, - options, - ); - - props.addPlugin(normalizedOptions); - process.exit(); - }; - - return ( - - Configure the tutorial using the options below. - - Use ENTER, TAB and SHIFT+TAB to move up or down. - Use SPACE to select items. - - {loaded ? ( - <> - - - - - {Array.from(availableTags, ([category, tags]) => ( - - ))} - - - ) : ( - - Loading data... - - )} - - ); -}; - -interface SelectTutorialComponentItem { - label: string; - value: number; -} - -interface SelectTutorialComponentProps { - items: SelectTutorialComponentItem[]; - onSelect: (index: number) => void; -} - -const SelectTutorialComponent: FC = (props) => { - const { exit } = useApp(); - - const handleSelect = (item) => { - props.onSelect(item.value); - exit(); - }; - - return ( - - Choose a plugin to configure or add a new one: - - - ); -}; - -function tryModuleExports(statement: Statement): Expression { - if ( - statement.type === 'ExpressionStatement' && - statement.expression.type === 'AssignmentExpression' && - statement.expression.left.type === 'MemberExpression' && - statement.expression.left.object.type === 'Identifier' && - statement.expression.left.object.name === 'module' && - statement.expression.left.property.type === 'Identifier' && - statement.expression.left.property.name === 'exports' - ) { - return statement.expression.right; - } -} - -function getConfig(statements: Statement[]): Expression { - let expression = statements.reduce( - (previous, current) => previous || tryModuleExports(current), - null as Expression, - ); - - if (expression === null) { - expression = assignmentExpression( - '=', - memberExpression(identifier('module'), identifier('exports')), - objectExpression([]), - ); - - statements.push(expressionStatement(expression)); - } - - return expression; -} - -function tryPlugins( - property: ObjectExpression['properties'][number], -): Expression | PatternLike { - if ( - property.type === 'ObjectProperty' && - property.key.type === 'Identifier' && - property.key.name === 'plugins' - ) { - return property.value; - } -} - -function getPlugins(properties: ObjectExpression['properties']) { - let plugins = properties.reduce( - (previous, current) => previous || tryPlugins(current), - null as Expression | PatternLike, - ); - - if (plugins === null) { - plugins = arrayExpression([]); - - properties.push(objectProperty(identifier('plugins'), plugins)); - } - - return plugins; -} - -export class Setup extends Command { - static paths = [[`tutorial`, `configure`]]; - - static usage = Command.Usage({ - description: `Configure the tutorial settings to properly list it on the IOTA Wiki.`, - }); - - async execute() { - // TODO: Remove hardcoded config file path. - const filePath = 'docusaurus.config.js'; - - const ast = parse(fs.readFileSync(filePath, 'utf-8')); - const config = getConfig(ast.program.body); - - // TODO: Allow config exported via variable assigned to `module.exports`. - if (config.type !== 'ObjectExpression') - throw 'Module needs to export a config object.'; - - const plugins = getPlugins(config.properties); - - // TODO: Allow variable and convert it to variable spread in array literal. - if (plugins.type !== 'ArrayExpression') - throw 'Plugins property needs to be an array.'; - - const tutorialPlugins = plugins.elements.reduce( - (plugins, element, index) => { - if (element.type === 'ArrayExpression') { - const pluginElement = element.elements[0]; - - if ( - pluginElement.type !== 'StringLiteral' || - pluginElement.value !== '@iota-wiki/plugin-tutorial' - ) { - return plugins; - } - - const optionsElement = element.elements[1]; - - if (optionsElement.type !== 'ObjectExpression') return plugins; - - const options = optionsElement.properties.reduce< - Partial - >((properties, property) => { - if ( - property.type === 'ObjectProperty' && - property.key.type === 'Identifier' - ) { - if (property.value.type === 'StringLiteral') { - properties[property.key.name] = property.value.value; - } - - if ( - property.key.name === 'tags' && - property.value.type === 'ArrayExpression' - ) { - properties.tags = property.value.elements.reduce( - (tags, tag) => { - if (tag.type === 'StringLiteral') tags.push(tag.value); - return tags; - }, - [], - ); - } - } - return properties; - }, {}); - - return plugins.set(index, options); - } - return plugins; - }, - new Map>(), - ); - - let pluginIndex: number | undefined; - const setPluginIndex = (index) => (pluginIndex = index); - - if (tutorialPlugins.size > 0) { - const items = Array.from(tutorialPlugins, ([index, options]) => ({ - label: options.title, - value: index, - })); - - items.push({ - label: 'Add a new tutorial...', - value: plugins.elements.length, - }); - - const { waitUntilExit } = render( - , - ); - - await waitUntilExit(); - - if (pluginIndex === undefined) process.exit(); - } - - const addPlugin = (options: TutorialOptions) => { - const { tags, ...rest } = options; - - plugins.elements[pluginIndex] = arrayExpression([ - stringLiteral('@iota-wiki/plugin-tutorial'), - objectExpression([ - ...Object.entries(rest).map(([key, value]) => - objectProperty(identifier(key), stringLiteral(value)), - ), - objectProperty( - identifier('tags'), - arrayExpression(tags.map((value) => stringLiteral(value))), - ), - ]), - ]); - - const { code } = generator(ast); - const formattedCode = prettier.format(code, { - filepath: filePath, - singleQuote: true, - jsxSingleQuote: true, - trailingComma: 'all', - }); - fs.writeFileSync(filePath, formattedCode); - }; - - const { waitUntilExit } = render( - , - ); - - await waitUntilExit(); - } -} diff --git a/cli/src/docusaurus/config/common.js b/cli/src/docusaurus/config/common.js index 94ac286f5ae..56f2feb7870 100644 --- a/cli/src/docusaurus/config/common.js +++ b/cli/src/docusaurus/config/common.js @@ -31,7 +31,6 @@ const common = { ), }, ], - '@iota-wiki/theme', path.resolve(__dirname, '../theme'), ], themeConfig: { diff --git a/cli/src/index.tsx b/cli/src/index.tsx index bd2db8f447e..66524b4740b 100644 --- a/cli/src/index.tsx +++ b/cli/src/index.tsx @@ -6,7 +6,6 @@ import { Start } from './commands/start'; import { Build } from './commands/build'; import { Check } from './commands/check'; import { Lint } from './commands/lint'; -import { Setup } from './commands/tutorial/configure'; import { Default } from './commands/default'; const args = process.argv.slice(2); @@ -23,6 +22,5 @@ cli.register(Start); cli.register(Build); cli.register(Check); cli.register(Lint); -cli.register(Setup); cli.register(Default); cli.runExit(args); diff --git a/cli/test/tutorial/code_snippet.py b/cli/test/tutorial/code_snippet.py deleted file mode 100644 index 53dac671926..00000000000 --- a/cli/test/tutorial/code_snippet.py +++ /dev/null @@ -1,10 +0,0 @@ -# start -def fib(n): - a, b = 0, 1 - while a < n: - print(a, end=' ') - a, b = b, a+b - print() -# end - -fib(1000) diff --git a/cli/test/tutorial/docs/index.md b/cli/test/tutorial/docs/index.md deleted file mode 100644 index 500260230bf..00000000000 --- a/cli/test/tutorial/docs/index.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Tutorial Intro - -Let's discover **Docusaurus in less than 5 minutes**. - -## Getting Started - -Get started by **creating a new site**. - -Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**. - -### What you'll need - -- [Node.js](https://nodejs.org/en/download/) version 14 or above: - - When installing Node.js, you are recommended to check all checkboxes related to dependencies. - -## Generate a new site - -Generate a new Docusaurus site using the **classic template**. - -The classic template will automatically be added to your project after you run the command: - -```bash -npm init docusaurus@latest my-website classic -``` - -You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor. - -The command also installs all necessary dependencies you need to run Docusaurus. - -## Start your site - -Run the development server: - -```bash -cd my-website -npm run start -``` - -The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there. - -The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/. - -Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes. diff --git a/cli/test/tutorial/docs/tutorial-basics/_category_.json b/cli/test/tutorial/docs/tutorial-basics/_category_.json deleted file mode 100644 index 135e4a6858b..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Tutorial - Basics", - "position": 2 -} diff --git a/cli/test/tutorial/docs/tutorial-basics/congratulations.md b/cli/test/tutorial/docs/tutorial-basics/congratulations.md deleted file mode 100644 index 9ef99bbadd9..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/congratulations.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -sidebar_position: 6 ---- - -# Congratulations! - -You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. - -Docusaurus has **much more to offer**! - -Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. - -Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) - -## What's next? - -- Read the [official documentation](https://docusaurus.io/). -- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) -- Add a [search bar](https://docusaurus.io/docs/search) -- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) -- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) diff --git a/cli/test/tutorial/docs/tutorial-basics/create-a-blog-post.md b/cli/test/tutorial/docs/tutorial-basics/create-a-blog-post.md deleted file mode 100644 index 0d50aaf3163..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/create-a-blog-post.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -sidebar_position: 3 ---- - -# Create a Blog Post - -Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... - -## Create your first Post - -Create a file at `blog/2021-02-28-greetings.md`: - -```md title="blog/2021-02-28-greetings.md" ---- -slug: greetings -title: Greetings! -authors: - - name: Joel Marcey - title: Co-creator of Docusaurus 1 - url: https://github.com/JoelMarcey - image_url: https://github.com/JoelMarcey.png - - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png -tags: [greetings] ---- - -Congratulations, you have made your first post! - -Feel free to play around and edit this post as much you like. -``` - -A new blog post is now available at `http://localhost:3000/blog/greetings`. diff --git a/cli/test/tutorial/docs/tutorial-basics/create-a-document.md b/cli/test/tutorial/docs/tutorial-basics/create-a-document.md deleted file mode 100644 index a9bb9a4140b..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/create-a-document.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Create a Document - -Documents are **groups of pages** connected through: - -- a **sidebar** -- **previous/next navigation** -- **versioning** - -## Create your first Doc - -Create a markdown file at `docs/hello.md`: - -```md title="docs/hello.md" -# Hello - -This is my **first Docusaurus document**! -``` - -A new document is now available at `http://localhost:3000/docs/hello`. - -## Configure the Sidebar - -Docusaurus automatically **creates a sidebar** from the `docs` folder. - -Add metadata to customize the sidebar label and position: - -```md title="docs/hello.md" {1-4} ---- -sidebar_label: 'Hi!' -sidebar_position: 3 ---- - -# Hello - -This is my **first Docusaurus document**! -``` - -It is also possible to create your sidebar explicitly in `sidebars.js`: - -```js title="sidebars.js" -module.exports = { - tutorialSidebar: [ - { - type: 'category', - label: 'Tutorial', - // highlight-next-line - items: ['hello'], - }, - ], -}; -``` diff --git a/cli/test/tutorial/docs/tutorial-basics/create-a-page.md b/cli/test/tutorial/docs/tutorial-basics/create-a-page.md deleted file mode 100644 index e112b0059c2..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/create-a-page.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Create a Page - -Add **Markdown or React** files to `src/pages` to create a **standalone page**: - -- `src/pages/index.js` -> `localhost:3000/` -- `src/pages/foo.md` -> `localhost:3000/foo` -- `src/pages/foo/bar.js` -> `localhost:3000/foo/bar` - -## Create your first React Page - -Create a file at `src/pages/my-react-page.js`: - -```jsx title="src/pages/my-react-page.js" -import React from 'react'; -import Layout from '@theme/Layout'; - -export default function MyReactPage() { - return ( - -

My React page

-

This is a React page

-
- ); -} -``` - -A new page is now available at `http://localhost:3000/my-react-page`. - -## Create your first Markdown Page - -Create a file at `src/pages/my-markdown-page.md`: - -```mdx title="src/pages/my-markdown-page.md" -# My Markdown page - -This is a Markdown page -``` - -A new page is now available at `http://localhost:3000/my-markdown-page`. diff --git a/cli/test/tutorial/docs/tutorial-basics/deploy-your-site.md b/cli/test/tutorial/docs/tutorial-basics/deploy-your-site.md deleted file mode 100644 index 492eae0276b..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/deploy-your-site.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -sidebar_position: 5 ---- - -# Deploy your site - -Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). - -It builds your site as simple **static HTML, JavaScript and CSS files**. - -## Build your site - -Build your site **for production**: - -```bash -npm run build -``` - -The static files are generated in the `build` folder. - -## Deploy your site - -Test your production build locally: - -```bash -npm run serve -``` - -The `build` folder is now served at `http://localhost:3000/`. - -You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/cli/test/tutorial/docs/tutorial-basics/markdown-features.mdx b/cli/test/tutorial/docs/tutorial-basics/markdown-features.mdx deleted file mode 100644 index 413fbded4c5..00000000000 --- a/cli/test/tutorial/docs/tutorial-basics/markdown-features.mdx +++ /dev/null @@ -1,156 +0,0 @@ ---- -sidebar_position: 4 ---- -import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton' -import { Networks } from '@theme/constant' -import CodeSnippetBlock from '@theme/CodeSnippetBlock' -import code_snippet from '!!raw-loader!../../code_snippet.py' - -# Markdown Features - -Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. - -## Front Matter - -Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): - -```text title="my-doc.md" -// highlight-start ---- -id: my-doc-id -title: My document title -description: My document description -slug: /my-custom-url ---- -// highlight-end - -## Markdown heading - -Markdown text with [links](./hello.md) -``` - -## Links - -Regular Markdown links are supported, using url paths or relative file paths. - -```md -Let's see how to [Create a page](/create-a-page). -``` - -```md -Let's see how to [Create a page](./create-a-page.md). -``` - -**Result:** Let's see how to [Create a page](./create-a-page.md). - -## Images - -Regular Markdown images are supported. - -Add an image at `static/img/docusaurus.png` and display it in Markdown: - -```md -![Docusaurus logo](/img/docusaurus.png) -``` - -![Docusaurus logo](/img/docusaurus.png) - -## Code Blocks - -Markdown code blocks are supported with Syntax highlighting. - - ```jsx title="src/components/HelloDocusaurus.js" - function HelloDocusaurus() { - return ( -

Hello, Docusaurus!

- ) - } - ``` - -```jsx title="src/components/HelloDocusaurus.js" -function HelloDocusaurus() { - return

Hello, Docusaurus!

; -} -``` - -## Admonitions - -Docusaurus has a special syntax to create admonitions and callouts: - - :::tip My tip - - Use this awesome feature option - - ::: - - :::danger Take care - - This action is dangerous - - ::: - -:::tip My tip - -Use this awesome feature option - -::: - -:::danger Take care - -This action is dangerous - -::: - -## MDX and React Components - -[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: - -```jsx -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`) - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! -``` - -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`); - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! - -## CodeSnippetBlock - - - -## AddToMetaMaskButton - - diff --git a/cli/test/tutorial/docs/tutorial-extras/_category_.json b/cli/test/tutorial/docs/tutorial-extras/_category_.json deleted file mode 100644 index ca3f8e06408..00000000000 --- a/cli/test/tutorial/docs/tutorial-extras/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Tutorial - Extras", - "position": 3 -} diff --git a/cli/test/tutorial/docs/tutorial-extras/manage-docs-versions.md b/cli/test/tutorial/docs/tutorial-extras/manage-docs-versions.md deleted file mode 100644 index 6335b0ac94b..00000000000 --- a/cli/test/tutorial/docs/tutorial-extras/manage-docs-versions.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Manage Docs Versions - -Docusaurus can manage multiple versions of your docs. - -## Create a docs version - -Release a version 1.0 of your project: - -```bash -npm run docusaurus docs:version 1.0 -``` - -The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. - -Your docs now have 2 versions: - -- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs -- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** - -## Add a Version Dropdown - -To navigate seamlessly across versions, add a version dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -module.exports = { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'docsVersionDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The docs version dropdown appears in your navbar: - -![Docs Version Dropdown](/img/tutorial/docsVersionDropdown.png) - -## Update an existing version - -It is possible to edit versioned docs in their respective folder: - -- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` -- `docs/hello.md` updates `http://localhost:3000/docs/next/hello` diff --git a/cli/test/tutorial/docs/tutorial-extras/translate-your-site.md b/cli/test/tutorial/docs/tutorial-extras/translate-your-site.md deleted file mode 100644 index a25c089ed79..00000000000 --- a/cli/test/tutorial/docs/tutorial-extras/translate-your-site.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Translate your site - -Let's translate `docs/intro.md` to French. - -## Configure i18n - -Modify `docusaurus.config.js` to add support for the `fr` locale: - -```js title="docusaurus.config.js" -module.exports = { - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - }, -}; -``` - -## Translate a doc - -Copy the `docs/intro.md` file to the `i18n/fr` folder: - -```bash -mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ - -cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md -``` - -Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. - -## Start your localized site - -Start your site on the French locale: - -```bash -npm run start -- --locale fr -``` - -Your localized site is accessible at `http://localhost:3000/fr/` and the `Getting Started` page is translated. - -:::caution - -In development, you can only use one locale at a same time. - -::: - -## Add a Locale Dropdown - -To navigate seamlessly across languages, add a locale dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -module.exports = { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'localeDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The locale dropdown now appears in your navbar: - -![Locale Dropdown](/img/tutorial/localeDropdown.png) - -## Build your localized site - -Build your site for a specific locale: - -```bash -npm run build -- --locale fr -``` - -Or build your site to include all the locales at once: - -```bash -npm run build -``` diff --git a/cli/test/tutorial/docusaurus.config.js b/cli/test/tutorial/docusaurus.config.js deleted file mode 100644 index bc28f1b9911..00000000000 --- a/cli/test/tutorial/docusaurus.config.js +++ /dev/null @@ -1,26 +0,0 @@ -const path = require('path'); - -module.exports = { - plugins: [ - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Test tutorial', - description: 'This is a test tutorial.', - preview: '/img/docusaurus.png', - route: '/intro', - source: 'https://github.com/iota-community/iota-wiki-cli.git', - tags: ['text', 'video', 'c'], - }, - ], - [ - '@docusaurus/plugin-content-docs', - { - id: 'tutorial', - path: path.resolve(__dirname, './docs'), - sidebarPath: path.resolve(__dirname, './sidebars.js'), - }, - ], - ], - staticDirectories: [path.resolve(__dirname, './static')], -}; diff --git a/cli/test/tutorial/sidebars.js b/cli/test/tutorial/sidebars.js deleted file mode 100644 index e452eb19097..00000000000 --- a/cli/test/tutorial/sidebars.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], -}; diff --git a/cli/test/tutorial/static/.nojekyll b/cli/test/tutorial/static/.nojekyll deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cli/test/tutorial/static/img/docusaurus.png b/cli/test/tutorial/static/img/docusaurus.png deleted file mode 100644 index f458149e3c8..00000000000 Binary files a/cli/test/tutorial/static/img/docusaurus.png and /dev/null differ diff --git a/cli/test/tutorial/static/img/favicon.ico b/cli/test/tutorial/static/img/favicon.ico deleted file mode 100644 index c01d54bcd39..00000000000 Binary files a/cli/test/tutorial/static/img/favicon.ico and /dev/null differ diff --git a/cli/test/tutorial/static/img/logo.svg b/cli/test/tutorial/static/img/logo.svg deleted file mode 100644 index 9db6d0d066e..00000000000 --- a/cli/test/tutorial/static/img/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/cli/test/tutorial/static/img/tutorial/docsVersionDropdown.png b/cli/test/tutorial/static/img/tutorial/docsVersionDropdown.png deleted file mode 100644 index ff1cbe68893..00000000000 Binary files a/cli/test/tutorial/static/img/tutorial/docsVersionDropdown.png and /dev/null differ diff --git a/cli/test/tutorial/static/img/tutorial/localeDropdown.png b/cli/test/tutorial/static/img/tutorial/localeDropdown.png deleted file mode 100644 index d7163f96752..00000000000 Binary files a/cli/test/tutorial/static/img/tutorial/localeDropdown.png and /dev/null differ diff --git a/cli/test/tutorial/static/img/undraw_docusaurus_mountain.svg b/cli/test/tutorial/static/img/undraw_docusaurus_mountain.svg deleted file mode 100644 index af961c49a88..00000000000 --- a/cli/test/tutorial/static/img/undraw_docusaurus_mountain.svg +++ /dev/null @@ -1,171 +0,0 @@ - - Easy to Use - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cli/test/tutorial/static/img/undraw_docusaurus_react.svg b/cli/test/tutorial/static/img/undraw_docusaurus_react.svg deleted file mode 100644 index 94b5cf08f88..00000000000 --- a/cli/test/tutorial/static/img/undraw_docusaurus_react.svg +++ /dev/null @@ -1,170 +0,0 @@ - - Powered by React - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cli/test/tutorial/static/img/undraw_docusaurus_tree.svg b/cli/test/tutorial/static/img/undraw_docusaurus_tree.svg deleted file mode 100644 index d9161d33920..00000000000 --- a/cli/test/tutorial/static/img/undraw_docusaurus_tree.svg +++ /dev/null @@ -1,40 +0,0 @@ - - Focus on What Matters - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/articleRedirects.js b/config/articleRedirects.js similarity index 100% rename from articleRedirects.js rename to config/articleRedirects.js diff --git a/contentPlugins.js b/config/contentPlugins.js similarity index 61% rename from contentPlugins.js rename to config/contentPlugins.js index 0c8e12d222c..4576c08f676 100644 --- a/contentPlugins.js +++ b/config/contentPlugins.js @@ -1,4 +1,4 @@ -const { generatePluginConfig } = require('./src/utils/pluginConfigGenerators'); +const { generatePluginConfig } = require('../src/utils/pluginConfigGenerators'); const { buildPluginsConfig, maintainPluginsConfig, @@ -13,24 +13,27 @@ module.exports = async () => { { id: 'build', globalSidebars: ['build'], - path: path.resolve(__dirname, 'docs/build/getting-started'), + path: path.resolve(__dirname, '../docs/build/getting-started'), sidebarPath: path.resolve( __dirname, - 'docs/build/getting-started/sidebars.ts', + '../docs/build/getting-started/sidebars.ts', ), routeBasePath: 'build', }, - ...generatePluginConfig(buildPluginsConfig, __dirname + '/docs/build/'), + ...generatePluginConfig( + buildPluginsConfig, + path.resolve(__dirname, '../docs/build/'), + ), { id: 'introduction-docs-stardust', path: path.resolve( __dirname, - 'docs/build/introduction-docs/stardust/docs', + '../docs/build/introduction-docs/stardust/docs', ), routeBasePath: 'introduction', sidebarPath: path.resolve( __dirname, - 'docs/build/introduction-docs/stardust/sidebars.js', + '../docs/build/introduction-docs/stardust/sidebars.js', ), versions: { current: { @@ -45,15 +48,15 @@ module.exports = async () => { const maintainPlugins = [ ...generatePluginConfig( maintainPluginsConfig, - __dirname + '/docs/maintain/', + path.resolve(__dirname, '../docs/maintain/'), ), { id: 'maintain', globalSidebars: ['maintain'], - path: path.resolve(__dirname, 'docs/maintain/getting-started'), + path: path.resolve(__dirname, '../docs/maintain/getting-started'), sidebarPath: path.resolve( __dirname, - 'docs/maintain/getting-started/sidebars.ts', + '../docs/maintain/getting-started/sidebars.ts', ), routeBasePath: 'maintain', }, @@ -62,8 +65,8 @@ module.exports = async () => { const getStartedPlugins = [ { id: 'get-started', - path: path.resolve(__dirname, 'docs/get-started'), - sidebarPath: path.resolve(__dirname, 'docs/get-started/sidebars.ts'), + path: path.resolve(__dirname, '../docs/get-started/'), + sidebarPath: path.resolve(__dirname, '../docs/get-started/sidebars.ts'), routeBasePath: 'get-started', }, ]; @@ -71,8 +74,8 @@ module.exports = async () => { const learnPlugins = [ { id: 'learn', - path: path.resolve(__dirname, 'docs/learn'), - sidebarPath: path.resolve(__dirname, 'docs/learn/sidebars.ts'), + path: path.resolve(__dirname, '../docs/learn/'), + sidebarPath: path.resolve(__dirname, '../docs/learn/sidebars.ts'), routeBasePath: 'learn', }, ]; @@ -82,8 +85,8 @@ module.exports = async () => { ...getStartedPlugins, { id: 'community', - path: path.resolve(__dirname, 'docs/community'), - sidebarPath: path.resolve(__dirname, 'docs/community/sidebars.ts'), + path: path.resolve(__dirname, '../docs/community/'), + sidebarPath: path.resolve(__dirname, '../docs/community/sidebars.ts'), routeBasePath: 'community', }, ...buildPlugins, diff --git a/common/jargon.js b/config/jargon.js similarity index 99% rename from common/jargon.js rename to config/jargon.js index 41700c6ff8e..0144184b203 100644 --- a/common/jargon.js +++ b/config/jargon.js @@ -50,6 +50,8 @@ module.exports = { 'The process of receiving blocks, either created locally by a node or received from a neighbor.', 'block signature': 'Digital signatures attached to blocks to ensure their authenticity.', + 'block time': + 'Block Time refers to the average amount of time it takes for a new block to be added to a blockchain. This metric is critical as it determines the network speed and efficiency in processing transactions and maintaining consensus.', 'block wrapper': 'The block wrapper is additional data around the typical blocks giving important metadata, including the version, time, and block issuer. This metadata allows nodes to follow the right version of the Tangle, to verify the timestamp of blocks, and to identify the creator of each block.', 'blockchain bottleneck': diff --git a/svgo.config.js b/config/svgo.config.js similarity index 100% rename from svgo.config.js rename to config/svgo.config.js diff --git a/switcherConfig.js b/config/switcherConfig.js similarity index 92% rename from switcherConfig.js rename to config/switcherConfig.js index 1cb8de7006d..4c6578a8026 100644 --- a/switcherConfig.js +++ b/config/switcherConfig.js @@ -1,13 +1,13 @@ // @ts-check const { generateSwitcherConfig, -} = require('./src/utils/pluginConfigGenerators'); +} = require('../src/utils/pluginConfigGenerators'); const { buildPluginsConfig, maintainPluginsConfig, } = require('./versionedConfig'); -/** @type {import('./src/common/components/Switcher').Config} */ +/** @type {import('../src/components/Switcher').Config} */ const config = { docs: [ ...generateSwitcherConfig(buildPluginsConfig), diff --git a/tutorials/tags.json b/config/tags.json similarity index 100% rename from tutorials/tags.json rename to config/tags.json diff --git a/config/tutorials.js b/config/tutorials.js new file mode 100644 index 00000000000..8bd51c17773 --- /dev/null +++ b/config/tutorials.js @@ -0,0 +1,252 @@ +const pluginTutorial = require('../src/plugins/tutorial'); + +module.exports = [ + [ + '@docusaurus/plugin-content-pages', + { + id: 'single-page-tutorials', + path: './docs/tutorials', + routeBasePath: '/tutorials', + }, + ], + [ + pluginTutorial, + { + title: 'Run a Wasp Node', + description: 'In this tutorial you will learn how to run a wasp node.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg', + route: '/wasp/how-tos/running-a-node', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Run a Wasp Chain', + description: 'In this tutorial you will learn how to run a wasp chain.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg', + route: '/wasp/how-tos/setting-up-a-chain', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Deploy a WASM Smart Contract', + description: + 'In this tutorial you will learn how to deploy a wasm smart contract.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg', + route: '/wasp/how-tos/setting-up-a-chain#deploying-a-wasm-contract', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Deploy a Solidity Smart Contract Using Remix + Metamask', + description: + 'In this tutorial you will learn how to deploy a solidity smart contract on EVM using remix and metamask.', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg', + route: '/isc/getting-started/tools#remix', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: 'Generate a WASM Smart Contract Using the Schema Tool', + description: + 'In this tutorial you will learn how to use schema tool to generate smart contract template code on rust and golang', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png', + route: '/isc/schema/how-tos/usage', + tags: ['text', 'video'], + }, + ], + [ + pluginTutorial, + { + title: + 'Generate a WASM Smart Contract Using the Schema Tool in Typescript', + description: + 'In this tutorial you will learn how to use schema tool to generate smart contract template code on typescript', + preview: '/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png', + route: 'https://www.youtube.com/watch?v=P5HMgmY3DMM', + tags: ['video'], + }, + ], + [ + pluginTutorial, + { + title: 'Interact with IOTA Node Extension (INX)', + description: + 'In this tutorial you will learn how to interact with the IOTA Node Extension (INX) interface based on gRPC.', + preview: '/img/tutorials/hornet-inx-interaction.png', + route: 'tutorials/hornet-inx-interaction', + tags: ['text', 'getting-started', 'shimmer', 'js'], + }, + ], + [ + pluginTutorial, + { + title: 'Tokenless Data Notarization', + description: + 'Proove that a block was part of the past Tangle, even if this part of the Tangle was already pruned from network nodes.', + preview: '/img/tutorials/proof-inclusion-of-a-block.png', + route: 'tutorials/proof-inclusion-of-a-block', + tags: ['text', 'getting-started', 'js', 'client', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'Set Up a Testnet Address and Receive Funds From the Faucet', + description: + 'In this tutorial you will learn how to create a seed and address with wallet.rs and receive testnet tokens from the faucet.', + preview: '/img/tutorials/wallet-setup.png', + route: 'tutorials/wallet-setup', + tags: ['text', 'getting-started', 'node_js', 'wallet', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'How to Set Up iota.js for Development', + description: + 'In this tutorial you will learn how to create a new project, generate a new address and receive x funds from the faucet.', + preview: '/img/tutorials/setup_iota-js_for_development.png', + route: 'tutorials/setup_iota-js_for_development', + tags: ['text', 'getting-started', 'client', 'shimmer', 'js'], + }, + ], + [ + pluginTutorial, + { + title: + 'Connect to Shimmer EVM Testnet and Deploy a Solidity Smart Contract', + description: + 'In this tutorial, we will connect to Shimmer EVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity.', + preview: '/img/tutorials/connect-shimmerevm-testnet-and-deploy.png', + route: 'tutorials/shimmerevm-testnet-setup', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'getting-started', + 'wasp', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: + 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Testnet Using Hardhat', + description: + 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', + preview: '/img/tutorials/shimmerevm-hardhat.jpg', + route: 'tutorials/shimmerevm-testnet-hardhat', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'shimmerevm', + 'hardhat', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: 'Create a Simple Voting dApp on ShimmerEVM', + description: + 'This tutorial will guide you as you write and deploy a voting dApp on ShimmerEVM. You can vote on a few options and view the results; all data will be stored on-chain.', + preview: '/img/tutorials/shimmerevm-dapp-voting.jpg', + route: 'tutorials/shimmerevm-dapp-voting', + tags: ['text', 'shimmer', 'solidity', 'iscp'], + }, + ], + [ + pluginTutorial, + { + title: 'Set Up WASP locally Using Docker', + description: + 'In this tutorial you will learn how to set up WASP and Hornet locally for Development setup.', + preview: '/img/tutorials/wasp-setup-shimmer.png', + route: 'https://youtu.be/ltem9Bh_4hA', + tags: ['text', 'shimmer', 'video', 'wasp', 'iscp'], + }, + ], + [ + pluginTutorial, + { + title: 'Create an NFT with the IOTA SDK and IPFS in NodeJs', + description: + 'In this tutorial you will learn how to create a NFT on the Shimmer network with iota-sdk and IPFS.', + preview: '/img/tutorials/create-nft-with-wallet-lib.png', + route: 'tutorials/create-nft-with-iota-sdk', + tags: [ + 'text', + 'getting-started', + 'node_js', + 'iota-sdk', + 'ipfs', + 'shimmer', + 'sdk', + ], + }, + ], + [ + pluginTutorial, + { + title: 'Send Shimmer Tokens with IOTA SDK in NodeJs', + description: + 'In this tutorial you will learn how to send Shimmer Tokens with IOTA SDK in NodeJs.', + preview: '/img/tutorials/send-shimmer-tokens-with-iota-sdk.png', + route: 'tutorials/send-shimmer-tokens-with-iota-sdk', + tags: ['text', 'iota-sdk', 'sdk', 'getting-started', 'rust', 'shimmer'], + }, + ], + [ + pluginTutorial, + { + title: 'Connect to Shimmer EVM and Deploy a Solidity Smart Contract', + description: + 'In this tutorial, we will connect to Shimmer EVM, connect Metamask to it, get funded and deploy a smart contract in Solidity.', + preview: '/img/tutorials/connect-shimmerevm-and-deploy.png', + route: 'tutorials/shimmerevm-setup', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'getting-started', + 'wasp', + 'iscp', + 'video', + ], + }, + ], + [ + pluginTutorial, + { + title: + 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Using Hardhat', + description: + 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', + preview: '/img/tutorials/shimmerevm-hardhat.jpg', + route: 'tutorials/shimmerevm-hardhat', + tags: [ + 'text', + 'shimmer', + 'solidity', + 'shimmerevm', + 'hardhat', + 'iscp', + 'video', + ], + }, + ], +]; diff --git a/versionedConfig.js b/config/versionedConfig.js similarity index 89% rename from versionedConfig.js rename to config/versionedConfig.js index ad3a1e5fe4d..dce6937538b 100644 --- a/versionedConfig.js +++ b/config/versionedConfig.js @@ -27,8 +27,13 @@ exports.buildPluginsConfig = [ subsection: 'build-layer-2', versions: [ { - label: 'v1.0.0-rc.6', - badges: ['Shimmer'], + label: 'v1.1', + badges: ['IOTA'], + }, + { + label: 'v1.3', + badges: ['Shimmer', 'Testnet'], + banner: 'staging', }, ], }, @@ -40,6 +45,10 @@ exports.buildPluginsConfig = [ icon: 'Identity', subsection: 'build-layer-1', versions: [ + { + label: '1.3', + badges: ['IOTA', 'Shimmer'], + }, { label: '1.2', badges: ['IOTA', 'Shimmer'], @@ -145,8 +154,13 @@ exports.maintainPluginsConfig = [ subsection: 'maintain-layer-2', versions: [ { - label: 'v1.0.0-rc.6', - badges: ['Shimmer'], + label: 'v1.1', + badges: ['IOTA'], + }, + { + label: 'v1.3', + badges: ['Shimmer', 'Testnet'], + banner: 'staging', }, ], }, diff --git a/docs/build/_partials/_metamask_buttons.mdx b/docs/build/_partials/_metamask_buttons.mdx index 52fec8cf14f..f4f28683502 100644 --- a/docs/build/_partials/_metamask_buttons.mdx +++ b/docs/build/_partials/_metamask_buttons.mdx @@ -3,7 +3,10 @@ import { Networks } from '@theme/constant'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; - + + + + diff --git a/docs/build/_partials/_oracles_contract_data.mdx b/docs/build/_partials/_oracles_contract_data.mdx new file mode 100644 index 00000000000..94fa12006b7 --- /dev/null +++ b/docs/build/_partials/_oracles_contract_data.mdx @@ -0,0 +1,35 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +| Contract Type | Contract Address | +|:----------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| Pyth contract | [https://explorer.evm.iota.org/address/0x8D254a21b3C86D32F7179855531CE99164721933](https://explorer.evm.iota.org/address/0x8D254a21b3C86D32F7179855531CE99164721933) | +| Supra Pull Contract | [https://explorer.evm.iota.org/address/0x2FA6DbFe4291136Cf272E1A3294362b6651e8517](https://explorer.evm.iota.org/address/0x2FA6DbFe4291136Cf272E1A3294362b6651e8517) | +| Supra Storage Contract | [https://explorer.evm.iota.org/address/0xD02cc7a670047b6b012556A88e275c685d25e0c9](https://explorer.evm.iota.org/address/0xD02cc7a670047b6b012556A88e275c685d25e0c9) | +| Supra Push Contract | [https://explorer.evm.iota.org/address/0xD02cc7a670047b6b012556A88e275c685d25e0c9](https://explorer.evm.iota.org/address/0xD02cc7a670047b6b012556A88e275c685d25e0c9) | + + + + +| Contract Type | Contract Address | +|:----------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| Pyth contract | [https://explorer.evm.shimmer.network/address/0x290f23E4a034Db5237edCb5aA2D94Acb4DD19fD2](https://explorer.evm.shimmer.network/address/0x290f23E4a034Db5237edCb5aA2D94Acb4DD19fD2) | +| Supra Pull Contract | [https://explorer.evm.shimmer.network/address/0xe41444462709484272F54371F3f53bBF900Ec49E](https://explorer.evm.shimmer.network/address/0xe41444462709484272F54371F3f53bBF900Ec49E) | +| Supra Storage Contract | [https://explorer.evm.shimmer.network/address/0x3E5E89d14576cE9f20a8347aA682517fe65B4ACB](https://explorer.evm.shimmer.network/address/0x3E5E89d14576cE9f20a8347aA682517fe65B4ACB) | +| Supra Push Contract | [https://explorer.evm.shimmer.network/address/0x3df842b27c997cEc63160E79CB4398c82645A1c3](https://explorer.evm.shimmer.network/address/0x3df842b27c997cEc63160E79CB4398c82645A1c3) | + + + + +:::tip Oracle Documentation + +You can find detailed documentation on the Oracles in their official documentation: + +* [Pyth Oracle Docs](https://docs.pyth.network/price-feeds/contract-addresses/evm) +* [Supra Pull Docs](https://gb-docs.supraoracles.com/docs/data-feeds/pull-model/networks) +* [Supra Push Docs](https://gb-docs.supraoracles.com/docs/data-feeds/decentralized/networks) + +::: diff --git a/docs/build/getting-started/blastAPI.md b/docs/build/getting-started/blastAPI.md new file mode 100644 index 00000000000..2bd2e188ac9 --- /dev/null +++ b/docs/build/getting-started/blastAPI.md @@ -0,0 +1,42 @@ +--- +description: Blast API is a decentralized platform providing scalable node infrastructure for accessing blockchain data, supporting multiple networks including IOTA EVM. +keywords: + - IOTA EVM + - blockchain API + - decentralized + - node infrastructure + - tools + - Blast api + - archive node +image: /img/logo/WASP_logo_dark.png +--- + +# Blast API + +[Blast API](https://blastapi.io/) is a decentralized platform that provides reliable and scalable node infrastructure +for accessing blockchain data. It supports multiple blockchain networks, offering seamless integration and +high-performance API endpoints for cross-chain decentralized applications (dApps). + +## Enhanced Performance and Reliability + +Blast API uses a decentralized network of third-party node providers, that ensure high availability and fast response +times. This architecture provides resilient infrastructure services crucial for dApps requiring real-time data access. + +## Multi-Blockchain Support + +Besides IOTA EVM, Blast API supports a wide range of blockchain networks, allowing access to multiple blockchains +through a single unified platform, therefore simplifying the development process and expanding the potential use cases +for dApps. + +## Archival Nodes + +Blast API includes archival nodes, which store all historical transaction data from the blockchain’s +genesis block to the present. This allows developers to query and retrieve past information, which is essential for +applications needing access to comprehensive blockchain histories. + + +:::tip Blast API Endpoints + +You can find a full list of Blast API endpoints in the [Networks & Endpoints section](networks-endpoints.mdx). + +::: diff --git a/docs/build/getting-started/multicall.md b/docs/build/getting-started/multicall.md new file mode 100644 index 00000000000..820ad311581 --- /dev/null +++ b/docs/build/getting-started/multicall.md @@ -0,0 +1,194 @@ +--- +description: 'Multicall3 allows you to bundle multiple calls to various contracts, for both reading and writing data, into a single transaction.' +image: /img/logo/WASP_logo_dark.png +--- + +# Multicall3 +## Powering Efficient Batch Transactions on L2 Networks + +Multicall3 is a smart contract on the Ethereum Virtual Machine (EVM) that streamlines transactions. It allows you to bundle multiple calls to various contracts, for both reading and writing data, into a single transaction. + +This can be particularly useful when working with decentralized applications that require multiple contract interactions or when batching multiple calls to save on gas costs. To use the Multicall3 contract on IOTA EVM, the Multicall3 contract is deployed at this address: [0xcA11bde05977b3631167028862bE2a173976CA11](https://explorer.evm.iota.org/address/0xcA11bde05977b3631167028862bE2a173976CA11?tab=write_contract). + +This contract offers significant advantages for optimizing transaction processing on L2 networks, also known as Layer 2 scaling solutions. Here's how Multicall3 enhances efficiency: + +- **Reduced Gas Costs:** By grouping calls together, Multicall3 minimizes the total gas fees associated with interacting with the blockchain. Gas refers to the computational effort required to execute a transaction on the network. + +- **Guaranteed Data Consistency:** Multicall3 fetches data from a single block on the blockchain, ensuring that all the information you receive reflects a consistent state. This eliminates discrepancies that might arise from fetching data across separate transactions. + +- **Faster Execution Speeds:** You no longer need to wait for individual transactions to be confirmed one by one. Multicall3 processes everything efficiently in a single transaction, significantly speeding up the overall process. + +- **Simplified Workflows:** Multicall3 removes the complexity of worrying about the order in which transactions are processed, eliminating potential issues caused by race conditions. Race conditions occur when multiple transactions compete for resources, and the outcome can depend on the order they are executed. + +- **All-or-Nothing Execution:** Multicall3 ensures data integrity by functioning on an all-or-nothing basis. This means that either all the calls within the Multicall3 transaction succeed, or none of them do. This prevents partial execution and maintains data consistency. + +:::tip + +You can find the ABI of the contract in the [Multicall3 website](https://www.multicall3.com/abi). + +::: + + +## Contract Information + +### Function: aggregate + +#### Description: + This function aggregates the results of multiple function calls made to different contracts within a single transaction. + +```solidity +function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData); +``` + + +|Parameter Name | Description| +|-----------|--------------------------------------------------------------------- +| calls (Call[] calldata) | An array of Call structs. Each Call struct contains the target contract address (address) and the encoded function call data (bytes).| + +#### Return Values: + - blockNumber (uint256): The block number where the calls were executed. + - returnData (bytes[] memory): An array of bytes containing the return data from each call. + +### Function: tryAggregate + +#### Description: + This function performs a similar function to `aggregate` but allows individual calls to fail without halting the entire execution. + + +```solidity +function tryAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (Result[] memory returnData); +``` + +| Parameter Name | Description | +|----------------|-----------------------------------------------------------------------------| +| requireSuccess (bool) | A boolean flag indicating whether all calls must succeed (true) or if failures are allowed (false). | +| calls (Call[] calldata) | An array of Call structs. Each Call struct contains the target contract address (address) and the encoded function call data (bytes). | + + +#### Return Values: +returnData (Result[] memory): An array of Result structs. Each Result struct contains a bool indicating success (success) and the return data for the corresponding call (bytes returnData). + +### Function: tryBlockAndAggregate + +#### Description: + This function combines features of `tryAggregate` and retrieves additional block information. + + +```solidity +function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) + public + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +``` + +| Parameter Name | Description | +|----------------|-----------------------------------------------------------------------------| +| requireSuccess (bool) | A boolean flag indicating whether all calls must succeed (true) or if failures are allowed (false). | +| calls (Call[] calldata) | An array of Call structs. Each Call struct contains the target contract address (address) and the encoded function call data (bytes). | + +#### Return Values: + - blockNumber (uint256): The block number where the calls were executed. + - blockHash (bytes32): The hash of the block where the calls were executed. + - returnData (Result[] memory): An array of Result structs, as defined in tryAggregate. + + +### Function: blockAndAggregate + +#### Description: +This function is a simplified version of `tryBlockAndAggregate` that always requires all calls to succeed. + +```solidity +function blockAndAggregate(Call[] calldata calls) + public + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +``` + +|Parameter Name | Description| +|-----------|--------------------------------------------------------------------- +| calls (Call[] calldata) | An array of Call structs, as defined in aggregate.| + +#### Return Values: + - blockNumber (uint256): The block number where the calls were executed. + - blockHash (bytes32): The hash of the block where the calls were executed. + - returnData (Result[] memory): An array of Result structs, as defined in tryAggregate. + + +### Function: aggregate3 +#### Description: +This function aggregates calls similar to `aggregate` but allows specifying whether failures are allowed for each call individually. + +```solidity +function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData); +``` + +|Parameter Name | Description| +|-----------|--------------------------------------------------------------------- +| calls (Call[] calldata) | An array of Call3 structs. Each Call3 struct includes the target contract address (address), a flag indicating if failure is allowed (bool allowFailure), and the encoded function call data (bytes callData).| + +#### Return Values: + - returnData (Result[] memory): An array of Result structs, as defined in `tryAggregate`. + + +### Function: aggregate3Value +#### Description: +This function aggregates calls with a specified value for each call, allowing sending funds along with the call data. It ensures the total sent value matches the sum of individual call values. + + +```solidity +function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData); +``` + +|Parameter Name | Description| +|-----------|--------------------------------------------------------------------- +| calls (Call[] calldata) | An array of Call3Value structs. Each Call3Value struct includes the target contract address (address), a flag indicating if failure is allowed (bool allowFailure), the value to send along with the call (uint256 value), and the encoded function call data (bytes callData). + +#### Return Values: + - returnData (Result[] memory): An array of Result structs, as defined in `tryAggregate`. + + + + ## Additional Functions +The contract also includes several view functions that retrieve blockchain data without modifying the state: + +- `getBlockHash(uint256 blockNumber)`: Returns the block hash for a given block number. +- `getBlockNumber()`: Returns the current block number. +- `getCurrentBlockCoinbase()`: Returns the address of the block miner (coinbase). +- `getCurrentBlockDifficulty()`: Returns the difficulty of the current block. +- `getCurrentBlockGasLimit()`: Returns the gas limit of the current block. +- `getCurrentBlockTimestamp()`: Returns + +## Structs + +- Call +```solidity +struct Call { + address target; + bytes callData; +} +``` +- Call3 +```solidity +struct Call3 { + address target; + bool allowFailure; + bytes callData; +} + +``` +- Call3 Value +```solidity +struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; +} +``` +- Result +```solidity +struct Result { + bool success; + bytes returnData; +} +``` \ No newline at end of file diff --git a/docs/build/getting-started/networks-endpoints.mdx b/docs/build/getting-started/networks-endpoints.mdx index 714c125449a..bb5632d2e93 100644 --- a/docs/build/getting-started/networks-endpoints.mdx +++ b/docs/build/getting-started/networks-endpoints.mdx @@ -16,7 +16,6 @@ tags: import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; import { Networks } from '@theme/constant'; import NetworkInfo from '@theme/NetworkInfo'; -import { ChainId } from '@theme/ChainId'; # Networks & Endpoints @@ -41,6 +40,18 @@ This network runs under a [Coordinator PoA scheme](/learn/protocols/coordinator/ +### IOTA EVM + +[IOTA EVM](https://explorer.evm.iota.org) is the L2 EVM running on top of the IOTA network. + + + + + +#### Additional Info + + + ## IOTA Testnet [The IOTA Testnet](https://explorer.iota.org/iota-testnet) acts as a test bed for builders without any real world value. @@ -64,6 +75,7 @@ This network is subject to occasional resets (no data retention) which are usual + #### Additional Info diff --git a/docs/build/getting-started/oracles.md b/docs/build/getting-started/oracles.md index 2ababe9d917..6aeae82bb1c 100644 --- a/docs/build/getting-started/oracles.md +++ b/docs/build/getting-started/oracles.md @@ -4,10 +4,15 @@ image: /img/logo/WASP_logo_dark.png tags: - Blockchain Oracles - Smart Contracts +- IOTA EVM - Shimmer EVM - Pyth Network - Supra Oracles --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import OraclesContractData from '../_partials/_oracles_contract_data.mdx' + # Introduction to Oracles in Blockchain @@ -36,52 +41,56 @@ multiple data points to validate the information's accuracy. This process ensure contracts is relevant and timely, maintaining the integrity and deterministic nature of the blockchain operations. -## Oracles on Shimmer EVM +## Oracle Providers in IOTA Ecosystem -### Supra +### Pyth -Supra Oracles validate and report prices derived from up to 21 data sources with Byzantine Fault Tolerant algorithms -for a wide array of assets and commodities using its own Distributed Oracle Agreement (DORA) to provide data for crypto -prices, forex, equities, and even Web3 data from other blockchains. Its feed gets updated from a minimum of 3 to 8 sources; if a data pair fails to meet this criterion, it gets deprecated to ensure data reliability. +The Pyth Network delivers real-time financial market data across multiple blockchains and can be used in off-chain applications. +Pyth gets contributions from over 90 publishers, including several exchanges. It offers comprehensive and accurate price +feeds for asset classes such as US equities, commodities, and cryptocurrencies. Its price feeds get updates +multiple times per second, ensuring they are current and reliable. :::tip -You can learn more about Supra Oracles in their [official documentation](https://supraoracles.com/docs/overview). +You can learn more about Pyth Oracles in their [official documentation](https://docs.pyth.network/documentation). ::: -### Pyth +### Supra -The Pyth Network delivers real-time financial market data across multiple blockchains and can be used in off-chain applications. -Pyth gets contributions from over 90 publishers, including several exchanges. It offers comprehensive and accurate price -feeds for asset classes such as US equities, commodities, and cryptocurrencies. Its price feeds get updates -multiple times per second, ensuring they are current and reliable. +Supra Oracles validate and report prices derived from up to 21 data sources with Byzantine Fault Tolerant algorithms +for a wide array of assets and commodities using its own Distributed Oracle Agreement (DORA) to provide data for crypto +prices, forex, equities, and even Web3 data from other blockchains. Its feed gets updated from a minimum of 3 to 8 sources; if a data pair fails to meet this criterion, it gets deprecated to ensure data reliability. :::tip -You can learn more about Pyth Oracles in their [official documentation](https://docs.pyth.network/documentation). +You can learn more about Supra Oracles in their [official documentation](https://supraoracles.com/docs/overview). ::: + + #### Example Code -You can use the following example code to get data from Pyth Oracles in Shimmer EVM: + + +You can use the following example code to get data from Pyth Oracles in IOTA EVM: ```typescript import {ethers} from "ethers"; import fetch from "node-fetch"; // Provider -const providerURL = "https://json-rpc.evm.shimmer.network" +const providerURL = "https://json-rpc.evm.iota.network" const provider = new ethers.JsonRpcProvider(providerURL); -// Pyth Oracle contract on ShimmerEVM Mainnet -const contractAddress = '0xA2aa501b19aff244D90cc15a4Cf739D2725B5729'; +// Pyth Oracle contract on IOTA EVM Mainnet +const contractAddress = '0x8D254a21b3C86D32F7179855531CE99164721933'; // Add Price Feed Ids obtained from https://pyth.network/developers/price-feed-ids#pyth-evm-stable const priceFeedIds = [ - //SMR/USD + //IOTA/USD '0xaf5b9ac426ae79591fde6816bc3f043b5e06d5e442f52112f76249320df22449', //BTC/USD '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43' @@ -120,4 +129,8 @@ async function main() { } } -main(); \ No newline at end of file +main(); +``` + + + \ No newline at end of file diff --git a/docs/build/getting-started/safe.md b/docs/build/getting-started/safe.md new file mode 100644 index 00000000000..4cdc7cf6928 --- /dev/null +++ b/docs/build/getting-started/safe.md @@ -0,0 +1,78 @@ +--- +description: 'Multisig wallet refers to having multiple private keys for a single web3 wallet.' +image: /img/logo/WASP_logo_dark.png +--- + +# MultiSig Wallet + +:::note TL;DR; + +[Safe Wallet](https://safe.iotaledger.net/welcome) is a multiSig wallet. The term “ + multisig” is short for "multisignature". + +::: + +The security of cryptocurrency demands greater attention as digital assets gain traction. Individuals and organizations need robust strategies to safeguard their funds. Multisignature (multisig) wallets are emerging as a powerful cybersecurity tool in crypto. + +Decentralized digital assets require a different approach to security than traditional finance. Thankfully, innovative technologies like multisig wallets provide an extra layer of protection, allowing you to trade cryptocurrencies on chains like [Shimmer EVM](https://explorer.evm.shimmer.network/) or [IOTA EVM](https://explorer.evm.iota.org/). + +![IOTA Sandbox](/img/get-started/safe/safe.png) + +## Why Are Multisig Wallets More Secure? + +Traditional crypto wallets rely on a single signature for transactions, making them vulnerable if that key is compromised. Multisig wallets offer superior security by requiring multiple approvals before funds can be moved. This added layer of verification significantly reduces the risk of unauthorized transactions, even if a hacker gains access to one of your keys. + +## Use Cases for Multisig Wallet + +### Shared Asset Security + +#### Joint Ownership + +Securely manage crypto held jointly by couples, business partners, or organizations. Requires approval from all parties for transactions, preventing unauthorized spending. + +#### Company Funds + + For businesses with substantial crypto holdings, enforce multi-approval workflows for withdrawals, minimizing internal theft risk. + +### Enhanced Threat Protection + +#### Lost/Compromised Keys + + Mitigate the impact of lost or compromised keys. Remaining keys can still safeguard funds, unlike single-signature wallets. + +#### Hacking Defense + + Add a significant hurdle for attackers. Even with access to one key, they cannot steal funds without additional signatures. + +#### Custodial Account Control + + Maintain control over crypto held in exchanges or IRA providers. Multisig wallets ensure withdrawals require approval from both the - user and the custodian, preventing unauthorized access. + +### Important Considerations + +#### Technical Complexity + + Setting up and using multisig wallets requires more technical expertise compared to traditional wallets. + +#### Signatory Balance + +Finding the optimal balance between security (more signatories) and practicality (fewer signatories) is crucial. + +#### Individual Suitability + + For most individual users with smaller crypto holdings, a standard single-signature wallet might be sufficient. + + +:::tip + +Learn more about safe accounts in the [Safe documentation](https://help.safe.global/en/articles/40835-what-safe-setup-should-i-use). + +::: + +## IOTA has its own dedicated MultiSig wallet - [safe(Wallet)](https://safe.iotaledger.net/welcome) + +:::info Set Up a Safe Account + +You can find instructions on setting up a safe account in the [Safe documentation](https://help.safe.global/en/articles/40868-creating-a-safe-on-a-web-browser). + +::: \ No newline at end of file diff --git a/docs/build/getting-started/sidebars.ts b/docs/build/getting-started/sidebars.ts index 5c77fcf837d..d029cf66407 100644 --- a/docs/build/getting-started/sidebars.ts +++ b/docs/build/getting-started/sidebars.ts @@ -16,54 +16,157 @@ module.exports = { }, items: [ { - type: 'link', - label: 'IOTA Sandbox', - href: '/iota-sandbox/welcome', - }, - { - type: 'link', - label: 'CLI Wallet', - href: '/cli-wallet/welcome', - }, - { - type: 'link', - label: 'WASP CLI', - href: '/wasp/how-tos/wasp-cli', - }, - { - label: 'Schema Tool', - type: 'link', - href: '/isc/schema/introduction', + type: 'category', + label: 'EVM Tools', + collapsed: false, + link: { + type: 'generated-index', + title: 'EVM Tools', + slug: '/tools/evm', + }, + items: [ + { + type: 'category', + label: 'IOTA EVM', + collapsed: false, + link: { + type: 'generated-index', + title: 'IOTA EVM Tools', + slug: '/tools/evm/iota', + }, + items: [ + { + label: 'Explorer', + type: 'link', + href: 'https://explorer.evm.iota.org', + }, + { + label: 'Toolkit', + type: 'link', + href: 'https://evm-toolkit.evm.iotaledger.net', + }, + ], + }, + { + type: 'category', + label: 'IOTA EVM Testnet', + collapsed: false, + link: { + type: 'generated-index', + title: 'IOTA Testnet EVM Tools', + slug: '/tools/evm/iota-testnet', + }, + items: [ + { + label: 'Explorer', + type: 'link', + href: 'https://explorer.evm.testnet.iota.org', + }, + { + label: 'Toolkit & Faucet', + type: 'link', + href: 'https://evm-toolkit.evm.testnet.iotaledger.net', + }, + ], + }, + { + label: 'Blast API', + type: 'doc', + id: 'blastAPI', + }, + { + label: 'Oracles', + type: 'doc', + id: 'oracles', + }, + { + label: 'Subgraphs', + type: 'doc', + id: 'subgraphs', + }, + { + label: 'IOTA Safe Wallet', + type: 'doc', + id: 'safe', + }, + { + label: 'Multicall3', + type: 'doc', + id: 'multicall', + }, + { + type: 'category', + label: 'ShimmerEVM', + collapsed: true, + link: { + type: 'generated-index', + title: 'ShimmerEVM Tools', + slug: '/tools/evm/shimmer', + }, + items: [ + { + label: 'Explorer', + type: 'link', + href: 'https://explorer.evm.shimmer.network', + }, + { + label: 'Toolkit', + type: 'link', + href: 'https://evm-toolkit.evm.shimmer.network', + }, + ], + }, + { + type: 'category', + label: 'ShimmerEVM Testnet', + collapsed: true, + link: { + type: 'generated-index', + title: 'ShimmerEVM Testnet Tools', + slug: '/tools/evm/shimmer-testnet', + }, + items: [ + { + label: 'Explorer', + type: 'link', + href: 'https://explorer.evm.testnet.shimmer.network', + }, + { + label: 'Toolkit & Faucet', + type: 'link', + href: 'https://evm-toolkit.evm.testnet.shimmer.network/', + }, + ], + }, + { + type: 'link', + label: 'WASP CLI', + description: + 'Wasp CLI is a command line tool for interacting with the Wasp node.', + href: '/wasp/how-tos/wasp-cli', + }, + ], }, + { label: 'Explorer', type: 'link', href: 'https://explorer.iota.org', }, { - label: 'Shimmer EVM Explorer', - type: 'link', - href: 'https://explorer.evm.shimmer.network/', - }, - { - label: 'Shimmer EVM Toolkit', + label: 'IOTA Testnet Faucet', type: 'link', - href: 'https://evm-toolkit.evm.shimmer.network/', + href: 'https://faucet.testnet.iotaledger.net', }, { - label: 'Shimmer EVM Testnet Toolkit & Faucet', type: 'link', - href: 'https://evm-toolkit.evm.testnet.shimmer.network/', - }, - { - label: 'Oracles for Shimmer EVM', - type: 'doc', - id: 'oracles', + label: 'CLI Wallet', + href: '/cli-wallet/welcome', }, { - label: 'Testnet Faucet', type: 'link', - href: 'https://faucet.testnet.shimmer.network', + label: 'IOTA Sandbox', + href: '/iota-sandbox/welcome', }, ], }, diff --git a/docs/build/getting-started/subgraphs.md b/docs/build/getting-started/subgraphs.md new file mode 100644 index 00000000000..0824882ea66 --- /dev/null +++ b/docs/build/getting-started/subgraphs.md @@ -0,0 +1,106 @@ +--- +description: 'Learn about the role of subgraphs in smart contracts and how they can provide indexed blockchain data to your smart contracts.' +image: /img/logo/WASP_logo_dark.png +tags: + - Blockchain subgraphs + - Smart Contracts + - Shimmer EVM + - IOTA EVM +--- + +# Subgraphs + +:::info tl;dr; + +Subgraphs provide a streamlined way for developers to access blockchain data relevant to their applications, +significantly enhancing developer efficiency and user experience. + +::: + +Subgraphs collect and organize blockchain data by application needs, making it readily accessible for developers. Unlike +blockchains that store data without application context, subgraphs allow you to quickly retrieve information pertinent +to your application and simplify real-time data access, facilitating the creation of +dynamic user interfaces and interactions in your applications. + +## Subgraph Components and Operations + +Subgraphs are built on [GraphQL](https://graphql.org/) APIs, enabling you to query on-chain transaction data +efficiently. +This feature is particularly useful for developers working with complex smart contracts requiring detailed frontend +interfaces. For instance, querying transactions within a specific liquidity pool becomes straightforward with subgraphs. +By defining a schema and indexing event data, you can utilize the generated GraphQL API for effective data querying. + +### Subgraph Manifest + +The manifest details the smart contracts your subgraph indexes, the events it tracks, and how event data is mapped to +queryable entities. This foundational document ensures your subgraph accurately reflects the blockchain data your +application needs. + +### Subgraph Schema + +The schema organizes your subgraph data, defining entities like pools in DeFi applications, and their attributes. It is +crucial for structuring your data to support efficient queries. + +### Subgraph Mappings + +Mappings process incoming blockchain events, specified in your [manifest](#subgraph-manifest), and store them +according to your [schema](#subgraph-schema). +These [AssemblyScript](https://www.assemblyscript.org/) codes are essential for translating raw blockchain data into a +format your application can easily query. + +## Popular Use Cases for Subgraphs + +Subgraphs have found widespread adoption in various blockchain applications, from DeFi to NFTs and DAOs, due to their +ability to index and query data effectively. + +* **Custom Smart Contract Indexing**: Ideal for developers needing to index data for unique smart contracts, especially + those creating frontend interfaces. +* **Decentralized Finance (DeFi)**: Subgraphs provide real-time data on token prices, liquidity, and more, enhancing + DeFi + applications. +* **Non-fungible Tokens (NFTs)**: They allow for efficient querying of NFT ownership, transaction history, and off-chain + data. +* **Decentralized Autonomous Organizations (DAOs)**: Subgraphs facilitate on-chain decision-making and data analysis for + DAOs. +* **Gaming**: They support real-time data access, improving gameplay and in-game transactions. + +## Benefits of Using Subgraphs + +Subgraphs offer a developer-friendly approach to blockchain data indexing, compatible with various blockchains and +enhancing application security and resilience. + +* **Ease of Use**: With familiar tools like AssemblyScript and GraphQL, subgraphs are accessible to developers, + simplifying + the backend data management. +* **Cross-Blockchain Compatibility**: They work across multiple EVM-compatible networks, allowing applications to + operate + seamlessly on different blockchains. +* **Security and Decentralization**: Opting for decentralized querying with subgraphs can reduce reliance on single data + sources, increasing application robustness. + +## Subgraph Providers + +### Goldsky + +[Goldsky](https://goldsky.com/products/subgraphs) [supports IOTA EVM](https://docs.goldsky.com/chains/iota). +You can use their public API endpoints to access subgraph data. + +:::tip Run a Local Graph Node + +You can use [Nakama's Graph Node GitHub repository](https://github.com/nakamaio/graph-node) to run your own Graph Node. + +::: + +:::tip Blast API Archival Nodes + +You can use the convenient Blast API on IOTA EVM to access [archival nodes](blastAPI.md#archival-nodes). + +::: + +:::tip Wasp Access Nodes + +You can find more information on how to connect to an access node in the +[#nodesharing channel](https://discordapp.com/channels/397872799483428865/398600007378272256) on the [IOTA Discord](https://discord.iota.org/). + +::: + diff --git a/docs/build/identity.rs/1.3/docs/contact.mdx b/docs/build/identity.rs/1.3/docs/contact.mdx new file mode 100644 index 00000000000..3c2958c5c24 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/contact.mdx @@ -0,0 +1,17 @@ +--- +title: Contact +sidebar_label: Contact +description: Get in touch with the project maintainers. +image: /img/Identity_icon.png +tags: + - Contact + - GitHub + - Maintainers +--- + +If you found a security related issue, please follow the [responsible disclosure policy](https://github.com/iotaledger/identity.rs/security/policy). + +For everything else, you can get in contact with the project by: + +- Creating an [issue](https://github.com/iotaledger/identity.rs/issues/new/choose) on [GitHub](https://github.com/iotaledger/identity.rs). +- Joining the `identity` channel on the [IOTA Discord](https://discord.iota.org/). diff --git a/docs/build/identity.rs/1.3/docs/contribute.mdx b/docs/build/identity.rs/1.3/docs/contribute.mdx new file mode 100644 index 00000000000..30116554ab5 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/contribute.mdx @@ -0,0 +1,49 @@ +--- +title: Contribute to the project +sidebar_label: Contribute +description: Contribute to IOTA Identity by joining the Identity initiative, via the projects GitHub repository, documentation, or sharing your knowledge. +image: /img/Identity_icon.png +tags: + - Contribute + - GitHub + - Identity Initiative + - Documentation + - Discord + - reference +--- + +**Thanks for thinking about contributing to the project! You can contribute using the following ways.** + +## Join the Identity Initiative + +The [Identity Initiative](https://github.com/iota-community/X-Team_IOTA_Identity) is a collaborative effort to help improve the developer experience that includes: + +- Quality assurance and review. +- Documentation. +- Code samples. + +If you would like to get involved, join the [#x-team-identity](https://discord.com/channels/397872799483428865/773274309861834782) channel on [Discord](https://discord.iota.org). + +## Contribute to the Project's GitHub Repository + +All of the code is open source and hosted on [GitHub](https://github.com/iotaledger/identity.rs) where you can: + +- [Report a bug](https://github.com/iotaledger/identity.rs/issues/new/choose). +- [Suggest a new feature](https://github.com/iotaledger/identity.rs/blob/main/.github/CONTRIBUTING.md). +- [Contribute to the documentation](#contribute-to-the-documentation). + +## Contribute to the Documentation + +This documentation is also open source and hosted on GitHub. + +If you want to contribute new documentation or fix an error, see the [contribution guidelines](https://github.com/iotaledger/iota-wiki/blob/main/.github/CONTRIBUTING.md). + +## Share Your Knowledge + +Helping others is an important part of any open source ecosystem. + +By sharing your knowledge with others, you can provide a lot of value to the community and maybe inspire someone else to learn and contribute. + +Take a look at what discussions are going on in the `#identity-discussion` channel on [Discord](https://discord.iota.org). + +Thanks :heart: diff --git a/docs/build/identity.rs/1.3/docs/explanations/about-alias-outputs.mdx b/docs/build/identity.rs/1.3/docs/explanations/about-alias-outputs.mdx new file mode 100644 index 00000000000..c7c160a0e41 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/explanations/about-alias-outputs.mdx @@ -0,0 +1,64 @@ +--- +title: Alias Outputs +description: UTXO Alias Ouput +image: /img/Identity_icon.png +tags: + - public keys + - utxo + - Method Specification + - Decentralized Identifiers + - overview + - DLT +--- + +# Alias Outputs + +:::info TL;DR + +The IOTA DID method uses Alias Outputs for storing DID Documents. +Alias Outputs are created via transactions, +and require a [storage deposit](/learn/protocols/stardust/core-concepts/storage-deposit/) to cover the data storage. +The deposit is refundable upon destruction of the output. + +Each Alias Output has an `Alias ID` that becomes the basis for the DID, +and which can be transferred through transactions to update DID Documents. + +::: + + +The IOTA DID method uses the IOTA ledger, which is baed on the unspent transaction output (_UTXO_) model, +as well as the features of the [Stardust](/introduction/stardust/explanations/what_is_stardust) upgrade, +which are fundamental to the IOTA DID method. + +The Alias Output is used to store a DID Document on the ledger. +It is a specific implementation of the UTXO _state machine_ that can hold arbitrary data in its `State Metadata`. +The Alias Output has two kinds of controllers, a state controller and a governor. + +The state controller can only execute state transitions, which update the data in the `State Metadata`. + +The governor, on the contrary, can't update the `State Metadata` but can change controllers and even destroy the Alias Output. + +A controller can be either Ed25519 Address, [Alias Address or an _NFT_ Address](/learn/protocols/stardust/core-concepts/multi-asset-ledger/). Only one of each of these types can be set for an Alias Output. + +To create a new Alias Output, a transaction must be made that includes another Output as input, +a Basic Output, for example, and the new Alias Output as output. + +### Storage Deposit + +The arbitrary data stored in the `State Metadata` of the Alias output must be covered by a +[storage deposit](/learn/protocols/stardust/core-concepts/storage-deposit/). +This helps to control the ledger size from growing uncontrollably while guaranteeing the data +is indefinitely stored on the ledger, which is important for resolving DID Documents. +This deposit is fully refundable and can be reclaimed when the output is destroyed. + +Both the state controller and the governor can control the tokens stored in the Alias Output. +_Nodes_ expose an API to calculate the required deposit depending on the size of the data stored. + +### Alias ID + +Each Alias Output has an `Alias ID`. This ID is assigned after a transaction creates the Alias Output. +The actual DID is derived from this `Alias ID`, so it will be unknown before publishing the transaction. +Consequently, the DID inside the `State Metadata` is replaced by the placeholder `did:0:0` to indicate self. + +If a transaction has an Alias Output as input, its `Alias ID` can be kept by one of its outputs. +This feature is necessary for updating the DID Documents since the DID itself is derived from the `Alias ID`. diff --git a/docs/build/identity.rs/1.3/docs/explanations/decentralized-identifiers.mdx b/docs/build/identity.rs/1.3/docs/explanations/decentralized-identifiers.mdx new file mode 100644 index 00000000000..f4e21c5e0eb --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/explanations/decentralized-identifiers.mdx @@ -0,0 +1,144 @@ +--- +description: The Decentralized Identifiers (DID) standard from W3C is the fundamental standard that supports the concept of a decentralized digital identity. Explore the basic aspects of the DID standard. +image: /img/Identity_icon.png +tags: + - public keys + - Method Specification + - Decentralized Identifiers + - overview + - DLT +--- + +# Decentralized Identifiers (DID) + +:::info TL;DR + +DIDs are unique identifiers that can be resolved to DID Documents containing public keys and URIs for identity verification and public information. + +Adhering to the W3C's DID specifications, IOTA's implementation ensures interoperability and security within its ledger. + +DIDs support self-sovereign identity, allowing identity owners to control their creation and destruction, +while facilitating encrypted communication. + +::: + + +A DID is a unique identifier that can be resolved to a DID Document. This document contains data such as public keys, enabling the holder to prove ownership over their personal data, but also URIs that link to public information about the identity. DIDs are the fundamental building blocks of decentralized digital identity. +This implementation complies with the [DID specifications v1.0](https://www.w3.org/TR/did-core//) from the World Wide Web Consortium (W3C). + +In the IOTA Identity framework, we have implemented the DID standard according to the `iota` [DID Method Specification](../references/specifications/iota-did-method-spec.mdx). Other implementations of DID on IOTA must follow the `iota` DID Method Specification if they want to use the `iota` method name. Libraries implementing the `iota` DID Method Specification are provided for [Rust](../getting-started/rust.mdx) and [WASM](../getting-started/wasm.mdx). + +An example of a DID conforming to the `iota` method specification: +`did:iota:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe` + +## Decentralized Identifiers + +A Decentralized Identifier, or DID, is a unique identifier that is tied to a subject. This subject can be anything, like a person, an organization, an IoT device, or even an object. The identifier can be used by the subject to identify themselves through a digital format, providing a basis for online identification. The identifier looks like a set of random characters that includes some prefixes to determine which standard and implementation is used: + +`did:iota:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe` + +The World Wide Web Consortium (W3C) is a well-known standardization body that has standardized how DIDs should look and work. +This provides a basis for different technologies that implement the [DID standard](https://www.w3.org/TR/did-spec-registries/#did-methods) to achieve interoperability. +Keep in mind that, unfortunately, most of these methods are outdated and not maintained. + +## DID Documents + +The purpose of a DID is to help navigate to a DID Document, +which is a document containing more information regarding the identity subject. +This document contains data such as public keys, enabling the subject to prove ownership over their personal data, +but can contain additional information on how to interact with the subject. + +The identifier contains all information to resolve a DID, providing the latest DID Document. +The first three characters `did` indicate that the DID standard from W3C must be used to resolve the identifier. +It is followed by a unique method name, in our case `iota`, to indicate that the IOTA method is used. + +The IOTA method is a specific implementation following the [IOTA DID Method Specification](../references/specifications/iota-did-method-spec.mdx). +This provides unique rules for the protocol to follow in order to manage a DID Document. +In our case, it describes how DID Documents are uploaded and queried to and from the IOTA ledger. + +Lastly, a DID also contains a set of random characters that are unique per identity and resolve to a single DID Document. + +:::tip Requires basic knowledge of Asymmetric Encryption + +The following sections require some basic knowledge of Asymmetric Encryption. +Please read or view some materials on the subject before continuing. + +::: + +### DID Document Anatomy + +A DID Document mostly contains two important pieces of data: verification methods and services. + +#### Verification Methods + +Verification methods contain public key material that can be used to prove ownership over the identity, +by cryptographically signing something with the associated private key. +The public key can be used to verify that the identity subject signed the data and therefore controls the private key. +Ownership over the private keys, therefore, proves ownership over the identity. + +This also means that it is very important to keep the private keys safe and secure. +In addition, the public keys allow users to send encrypted data to the identity that only the identity owner can decrypt. + +:::caution + +Never share your private keys, seeds, passphrases with anyone. Not even IOTA Foundation members. +This may lead to loss of funds or control over your own digital identity. + +::: + +#### Services + +Services are URIs that point to more information about the identity. +This could be something as simple as a website for an organizational identity. +These services are publicly available for all to read, +and should not contain Personal Identifiable Information (PII) in the case of human identities. + +## Why Use DIDs? + +DIDs allow any subject to have a unique identifier that they can prove ownership of, +and at the same time provide a way to send them encrypted messages. +The Identity is Self-Sovereign, meaning the subject is always in control; +whether it is [creating](../how-tos/decentralized-identifiers/create.mdx), [updating](../how-tos/decentralized-identifiers/update.mdx), or [destroying](../how-tos/decentralized-identifiers/delete.mdx) it. + +### Verifiable Credentials + +DIDs become more interesting when you combine them with [verifiable credentials (VC)](verifiable-credentials.mdx). +In essence, verifiable credentials (VCs) are signed statements by trusted third parties about a certain identity. +The signer, or Issuer, is referenced by the DID and so is the subject, often called the holder. +The holder controls a copy of this statement and can share it with other parties, the _Verifiers_, +who can verify the statement and check which party made the statement without asking the Issuer. +Instead, they can verify the issuer's signature by checking the issuer's DID Document. + +This puts Holders back in control over their own data, +while making the data much more trustworthy as it has become verifiable. + +## Why Use Iota Identity Over Other Implementations? + +IOTA Identity is a framework to implement Self-Sovereign Identities on IOTA. +Inherently, IOTA provides some unique features that have a major impact on the usability of the framework. + +### Availability and Accessibility + +DID Documents are stored in the ledger state and are covered [storage deposit](/learn/protocols/stardust/core-concepts/storage-deposit/). +This guarantees that all nodes will have an up-to-date copy of the latest DID Document. +Resolving a DID into its document can usually be done by any IOTA node in the network. +This solves many issues regarding availability, accessibility, and synchronization. + +### Layer1 Interactions + +DID Documents are stored in [Alias Outputs](./about-alias-outputs.mdx), +this allows them to directly interact with Layer 1 artifacts like [NFTs and native assets](/learn/protocols/stardust/core-concepts/multi-asset-ledger/). + +For instance, an Alias Output representing a DID can hold native assets or control NFTs. +Transferring funds between DIDs is also possible on Layer 1. + +### Ease-of-use + +IOTA Identity abstracts the details of the DID standard by providing easy-to-use APIs that allow standardized behavior. +It also allows more flexible and complex management of DID Documents. + +### Secure Storage + +IOTA Identity provides a +[Stronghold](/stronghold.rs/welcome/ 'Stronghold is an open-source software library that was originally built to protect IOTA Seeds, but can be used to protect any digital secret.') solution +for managing secrets securely, without requiring developers to reinvent the security wheel. diff --git a/docs/build/identity.rs/1.3/docs/explanations/verifiable-credentials.mdx b/docs/build/identity.rs/1.3/docs/explanations/verifiable-credentials.mdx new file mode 100644 index 00000000000..708e04d8289 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/explanations/verifiable-credentials.mdx @@ -0,0 +1,74 @@ +--- +description: Verifiable credentials are statements about the holder. They can be verified online or in person, and the holder decides who to share them with. +image: /img/Identity_icon.png +tags: + - verifiable + - credentials + - person +--- +# Verifiable Credentials + +:::info TL;DR + +Verifiable credentials (VCs) are digital statements that can be cryptographically proven, like a digital passport, +and are used within systems to assert certain properties or capabilities of an entity. + +In the IOTA Identity framework, this is managed with decentralized identifiers (DIDs) on the Tangle. +Subjects and issuers use their DIDs for the creation and verification of credentials. + +::: + +Credentials are statements about an entity, +such as properties that the entity possesses or capabilities that they have, +like a driver's license, passports, or a person's age. +Verifiable credentials (VCs) are statements (e.g., Alice has a driver's license) +that can be cryptographically verified by a third party, either online or in person. +Additionally, the holder of the VC decides what is shared and who it is shared with. + +There are several types of actors that play different roles in a Verifiable Credential system. +We'll start with a common example of how things work in the world today using physical credentials and centralized databases, +and outline the roles that various entities play in the Verifiable Credential system. + +## Example - Passport Issuance + +A government (the _issuer_) issues a passport asserting citizenship (the _Verifiable Credential_) to Alice (the _subject_ and _Holder_), +and writes the information to a database (the _Verifiable Data Registry_). +When crossing the border, Alice (the _Holder_) presents her passport to a border agent (the _Verifier_), +who can verify that Alice (the _subject_) is indeed a citizen. + + + +**Subject:** An entity about which claims are made – in this example, that Alice (the _subject_) is a citizen of this country. + +**Holder:** Any entity with a verifiable credential – Alice (the _Holder_) possesses the passport (the _VC_). + +**Issuer:** An entity which asserts claims about a subject – The governing body (the _issuer_), which is trusted, issues Alice a passport. + +**Verifier:** An entity which checks if the VC a holder presents is legitimate – The border agent (the _Verifier_) trusts the government (the _issuer_) which issued Alice her passport and validates that Alice (the _subject_) is a citizen. + +:::note + +See the [Verifiable Credentials Data Model 1.0 Specification](https://w3c.github.io/vc-data-model/) for more information. + +::: + +## Verifiable Credentials in IOTA + +In the IOTA Identity framework, instead of a physical passport being given to Alice and its information written +into a centralized database owned by the government, Alice receives a digital verifiable credential, +and the information required for verification in the future is written to the Tangle. + +At a high level, the creation and verification of a VC on IOTA works as follows: + + +The first step is to create a verifiable credential that requires the subject (Alice) and issuer (the government) to +have [DIDs](./decentralized-identifiers.mdx) published on the Tangle and a set of statements being asserted (that Alice has a passport). +The issuer signs the credential with their private key and publishes the public key to the Tangle. + +Once the issuer is confident that the credential satisfies its expectations, +the credential is stored and transmitted to the subject in a secure manner (off-chain). + +Validation is performed by looking up the issuer's public key on the Tangle, +the holder proving ownership of their DID to the verifier (evidence), +and validating that the issuing party has indeed signed the credential. + diff --git a/docs/build/identity.rs/1.3/docs/explanations/verifiable-presentations.mdx b/docs/build/identity.rs/1.3/docs/explanations/verifiable-presentations.mdx new file mode 100644 index 00000000000..a0a68dafc3e --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/explanations/verifiable-presentations.mdx @@ -0,0 +1,39 @@ +# Verifiable Presentations + +A verifiable presentation is the recommended data format for sharing one or more [verifiable credentials](./verifiable-credentials.mdx). +It is constructed and signed by a holder to prove control over their credentials and can be presented to a verifier for [validation](#validation). + +For instance, after an issuer [creates and issues](./../how-tos/verifiable-credentials/create.mdx) a [verifiable credential](./verifiable-credentials.mdx) to a holder, such as a university issuing a degree to a graduate, +the holder stores it securely until asked to present it. +A company could then request proof of that university degree: the holder can [create a verifiable presentation](./../how-tos/verifiable-credentials/create.mdx) +containing their credential, already signed by their university, and present it to the company to [validate](./../how-tos/verifiable-credentials/create.mdx#validate-a-vc). + +Note that verifiable presentations that contain personal data should, as with verifiable credentials, be transmitted and stored securely off-chain to satisfy data privacy regulations such as [GDPR](https://gdpr.eu/). + +:::note + +See the [Verifiable Credentials Data Model Specification](https://www.w3.org/TR/vc-data-model/#presentations) for more information on verifiable presentations. + +::: + +## Security Considerations + +### Replay Attacks + +A malicious actor could potentially store a verifiable presentation without a challenge +and replayed to a different verifier, impersonating the holder. +This is because the holder's signature on a presentation would still be seen as valid indefinitely, +until they [rotate](https://www.w3.org/TR/did-core/#verification-method-rotation) the verification method used. + +To mitigate this, verifiers should always send a unique challenge when requesting a verifiable presentation. +This challenge can be set as the `nonce` property of the JWS by the holder during signing. +The digital signature prevents these properties from being altered as it would invalidate the signature, effectively preventing a malicious +actor from injecting different values into old verifiable presentations. A presentation without a challenge in its proof that matches what was +sent by the verifier should be considered invalid. + +The challenge string should be sufficiently random and unique for each verifiable presentation requested by a verifier to avoid +being predicted. + +Holders may additionally specify that their signature on a verifiable presentation expires after a short duration, as +per `JwtPresentationOptions`. However, verifiers and different implementations could ignore that property, +so setting a signature expiration alone should not be relied upon. diff --git a/docs/build/identity.rs/1.3/docs/faq.mdx b/docs/build/identity.rs/1.3/docs/faq.mdx new file mode 100644 index 00000000000..d611f9dfa94 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/faq.mdx @@ -0,0 +1,53 @@ +--- +title: Frequently Asked Questions +sidebar_label: FAQ +description: Frequently Asked Question regarding IOTA Identity. +image: /img/Identity_icon.png +tags: + - FAQ + - Frequently Asked Question + - Troubleshooting + - IOTA Identity +--- + +This page contains frequently asked questions regarding the Identity Library and Self-Sovereign Identity in general. + +### What programming languages are supported by the IOTA Identity framework? + +We currently provide a Rust library and a JavaScript library for both the browser and Node.js via WebAssembly (Wasm) bindings. See the "Programming Languages" section for more information. + +### Do I need to have IOTA tokens to start building with IOTA Identity? + +You need IOTA tokens to create identities, in order to pay the storage deposit. + +### How do I prove control over my DID? + +Control over an identity is ultimately tied to the control over cryptographic key material (something you have). + +### How do I store my private keys? + +Theoretically, you can store the keys however you like. Where possible, we provide a secure default using IOTA Stronghold, a secure software implementation for isolating digital secrets with encrypted storage. For even better guarantees, you could look into hardware-based key storage. + +### Do I need a Permanode to use IOTA Identity? + +You can get started without one, but currently, you require access to a Permanode (a node that stores the entire history of the Tangle) to reliably resolve the history of identities. + +### Can I use IOTA Identity on Android or iOS? + +We currently do not supply dedicated bindings for Kotlin or Swift. There has been some success running the Wasm bindings on mobile, however. + +### Can I use IOTA Identity on embedded devices? + +We currently do not supply dedicated bindings catering to embedded devices with restricted capabilities. You can try to compile the Rust library for your target platform or use a gateway in front of the devices to handle IOTA Identity interactions. + +### What should I do if my private key is compromised? + +If you still have control over your identity, rotate the key material ASAP! If an attacker has locked you out of your identity, there is not much you can do. Notify contacts that your identity has been compromised and start fresh with a new one. For this reason, we suggest using different keys for day-to-day signing and authentication operations and instead storing private keys capable of updating your DID Document securely and separately. + +### Are verifiable credentials stored on the Tangle? + +Verifiable credentials, particularly those with personal identifiable information, are supposed to be stored securely off-Tangle on user devices or systems. As a user, you are in charge of storing your credentials securely and sharing them with other parties on a need-to-know basis. + +### Do I need to hide my DID? Will people be able to identify me by my DID? + +A DID Document should not contain any information linking back to you as a person. However, there is the chance of entities correlating information about you from your DID if used across multiple issuers and verifiers. To minimize this risk, it is advisable to use different DIDs for different use cases. diff --git a/docs/build/identity.rs/1.3/docs/getting-started/rust.mdx b/docs/build/identity.rs/1.3/docs/getting-started/rust.mdx new file mode 100644 index 00000000000..ab6e3296cdb --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/getting-started/rust.mdx @@ -0,0 +1,68 @@ +--- +sidebar_label: Rust +description: Getting started with the IOTA Identity Rust Library. +image: /img/Identity_icon.png +tags: + - Rust + - Identity +--- +# Getting Started with Rust + +## Requirements + +- [Rust](https://www.rust-lang.org/) (>= 1.62) +- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.62) + +## Include the Library + +To include IOTA Identity in your project, add it as a dependency in your `Cargo.toml`: + +### Latest Stable Release + +This version is published to crates.io and is **stable**, following semantic versioning. + +```toml +[dependencies] +identity_iota = { version = "1.2.0" } +``` + +### Development Release + +This version matches the `main` branch of this repository. It has all the **latest features**, but as such, it **may also have undocumented breaking changes**. + +```toml +[dependencies] +identity_iota = { git = "https://github.com/iotaledger/identity.rs", branch = "main"} +``` + +## Examples + +To try out the [examples](https://github.com/iotaledger/identity.rs/tree/v1.2.0/examples), you should: + +1. Clone the repository: + +```bash +git clone https://github.com/iotaledger/identity.rs +``` + +2. Build the repository: + +```bash +cargo build +``` + +3. Run your first example: + +```bash +cargo run --example 0_create_did +``` + +## API Reference + +You can find the API reference for the Rust library on [docs.rs](https://docs.rs/identity_iota/latest/identity_iota/index.html). + +If you would like to build the documentation, locally you can do so with the following command: + +``` +RUSTDOCFLAGS='--cfg docsrs' cargo +nightly doc -p identity_iota --all-features --no-deps --open +``` diff --git a/docs/build/identity.rs/1.3/docs/getting-started/wasm.mdx b/docs/build/identity.rs/1.3/docs/getting-started/wasm.mdx new file mode 100644 index 00000000000..ad1baaf48d3 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/getting-started/wasm.mdx @@ -0,0 +1,339 @@ +--- +sidebar_label: Wasm +description: Getting started with the IOTA Identity WASM Library. +image: /img/Identity_icon.png +tags: + - WASM + - install + - npm + - yarn + - build + - nodejs + - webpack +--- +# Getting Started with Wasm + +## Minimum Requirements + +- [Node.js](https://nodejs.org/en) (>= `v16`) + +## Install the Library + +You can install the latest stable version of the library by running the following command: + +```bash npm2yarn +npm install @iota/identity-wasm +``` + +## Build the Library + +Alternatively, you can build the bindings yourself if you have Rust installed. +If not, refer to [rustup.rs](https://rustup.rs) for the installation. + +### Requirements + +- [Node.js](https://nodejs.org/en) (>= `v16`) +- [Rust](https://www.rust-lang.org/) (>= 1.62) +- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.62) + +### 1. Install `wasm-bindgen-cli` + +If you want to build the library from source, +you will first need to manually install [`wasm-bindgen-cli`](https://github.com/rustwasm/wasm-bindgen). +A manual installation is required because we use the [Weak References](https://rustwasm.github.io/wasm-bindgen/reference/weak-references.html) feature, +which [`wasm-pack` does not expose](https://github.com/rustwasm/wasm-pack/issues/930). + +```bash +cargo install --force wasm-bindgen-cli +``` + +### 2. Install Dependencies + +After installing `wasm-bindgen-cli`, you can install the necessary dependencies using the following command: + +```bash npm2yarn +npm install +``` + +### 3. Build + + + + + +You can build the bindings for `node.js` using the following command: + +```bash npm2yarn +npm run build:nodejs +``` + + + + + +You can build the bindings for the `web` using the following command: + +```bash npm2yarn +npm run build:web +``` + + + + +## NodeJS Usage + +The following code creates a new IOTA DID Document suitable for publishing to a local test network, like the +[IOTA Sandbox](/iota-sandbox/welcome/). + + + + +```typescript +const { + KeyPair, + KeyType, + MethodScope, + IotaDocument, + IotaVerificationMethod, + IotaService, + MethodRelationship, + IotaIdentityClient, +} = require('@iota/identity-wasm/node'); +const { Client } = require('@iota/client-wasm/node'); + +// The endpoint of the IOTA node to use. +const API_ENDPOINT = 'http://127.0.0.1:14265'; + +/** Demonstrate how to create a DID Document. */ +async function main() { + // Create a new client with the given network endpoint. + const client = new Client({ + primaryNode: API_ENDPOINT, + localPow: true, + }); + + const didClient = new IotaIdentityClient(client); + + // Get the Bech32 human-readable part (HRP) of the network. + const networkHrp = await didClient.getNetworkHrp(); + + // Create a new DID document with a placeholder DID. + // The DID will be derived from the Alias Id of the Alias Output after publishing. + const document = new IotaDocument(networkHrp); + + // Insert a new Ed25519 verification method in the DID document. + let keypair = new KeyPair(KeyType.Ed25519); + let method = new IotaVerificationMethod( + document.id(), + keypair.type(), + keypair.public(), + '#key-1', + ); + document.insertMethod(method, MethodScope.VerificationMethod()); + + // Attach a new method relationship to the existing method. + document.attachMethodRelationship( + document.id().join('#key-1'), + MethodRelationship.Authentication, + ); + + // Add a new Service. + const service = new IotaService({ + id: document.id().join('#linked-domain'), + type: 'LinkedDomains', + serviceEndpoint: 'https://iota.org/', + }); + document.insertService(service); + + console.log(`Created document `, JSON.stringify(document.toJSON(), null, 2)); +} + +main(); +``` + +### Expected Output + +``` +Created document { + "doc": { + "id": "did:iota:0x0000000000000000000000000000000000000000000000000000000000000000", + "verificationMethod": [ + { + "id": "did:iota:0x0000000000000000000000000000000000000000000000000000000000000000#key-1", + "controller": "did:iota:0x0000000000000000000000000000000000000000000000000000000000000000", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "z4SxypezRxr1YdMAJBePfHGxZ9hNZ53WVixZq3PbUcztW" + } + ], + "authentication": [ + "did:iota:0x0000000000000000000000000000000000000000000000000000000000000000#key-1" + ], + "service": [ + { + "id": "did:iota:0x0000000000000000000000000000000000000000000000000000000000000000#linked-domain", + "type": "LinkedDomains", + "serviceEndpoint": "https://iota.org/" + } + ] + }, + "meta": { + "created": "2022-09-09T11:29:32Z", + "updated": "2022-09-09T11:29:32Z" + } +} +``` + +## Web Usage + +### Set Up + +The library loads the WASM file with an HTTP GET request, so you must copy the `.wasm` file the root of the `dist` folder. + +#### Rollup + +- Install `rollup-plugin-copy`: + +```bash npm2yarn +npm install rollup-plugin-copy --save-dev +``` + +- Add the copy plugin usage to the `plugins` array under `rollup.config.js`: + +```js +// Include the copy plugin +import copy from 'rollup-plugin-copy'; + +// Add the copy plugin to the `plugins` array of your rollup config: +copy({ + targets: [ + { + src: 'node_modules/@iota/client-wasm/web/wasm/client_wasm_bg.wasm', + dest: 'public', + rename: 'client_wasm_bg.wasm', + }, + { + src: 'node_modules/@iota/identity-wasm/web/identity_wasm_bg.wasm', + dest: 'public', + rename: 'identity_wasm_bg.wasm', + }, + ], +}); +``` + +#### Webpack + +- Install `copy-webpack-plugin`: + +```bash npm2yarn +npm install copy-webpack-plugin --save-dev +``` + +```js +// Include the copy plugin +const CopyWebPlugin= require('copy-webpack-plugin'); + +// Add the copy plugin to the `plugins` array of your webpack config: + +new CopyWebPlugin({ + patterns: [ + { + from: 'node_modules/@iota/client-wasm/web/wasm/client_wasm_bg.wasm', + to: 'client_wasm_bg.wasm' + }, + { + from: 'node_modules/@iota/identity-wasm/web/identity_wasm_bg.wasm', + to: 'identity_wasm_bg.wasm' + } + ] +}), +``` + +### Web Usage Example + +```typescript +import * as client from '@iota/client-wasm/web'; +import * as identity from '@iota/identity-wasm/web'; + +/** Demonstrate how to create a DID Document. */ +async function createDocument() { + // Create a new client with the given network endpoint. + const iotaClient = new client.Client({ + primaryNode: API_ENDPOINT, + localPow: true, + }); + + const didClient = new identity.IotaIdentityClient(iotaClient); + + // Get the Bech32 human-readable part (HRP) of the network. + const networkHrp = await didClient.getNetworkHrp(); + + // Create a new DID document with a placeholder DID. + // The DID will be derived from the Alias Id of the Alias Output after publishing. + const document = new identity.IotaDocument(networkHrp); + + // Insert a new Ed25519 verification method in the DID document. + let keypair = new identity.KeyPair(identity.KeyType.Ed25519); + let method = new identity.IotaVerificationMethod( + document.id(), + keypair.type(), + keypair.public(), + '#key-1', + ); + document.insertMethod(method, identity.MethodScope.VerificationMethod()); + + // Attach a new method relationship to the existing method. + document.attachMethodRelationship( + document.id().join('#key-1'), + identity.MethodRelationship.Authentication, + ); + + // Add a new Service. + const service = new identity.IotaService({ + id: document.id().join('#linked-domain'), + type: 'LinkedDomains', + serviceEndpoint: 'https://iota.org/', + }); + document.insertService(service); + + console.log(`Created document `, JSON.stringify(document.toJSON(), null, 2)); +} + +client + .init() + .then(() => identity.init()) + .then(() => { + await createDocument(); + }); + +// or + +(async () => { + await client.init(); + await identity.init(); + + await createDocument(); +})(); + +// Default path is "identity_wasm_bg.wasm", but you can override it like this +await identity.init('./static/identity_wasm_bg.wasm'); +``` + +You need to call `identity.init().then()`, +or `await identity.init()` to load the Wasm file from the server if not available, +because of that **it will only be slow for the first time**. + +## Examples in the Wild + +You may find it useful to see how the WASM bindings are being used in existing applications: + +- [Zebra IOTA Edge SDK](https://github.com/ZebraDevs/Zebra-Iota-Edge-SDK) (mobile apps using Capacitor.js + Svelte) + +## [API Reference](../references/api/wasm.mdx) + +## [Examples](https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/README.md) diff --git a/docs/build/identity.rs/1.3/docs/glossary.mdx b/docs/build/identity.rs/1.3/docs/glossary.mdx new file mode 100644 index 00000000000..54c79d76b62 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/glossary.mdx @@ -0,0 +1,141 @@ +--- +description: Glossary for IOTA Identity, defines the terms used in this specification and throughout decentralized identifier infrastructure. +image: /img/Identity_icon.png +tags: + - W3C + - terminology + - IOTA + - verification method + - verifiable data registry + - reference +--- + +# Glossary + +This section defines the terms used in this specification, [sourced from W3](https://www.w3.org/TR/did-core/#terminology), and throughout decentralized identifier infrastructure. A link to these terms is included whenever they appear in this specification. + +The first part of the glossary describes the terminology by the W3C. The [second describes](#iota-terminology) the terminology for IOTA-related topics. + +## W3C Terminology + +### Authentication + +A process (typically some type of protocol) by which an entity can prove it has a specific attribute or controls a specific secret using one or more verification methods. With DIDs, a common example would be proving control of the private key associated with a public key published in a DID document. + +### Decentralized Identifier (DID) + +A globally unique persistent identifier that does not require a centralized registration authority because it is generated or registered cryptographically. The generic format of a DID is defined in the DID Core specification. A specific DID scheme is defined in a DID method specification. Many, but not all, DID methods make use of distributed ledger technology (DLT) or some other form of decentralized network. + +### Decentralized Identity Management + +A type of identity management that is based on the use of decentralized identifiers. Decentralized identity management extends authority for identifier generation, registration, and assignment beyond traditional roots of trust, such as X.500 directory services, the Domain Name System, and most national ID systems. + +### DID Controller + +An entity that can make changes to a DID document. A DID may have more than one DID controller. The DID controller(s) can be denoted by the optional controller property at the top level of the DID document. Note that one DID controller may be the DID subject. + +### DID Delegate + +An entity to whom a DID controller has granted permission to use a verification method associated with a DID via a DID document. For example, a parent who controls a child's DID document might permit the child to use their personal device for authentication purposes. In this case, the child is the DID delegate. The child's personal device would contain the private cryptographic material enabling the child to authenticate using the DID. However, the child may not be permitted to add other personal devices without the parent's permission. + +### DID Document + +A set of data describing the DID subject, including mechanisms, such as public keys and pseudonymous biometrics, that the DID subject or a DID delegate can use to authenticate itself and prove its association with the DID. A DID document may also contain other attributes or claims describing the DID subject. A DID document may have one or more different representations as defined in [§ 6. Representations](https://www.w3.org/TR/did-core/#representations) or in the W3C DID Specification Registries [DID-SPEC-REGISTRIES](https://www.w3.org/TR/did-core/#bib-did-spec-registries). + +### DID Fragment + +The portion of a DID URL that follows the first hash sign character (#). DID fragment syntax is identical to URI fragment syntax. + +### DID Method + +A definition of how a specific DID scheme must be implemented to work with a specific verifiable data registry. A DID method is defined by a DID method specification, which must specify the precise operations by which DIDs are created, resolved, and deactivated, where DID documents are written and updated. [See W3's Methods](https://www.w3.org/TR/did-core/#methods). + +### DID Path + +The portion of a DID URL that begins with and includes the first forward-slash (/) character and ends with either a question mark (?) character or a fragment hash sign (#) character (or the end of the DID URL). DID path syntax is identical to URI path syntax. See [Path](https://www.w3.org/TR/did-core/#path). + +### DID Query + +The portion of a DID URL that follows and includes the first question mark character (?). DID query syntax is identical to URI query syntax. See [Query](https://www.w3.org/TR/did-core/#query). + +### DID Resolution + +The function that takes, as an input, a DID and a set of input metadata and returns a DID document in a conforming representation plus additional metadata. This function relies on the "Read" operation of the applicable DID method. The inputs and outputs of this function are defined in [Resolution](https://www.w3.org/TR/did-core/#resolution). + +### DID Resolver + +A DID resolver is a software or hardware component that performs the DID resolution function by taking a DID as input and producing a conforming DID document as output. + +### DID Scheme + +The formal syntax of a decentralized identifier. The generic DID scheme begins with the prefix "did:" as defined in the section of the DID Core specification. Each DID method specification must define a specific DID scheme that works with that particular DID method. In a specific DID method scheme, the DID method name must follow the first colon and terminate with the second colon, such as "did:example:". + +### DID Subject + +The entity identified by a DID and described by a DID document. A DID has exactly one DID subject. Anything can be a DID subject: a person, group, organization, physical thing, digital thing, logical thing, and so on. + +### DID URL + +A DID plus any additional syntactic component that conforms to the definition in § 3.2 DID URL Syntax. This includes an optional DID path, optional DID query (and its leading ? character), and optional DID fragment (and its leading # character). + +### DID URL Dereferencing + +The function that takes as its input a DID URL, a DID document, plus a set of dereferencing options, and returns a resource. This resource may be a DID document plus additional metadata, or it may be a secondary resource contained within the DID document, or it may be a resource entirely external to the DID document. If the function begins with a DID URL, it uses the DID resolution function to fetch a DID document indicated by the DID contained within the DID URL. The dereferencing function can then perform additional processing on the DID document to return the dereferenced resource indicated by the DID URL. The inputs and outputs of this function are defined in [DID URL Dereferencing](https://www.w3.org/TR/did-core/#did-url-dereferencing). + +## IOTA Terminology + +### Distributed Ledger (DLT) + +A distributed database in which the various nodes use a consensus protocol to maintain a shared ledger in which each transaction is cryptographically signed and chained to the previous transaction. + +### Public Key Description + +A data object contained inside a DID document that contains all the metadata necessary to use a public key or verification key. + +### Resource + +As defined by [RFC3986](https://www.rfc-editor.org/rfc/rfc3986): "...the term 'resource' is used in a general sense for whatever might be identified by a URI." Similarly, any resource may serve as a DID subject identified by a DID + +### Representation + +As defined for HTTP by [RFC7231](https://httpwg.org/specs/rfc7231.html): "information that is intended to reflect a past, current, or desired state of a given resource, in a format that can be readily communicated via the protocol, and that consists of a set of representation metadata and a potentially unbounded stream of representation data." A DID document is a representation of information describing a DID subject. The [Representations](https://www.w3.org/TR/did-core/#representations) section of the DID Core specification defines several representation formats for a DID document. + +### Service + +A means of communicating or interacting with the DID subject or associated entities via one or more service endpoints. Examples include discovery services, agent services, social networking services, file storage services, and verifiable credential repository services. + +### Service Endpoint + +A network address (such as an HTTP URL) at which a service operates on behalf of a DID subject. + +### Uniform Resource Identifier (URI) + +The standard identifier format for all resources on the World Wide Web as defined by [RFC3986](https://www.rfc-editor.org/rfc/rfc3986). A DID is a type of URI scheme. + +### Verifiable Credential + +A standard data model and representation format for cryptographically-verifiable digital credentials as defined by the W3C [VC-DATA-MODEL](https://www.w3.org/TR/vc-data-model/). + +### Verifiable Data Registry + +A system that facilitates the creation, verification, updating, or deactivation of decentralized identifiers and DID documents. A verifiable data registry may also be used for other cryptographically-verifiable data structures, such as verifiable credentials. For more information, see [VC-DATA-MODEL](https://www.w3.org/TR/vc-data-model/). + +### Verifiable Timestamp + +A verifiable timestamp enables a third-party to verify that a data object existed at a specific moment in time and that it has not been modified or corrupted since that moment in time. If the data integrity were to be reasonably modified or corrupted since that moment in time, the timestamp is not verifiable. + +### Verification Method + +A set of parameters that can be used together with a process or protocol to independently verify a proof. For example, a public key can be used as a verification method with respect to a digital signature; in such usage, it verifies that the signer possessed the associated private key. + +"Verification" and "proof" in this definition are intended to apply broadly. For example, a public key might be used during Diffie-Hellman key exchange to negotiate a shared symmetric key for encryption. This guarantees the integrity of the key agreement process. It is thus another type of verification method, even though descriptions of the process might not use the words "verification" or "proof." + +### Verification Relationship + +An expression of the relationship between the DID subject and a verification method. An example of a verification relationship is [authentication](https://www.w3.org/TR/did-core/#authentication). + +### Universally Unique Identifier (UUID) + +A type of globally unique identifier defined by [RFC4122](https://www.rfc-editor.org/rfc/rfc4122). UUIDs are similar to DIDs in that they do not require a centralized registration authority. UUIDs differ from DIDs in that they are not resolvable or cryptographically verifiable. +In addition to the terminology above, this specification also uses terminology from the [INFRA](https://infra.spec.whatwg.org/) specification to formally define the abstract data model. When [INFRA](https://infra.spec.whatwg.org/) terminology is used, such as string, ordered set, and map, it is linked directly to that specification. +In addition to the terminology above, this specification also uses terminology from the [INFRA] specification to formally define the abstract data model. When [INFRA] terminology is used, such as string, ordered set, and map, it is linked directly to that specification. diff --git a/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/create.mdx b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/create.mdx new file mode 100644 index 00000000000..6266a8b26df --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/create.mdx @@ -0,0 +1,180 @@ +--- +title: Creating a Decentralized Identity +sidebar_label: Create and Publish +description: Create DID Documents and publish them to the Tangle +image: /img/Identity_icon.png +tags: + - Documents + - DID + - Tangle + - Create + - Publish +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +If you want to benefit from Self-Sovereign Identity, +you need to create a [Decentralized Identity](../../explanations/decentralized-identifiers.mdx). +This identity consists of many parts that have different functions. + +:::note DID method Specification + +Note that the Iota Identity Framework follows [IOTA DID Method Specification](../../references/specifications/iota-did-method-spec.mdx). + +::: + +## Identity Generation Process + + +### 1. Get Funds to Cover the Storage Deposit + +The first thing you will need to generate an identity is an address with enough funds to cover +the [Storage Deposit](../../explanations/about-alias-outputs.mdx#storage-deposit). +In test networks, you can use a [faucet](https://faucet.testnet.shimmer.network/) to request funds. + +:::tip + +If you want to use the main Shimmer or IOTA networks, +you will need an output with actual Shimmer or IOTA funds to create a new Alias Output that represents a DID. + +::: + +
+ + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/0_create_did.rs#L52 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/0_create_did.ts#L40-L51 +``` + + + +
+ +### 2. Create the Content for the DID Document + +As a bare minimum, a [DID document](../../explanations/decentralized-identifiers.mdx) needs at least one verification method. + +At this point, the DID itself is unknown since the Alias Output is not published yet and didn't get an `Alias ID` assigned. + +:::tip + +You can use a placeholder `did:iota:0x0000000000000000000000000000000000000000000000000000000000000000` to reference +the DID inside the document. + +::: + +
+ + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/0_create_did.rs#L59-L71 +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/0_create_did.ts#L55C44-L65 +``` + + + +
+ +### 3. Construct a New Alias Output + +Next, you need to construct a new [Alias Output](../../explanations/about-alias-outputs.mdx) that includes the +DID Document in the [State Metadata](../../explanations/about-alias-outputs.mdx). +The created Alias Output contains an encoded version of the DID Document in its `State Metadata`, and has the state +controller and the governor set to the generated Ed25519 address. + +Note that controllers don't need to be Ed25519 addresses, they can be any type of output. +However, they must be unlocked in order perform a state or governance transition when the DID Document is updated or destroyed. + + +
+ + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/0_create_did.rs#L75 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/0_create_did.ts#L70 +``` + + + +
+ +### 4. Publish the generated Alias Output. + +The byte cost for the document is automatically calculated and a new transaction is published that includes +the Basic Output as input and the newly generated Alias Output as output, as well as another Basic Output which contains +the remaining tokens. + +The DID is only known once the [Alias Output](../../explanations/about-alias-outputs.mdx) is successfully published, +since the DID's [Tag](../../references/specifications/iota-did-method-spec.mdx#iota-tag) contains the +[Alias ID](../../explanations/about-alias-outputs.mdx#alias-id). +Once the transaction is confirmed, the `Alias ID` is assigned, and the DID can be derived from it, +the DID Document is stored on the ledger and can be [resolved](resolve.mdx) using any node. + + +
+ + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/0_create_did.rs#L78 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/0_create_did.ts#L74 +``` + + + +
+ +## Full Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/0_create_did.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/0_create_did.ts +``` + + + + +## Running Examples Locally + +In order to run the examples, you will need to run the [IOTA Sandbox](/iota-sandbox/welcome/) locally. + +If you want to use something different, you will need to modify the API and faucet endpoints in the examples to match your +setup. \ No newline at end of file diff --git a/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/delete.mdx b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/delete.mdx new file mode 100644 index 00000000000..86bb74c20a7 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/delete.mdx @@ -0,0 +1,106 @@ +--- +title: Delete an IOTA Identity +sidebar_label: Delete +description: How to deactivate or destroy an IOTA Identity +image: /img/Identity_icon.png +tags: + - Delete + - Deactivate + - Destroy +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +There are two approaches to delete an IOTA Identity, with different implications: + +- [Deactivate](#deactivate) +- [Destroy](#destroy) + +## Deactivate + +As detailed in the [IOTA DID Method Specification](../../references/specifications/iota-did-method-spec.mdx#deactivate), +the state controller of an IOTA Identity may [deactivate](https://www.w3.org/TR/did-core/#did-document-metadata) it by publishing an update that either: + +- deletes the contents of the DID Document entirely, leaving the state metadata empty, OR +- sets the `deactivated` field in the DID Document metadata to `true`. + +In both cases, the DID Document will be marked as `deactivated` when resolved. + +:::tip Reversible + +The identity can be reactivated at any time, by publishing an update restoring the DID Document's contents, +or unsetting the `deactivated` field in the metadata respectively, depending on how it was initially deactivated. + +Note that if the governor is different from the state controller, it cannot deactivate an identity directly because +it is disallowed from updating the DID Document, but it may [destroy](#destroy) it. + +::: + +### Example + +The following example demonstrates deactivating and reactivating an IOTA DID Document, +and optionally reclaiming the storage deposit. + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/3_deactivate_did.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/3_deactivate_did.ts +``` + + + + +## Destroy + +Alternatively, you can [destroy](../../references/specifications/iota-did-method-spec.mdx#destroy) an IOTA Identity can be permanently. + +:::warning Irreversible + +Destroying an IOTA Identity is permanent and irreversible. + +::: + + +This is achieved by the governor of a DID publishing a transaction consuming the [Alias Output](../../references/specifications/iota-did-method-spec.mdx#alias-output) +containing the IOTA DID Document, without a corresponding Alias Output on the output side. + +Any coins and tokens in the Alias Output are reclaimed and can be sent to another address. + +:::warning + +Note that historical versions may still be stored off-ledger, or on a permanode, +so sensitive or Personal Identifiable Information (PII) should NEVER be stored in a DID Document. + +::: + +Even with a previous version available, a destroyed DID can never be restored. + +### Example + +The following example demonstrates how a governor destroys an IOTA Identity and sends the storage deposit back to itself. + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/4_delete_did.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/4_delete_did.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/resolve.mdx b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/resolve.mdx new file mode 100644 index 00000000000..1e5411f592d --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/resolve.mdx @@ -0,0 +1,196 @@ +--- +title: Resolve an IOTA Identity +sidebar_label: Resolve +description: Explain how resolving works including arguments +image: /img/Identity_icon.png +tags: + - Resolve +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +DID resolution is the process of fetching and decoding a [DID Document](https://www.w3.org/TR/did-core/#dfn-did-documents) corresponding to a given [DID](https://www.w3.org/TR/did-core/#dfn-decentralized-identifiers). +The [IOTA Identity framework](https://github.com/iotaledger/identity.rs) supports resolving DID Documents that are +stored on the IOTA and Shimmer networks and enables users to plug in handlers for additional methods. + +This is similar to, but not to be confused with, +the [W3C DID Resolution specification](https://w3c-ccg.github.io/did-resolution/), +which defines function signatures for resolution in the context of web or REST APIs, +whereas the IOTA Identity framework provides strongly-typed resolution for a better developer experience. + +This functionality is primarily provided by the `Resolver`, which can: + +- [Resolve IOTA DID Documents](#resolving-an-iota-did). +- [Resolve DID Documents from multiple DID methods](#resolving-multiple-did-methods). +- Resolve the DID Documents referenced in a verifiable presentation or credential. + +## Resolving an IOTA DID + +The following examples demonstrate how to resolve an IOTA DID Document from its DID. + +### Resolver + +Once you have configured a `Resolver` with a [`Client`](/iota-sdk/welcome), it will resolve +IOTA DID Documents according to the read procedure defined in the [IOTA DID Method Specification](../../references/specifications/iota-did-method-spec.mdx#read). +It fetches the latest [Alias Output](../../references/specifications/iota-did-method-spec.mdx#alias-output) from the network specified in the DID (see [DID Format](../../references/specifications/iota-did-method-spec.mdx#did-format)), +then extracts and validates the DID Document from it. + + + + +```rust +use identity_iota::iota::IotaDID; +use identity_iota::iota::IotaDocument; +use identity_iota::resolver::Resolver; +use iota_sdk::client::Client; + +#[tokio::main] +async fn main() -> anyhow::Result<()>{ + // Configure a client for the Shimmer testnet "rms". + let node_url = "https://api.testnet.shimmer.network/"; + let client = Client::builder() + .with_primary_node(node_url, None)? + .finish()?; + + // Construct a resolver using the client. + let mut resolver = Resolver::::new(); + resolver.attach_iota_handler(client); + + // Parse the DID and resolve its DID Document. + let did = IotaDID::parse("did:iota:rms:0x7b48b06232b8a1e7a31c314cab1ceedb84e2e9dd2b1fae79b67eaa4595f15e47")?; + let document: IotaDocument = resolver.resolve(&did).await?; + + Ok(()) +} +``` + + + + +```js +const { + Resolver, + IotaDID, + IotaIdentityClient, +} = require('@iota/identity-wasm/node'); +const { Client } = require('@iota/client-wasm/node'); + +// Configure a client for the Shimmer testnet "rms". +const nodeUrl = 'https://api.testnet.shimmer.network/'; +const client = new Client({ + primaryNode: nodeUrl, + localPow: true, +}); +const didClient = new IotaIdentityClient(client); + +// Construct a resolver using the client. +const resolver = new Resolver({ + client: didClient, +}); + +// Resolve the given did +const did = + 'did:iota:rms:0x7b48b06232b8a1e7a31c314cab1ceedb84e2e9dd2b1fae79b67eaa4595f15e47'; +const document = await resolver.resolve(did); +``` + + + + +### Client + +You can also use the [`Client`](/iota-sdk/welcome) directly to resolve individual DIDs from its configured network. + + + + +```rust +use identity_iota::iota::IotaDID; +use identity_iota::iota::IotaDocument; +use identity_iota::iota::IotaIdentityClientExt; +use iota_sdk::client::Client; + +#[tokio::main] +async fn main() -> anyhow::Result<()>{ + // Configure a client for the Shimmer testnet "rms". + let node_url = "https://api.testnet.shimmer.network/"; + let client = Client::builder() + .with_primary_node(node_url, None)? + .finish()?; + + // Parse the DID and resolve its DID Document. + let did = IotaDID::parse("did:iota:rms:0x7b48b06232b8a1e7a31c314cab1ceedb84e2e9dd2b1fae79b67eaa4595f15e47")?; + let document: IotaDocument = client.resolve_did(&did).await?; + Ok(()) +} +``` + + + + +```js +const { IotaDID, IotaIdentityClient } = require('@iota/identity-wasm/node'); +const { Client } = require('@iota/client-wasm/node'); + +// Configure a client for the Shimmer testnet "rms". +const nodeUrl = 'https://api.testnet.shimmer.network/'; +const client = new Client({ + primaryNode: nodeUrl, + localPow: true, +}); +const didClient = new IotaIdentityClient(client); + +// Parse the DID and resolve its DID Document. +const did = IotaDID.parse( + 'did:iota:rms:0x7b48b06232b8a1e7a31c314cab1ceedb84e2e9dd2b1fae79b67eaa4595f15e47', +); +const document = await didClient.resolveDid(did); +``` + + + + +## Advanced Resolver Configuration + +You can configure the `Resolver` to support many use cases by attaching custom resolution handlers. +This enables the `Resolver` to resolve multiple DID methods, as well as customizing how +a particular DID method (such as the IOTA method) gets resolved. + +This feature is mainly intended to be used together with the Resolver's convenience methods for +handling [verifiable presentations](../verifiable-presentations/create-and-validate.mdx) +and [credentials](./../../explanations/verifiable-credentials.mdx). + +### Resolving Multiple DID Methods + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/5_custom_resolution.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/4_custom_resolution.ts +``` + + + + +## Resolution for Verifiable Presentations + +When validating [verifiable presentations](./../verifiable-presentations/create-and-validate.mdx), you need to +resolve the DID Documents of the [verifiable credential](./../../explanations/verifiable-credentials.mdx) issuers +and presentation holder to verify their signatures. + +Resolving the necessary DID Documents is +[performed automatically when verifying presentations via the `Resolver`](../verifiable-presentations/create-and-validate.mdx#example) + +When direct access to these DID Documents is desired, the `Resolver` also provides standalone methods to: + +- Resolve a presentation holder's DID Document. +- Resolve the DID Documents of the issuers of the credentials in a verifiable presentation. +- Resolve the issuer's DID Document for a given verifiable credential. diff --git a/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/update.mdx b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/update.mdx new file mode 100644 index 00000000000..13e4dc22034 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/decentralized-identifiers/update.mdx @@ -0,0 +1,534 @@ +--- +sidebar_label: Update +description: How DID Documents can be manipulated and how updates should be published +image: /img/Identity_icon.png +tags: + - Documents + - DID + - Tangle + - Update + - Publish +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Update DID Documents + +You can extend DID Documents by adding [verification methods](#verification-methods), [services](#services) and custom properties. +A verification method adds public keys, which can be used to digitally sign things like a DID message or a verifiable credential, +while a service can provide metadata around the identity via URIs. + +## Verification Methods + +As demonstrated by the [example](#example) below, the IOTA Identity framework offers easy-to-use methods for adding +[verification methods](https://www.w3.org/TR/did-core/#verification-methods). + +### Properties + +You can specify the following properties for a verification method: + +- **id**: A [DID URL](https://www.w3.org/TR/did-core/#did-url-syntax) for the verification method. You can specify it by setting the [fragment](https://www.w3.org/TR/did-core/#fragment). +- **type**: Specifies the type of the verification method. The framework supports `Ed25519` and `X25519` key types. This property is automatically filled by the framework when specifying the verification material. +- **publicKeyMultibase**: A multi-base encoded public key which concludes the [verification material](https://www.w3.org/TR/did-core/#verification-material). This can be automatically generated by the framework or manually provided by users. + +## Verification Relationships + +[Verification relationships](https://www.w3.org/TR/did-core/#verification-relationships) express the relationship between the DID subject and the verification method. +You can use it to specify the purpose of the verification method. + +### Relationships + +The Identity Framework supports the following relationships: + +- **[Authentication](https://www.w3.org/TR/did-core/#authentication)**: Used to specify authentication methods for the DID subject. +- **[Assertion](https://www.w3.org/TR/did-core/#assertion)**: Used to verify verifiable credentials. +- **[Key Agreement](https://www.w3.org/TR/did-core/#assertion)**: Used for establishing secure communication channels. +- **[Capability Invocation](https://www.w3.org/TR/did-core/#capability-invocation)**: Can be used to authorize updates to the DID Document. +- **[Capability Delegation](https://www.w3.org/TR/did-core/#capability-delegation)**: A mechanism to delegate cryptographic capability to another party. + +Verification methods can be either [embedded or referenced](https://www.w3.org/TR/did-core/#referring-to-verification-methods). Referencing verification +methods allows them to be used by more than one verification relationship. +When you create a verification method using the Identity Framework, specifying the `MethodScope` option will result in an embedded verification method. +Leaving that option unset will create the verification method as a map entry of the `verificationMethod` property. +You can also add verification relationships afterward using references. + +:::note + +Updates to the DID Document are done through a state transition of the [Alias Output](../../references/specifications/iota-did-method-spec.mdx#alias-output) by its state controller. +The public key or address of the state controller does not need to be a verification method in the DID Document, +since it is defined in the containing Alias Output. + +::: + +## Services + +[Services](https://www.w3.org/TR/did-core/#services) allow you to add other ways of communicating with the DID subject. +An endpoint included in the DID Document can offer a way of reaching services for different purposes +like authentication, communicating, and discovery. + +### Properties + +You can specify the following properties for a service: + +- **id**: A [DID URL](https://www.w3.org/TR/did-core/#did-url-syntax) for referencing the service in the DID document. You can specify it by setting the [fragment](https://www.w3.org/TR/did-core/#fragment). +- **type**: A string used to maximize interoperability between services. The framework does not perform any checks on the content of this string. +- **serviceEndpoint**: A URL that points to the service endpoint. + +## Create Identity + +Before you can update anything, you will need to [create an Identity](./create.mdx). + + + + +```rust + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder() + .with_primary_node(API_ENDPOINT, None)? + .finish() + .await?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password(Password::from("secure_password".to_owned())) + .build(random_stronghold_path())?, + ); + + // Create a new DID in an Alias Output for us to modify. + let storage: MemStorage = MemStorage::new(JwkMemStore::new(), KeyIdMemstore::new()); + let (_, document, fragment_1): (Address, IotaDocument, String) = + create_did(&client, &mut secret_manager, &storage).await?; + let did: IotaDID = document.id().clone(); + +``` + + + + +```js + const client = new Client({ + primaryNode: API_ENDPOINT, + localPow: true, + }); + const didClient = new IotaIdentityClient(client); + + // Generate a random mnemonic for our wallet. + const secretManager: MnemonicSecretManager = { + mnemonic: Utils.generateMnemonic(), + }; + + // Creates a new wallet and identity (see "0_create_did" example). + const storage: Storage = new Storage(new JwkMemStore(), new KeyIdMemStore()); + let { document, fragment } = await createDid( + client, + secretManager, + storage, + ); +``` + + + + +This creates and publishes an Alias Output containing a DID Document with one verification method. + +```json +{ + "doc": { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "verificationMethod": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "crv": "Ed25519", + "x": "475CGLtezvySFMCHhx6hE9S97MIYMLb4B-pbVEHaCtY" + } + } + ] + }, + "meta": { + "created": "2023-11-16T20:40:03Z", + "updated": "2023-11-16T20:40:03Z", + "governorAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd", + "stateControllerAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd" + } +} +``` + +## Add a Verification Method + + + + +```rust + // Insert a new Ed25519 verification method in the DID document. + let fragment_2: String = document + .generate_method( + &storage, + JwkMemStore::ED25519_KEY_TYPE, + JwsAlgorithm::EdDSA, + None, + MethodScope::VerificationMethod, + ) + .await?; +``` + + + + +```js + // Insert a new Ed25519 verification method in the DID document. + await document.generateMethod( + storage, + JwkMemStore.ed25519KeyType(), + JwsAlgorithm.EdDSA, + "#key-2", + MethodScope.VerificationMethod(), + ); +``` + + + + +This creates a new verification method that includes a newly generated Ed25519 public key. + +```json +{ + "doc": { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "verificationMethod": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "crv": "Ed25519", + "x": "475CGLtezvySFMCHhx6hE9S97MIYMLb4B-pbVEHaCtY" + } + }, + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "crv": "Ed25519", + "x": "h8ndZ4_Urmzf4xN4emqS8r5q4pAQvAh0k2YHq5JLBBo" + } + } + ] + }, + "meta": { + "created": "2023-11-16T20:40:03Z", + "updated": "2023-11-16T20:40:03Z", + "governorAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd", + "stateControllerAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd" + } +} +``` + +Notice that these changes to the document are not [published](#publish-your-updates) yet. + +## Add Verification Relationships + +You can attach verification relationships to a verification method by referencing its fragment. + + + + +```rust +// Attach a new method relationship to the inserted method. +document.attach_method_relationship( + &document.id().to_url().join(format!("#{fragment_2}"))?, + MethodRelationship::Authentication, +)?; +``` + + + + +```js +// Attach a new method relationship to the inserted method. +document.attach_method_relationship( + &document.id().to_url().join(format!("#{fragment_2}"))?, + MethodRelationship::Authentication, +)?; +``` + + + + +This will add `Authentication` relationship to the verification method with the fragment `key-1`. +Note that `Authentication` references the already included `key-2` verification method: + +```json {12,19} +{ + "doc": { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "verificationMethod": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "crv": "Ed25519", + "x": "475CGLtezvySFMCHhx6hE9S97MIYMLb4B-pbVEHaCtY" + } + }, + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "crv": "Ed25519", + "x": "h8ndZ4_Urmzf4xN4emqS8r5q4pAQvAh0k2YHq5JLBBo" + } + } + ], + "authentication": [ + "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE" + ] + }, + "meta": { + "created": "2023-11-16T20:40:03Z", + "updated": "2023-11-16T20:40:03Z", + "governorAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd", + "stateControllerAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd" + } +} +``` + +## Add a Service + +You can also add custom properties can to a service by setting `properties`: + + + + +```rust + // Add a new Service. + let service: Service = Service::from_json_value(json!({ + "id": document.id().to_url().join("#linked-domain")?, + "type": "LinkedDomains", + "serviceEndpoint": "https://iota.org/" + }))?; + assert!(document.insert_service(service).is_ok()); + document.metadata.updated = Some(Timestamp::now_utc()); +``` + + + + +```js + // Add a new Service. + const service: Service = new Service({ + id: did.join("#linked-domain"), + type: "LinkedDomains", + serviceEndpoint: "https://iota.org/", + }); + document.insertService(service); + document.setMetadataUpdated(Timestamp.nowUTC()); +``` + + + + +The updated Document with the newly created service looks as follows. + +```json {21-27} +{ + "doc": { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "verificationMethod": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "HZ11e0XacuODQw5FcoMHtcdxl8oXHbSnIhQMUgVzWBE", + "crv": "Ed25519", + "x": "475CGLtezvySFMCHhx6hE9S97MIYMLb4B-pbVEHaCtY" + } + }, + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "crv": "Ed25519", + "x": "h8ndZ4_Urmzf4xN4emqS8r5q4pAQvAh0k2YHq5JLBBo" + } + } + ], + "authentication": [ + "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE" + ], + "service": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#linked-domain", + "type": "LinkedDomains", + "serviceEndpoint": "https://iota.org/" + } + ] + }, + "meta": { + "created": "2023-11-16T20:40:03Z", + "updated": "2023-11-16T20:40:08Z", + "governorAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd", + "stateControllerAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd" + } +} +``` + +## Remove a Verification Method + +You can also remove verification methods at any time using the following snippet: + + + + +```rust +// Remove a verification method. +let original_method: DIDUrl = document.resolve_method(fragment_1.as_str(), None).unwrap().id().clone(); +document.purge_method(&storage, &original_method).await.unwrap(); +``` + + + + +```js +// Remove a verification method. +let originalMethod = document.resolveMethod(fragment) as VerificationMethod; +await document.purgeMethod(storage, originalMethod?.id()); +``` + + + + +This removes the original verification method with the fragment `key-1`. + +```json +{ + "doc": { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "verificationMethod": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "controller": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE", + "crv": "Ed25519", + "x": "h8ndZ4_Urmzf4xN4emqS8r5q4pAQvAh0k2YHq5JLBBo" + } + } + ], + "authentication": [ + "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#yJz-sPlCmd432JKqK_hkiPml2kj22Jv0aAFy_2jJ8nE" + ], + "service": [ + { + "id": "did:iota:tst:0x19ed80fbd2a644fc2347e27e46e09d42b89df9b1ba09ae41832a9d47d686776a#linked-domain", + "type": "LinkedDomains", + "serviceEndpoint": "https://iota.org/" + } + ] + }, + "meta": { + "created": "2023-11-16T20:40:03Z", + "updated": "2023-11-16T20:40:08Z", + "governorAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd", + "stateControllerAddress": "tst1qrjsnlg6nqd2kdzx4q880nl74jtrcajm7ae57zazl0l7ye09ahh4x6z9gtd" + } +} +``` + +## Publish Your Updates + +Publish the updated DID Document inside the Alias Output taking into account the increase in the storage deposit needed. + + + + +```rust + // Resolve the latest output and update it with the given document. + let alias_output: AliasOutput = client.update_did_output(document.clone()).await?; + + // Because the size of the DID document increased, we have to increase the allocated storage deposit. + // This increases the deposit amount to the new minimum. + let rent_structure: RentStructure = client.get_rent_structure().await?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) + .with_minimum_storage_deposit(rent_structure) + .finish()?; + + // Publish the updated Alias Output. + let updated: IotaDocument = client.publish_did_output(&secret_manager, alias_output).await?; +``` + + + + +```js + // Resolve the latest output and update it with the given document. + let aliasOutput: AliasOutput = await didClient.updateDidOutput(document); + + // Because the size of the DID document increased, we have to increase the allocated storage deposit. + // This increases the deposit amount to the new minimum. + const rentStructure: IRent = await didClient.getRentStructure(); + + aliasOutput = await client.buildAliasOutput({ + ...aliasOutput, + amount: Utils.computeStorageDeposit(aliasOutput, rentStructure), + aliasId: aliasOutput.getAliasId(), + unlockConditions: aliasOutput.getUnlockConditions(), + }); + + // Publish the output. + const updated: IotaDocument = await didClient.publishDidOutput(secretManager, aliasOutput); +``` + + + + +## Full Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/1_update_did.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/1_update_did.ts +``` + + + \ No newline at end of file diff --git a/docs/build/identity.rs/1.3/docs/how-tos/domain-linkage/create-and-verify.mdx b/docs/build/identity.rs/1.3/docs/how-tos/domain-linkage/create-and-verify.mdx new file mode 100644 index 00000000000..ef3a313e224 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/domain-linkage/create-and-verify.mdx @@ -0,0 +1,179 @@ +--- +description: How to link a domain and a DID +sidebar_label: Create and Verify +image: /img/Identity_icon.png +tags: + - well-known + - domain linkage + - DID Configuration Resource + - Domain Linkage Credential +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Domain Linkage + +:::info +To use Domain Linkage in Rust you have to enable the `domain-linkage` feature. +::: + +## Overview + +Domain Linkage can provide proof for a connection between a DID and a domain being controlled by the same entity. +This linkage can transfer trust from a domain to a DID and vice versa. +For instance, if an entity trusts a domain, it can also trust the linked DID and all documents signed by +the verification methods included in the DID Document. + +A use case could be a verifier that trusts `www.example.com`, and receives a verifiable presentation issued by `did:foo:abc`. +If `did:foo:abc` is linked to `www.example.com`, the verifier can trust that the verifiable presentation is issued by +the same entity controlling `www.example.com`. +The DIF has approved a [Well Known DID Configuration](https://identity.foundation/.well-known/resources/did-configuration/) draft to standardize this connection by introducing +the [DID Configuration Resource](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource) and the [Linked Domain Service Endpoint](https://identity.foundation/.well-known/resources/did-configuration/#linked-domain-service-endpoint). + +![Identity getting started](/img/domain-linkage-diagram.png) + +### DID Configuration Resource + +Suppose that a DID `did:foo:example` with the following DID Document only contains one `verificationMethod`, `key-1`: + +```json {5} +{ + "id": "did:foo:abc", + "verificationMethod": [ + { + "id": "did:foo:abc#key-1", + "controller": "did:foo:abc", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zDShpHKXkcHKHcF8CnGAA1UqyyuEPRNz1XFEuggbWJQSq" + } + ] + }, +``` + +The domain `https://www.example.com` represents the same entity and needs to be linked to increase trust in the DID. + +To establish this link, you must create a [DID Configuration Resource](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource), +and make it available on the [DID Configuration URL](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-uri). +In this case it's `https://example.com/.well-known/did-configuration.json`. + +The [DID Configuration Resource](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource) is a JSON-LD object containing verifiable credentials called `Domain Linkage Credentials`. +Each credential represents a linkage to a single DID. + +:::note + +Note that one `DID Configuration Resource` can include multiple `Domain Linkage Credentials`, +effectively linking the same domain to multiple DIDs. + +::: + +In this example, the domain `https://www.example.com` needs to be linked to the DID `did:foo:abc`. +This means that the `DID Configuration Resource` will have one `Domain Linkage Credential`. +This credential must have the following properties: + +- Its `type` includes `DomainLinkageCredential`. +- It includes the DID Configuration context. +- The `credentialSubject` must be the DID `did:foo:abc` and references the domain `https://www.example.com`. +- The issuer is the DID itself `did:foo:abc`. +- It is signed by a key material included in the DID Document, in this case `did:foo:abc#key-1`. + +```json +{ + "@context": "https://identity.foundation/.well-known/did-configuration/v1", + "linked_dids": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://identity.foundation/.well-known/did-configuration/v1" + ], + "type": ["VerifiableCredential", "DomainLinkageCredential"], + "credentialSubject": { + "id": "did:foo:abc", + "origin": "https://www.example.com/" + }, + "issuer": "did:foo:abc", + "issuanceDate": "2023-02-09T22:14:15Z", + "expirationDate": "2024-02-09T22:14:15Z", + "proof": { + "type": "JcsEd25519Signature2020", + "verificationMethod": "did:foo:abc#key-1", + "signatureValue": "4SvYqo3YoArfW7r7qKfN7RUJdZnBteb166KE4UkX8MNdbp5UW6YbykneAzvjyRmf5EVQ9bnP9cS5sbEPUn2uaAcB" + } + } + ] +} +``` + +Now this `DID Configuration Resource` must be made available on `https://example.com/.well-known/did-configuration.json`, +which establishes the linkage. + +### Linked Domain Service Endpoint + +By having a domain, one can discover what DIDs are linked to it by fetching the `DID Configuration Resource` and +investigating the `Domain Linkage Credentials`. + +If you want to enable discovery from the other direction, that is, if you have a DID and want to discover which +domains are linked to it, you can add a [Linked Domain Service Endpoint](https://identity.foundation/.well-known/resources/did-configuration/#linked-domain-service-endpoint) to the DID Document. +The DID Document from this example will be extended as follows to enable discovery of `https://www.example.com`: + +```json {11-17} +{ + "id": "did:foo:abc", + "verificationMethod": [ + { + "id": "did:foo:abc#key-1", + "controller": "did:foo:abc", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zDShpHKXkcHKHcF8CnGAA1UqyyuEPRNz1XFEuggbWJQSq" + } + ], + "service": [ + { + "id": "did:foo:abc#domain-linkage", + "type": "LinkedDomains", + "serviceEndpoint": "https://www.example.com/" + } + ] +} +``` + +:::note +Note that a DID Document can have multiple `Linked Domain Services` and each service can link to multiple domains. +::: + +### Verifying a DID and Domain Linkage + +As mentioned above, you can discover the Domain Linkage from either direction. +However, verifying the linkage in both cases involves only verifying the DID Configuration Resource. +The process is as follows: + +1. Fetch `DID Configuration Resource` from `https://www.example.com/.well-known/did-configuration.json`. +2. Resolve the DID Document of `did:foo:abc`. +3. Verify the `DID Configuration Resource` and its `Domain Linkage Credential` that references `did:foo:abc`. + + +:::tip About DID Configuration Resource Verification + +You can learn more +[about DID Configuration Resource Verification on the Identity Foundation website](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource-verification). + +::: + +## Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/6_domain_linkage.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/5_domain_linkage.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/key-storage.mdx b/docs/build/identity.rs/1.3/docs/how-tos/key-storage.mdx new file mode 100644 index 00000000000..5d76d6dcaa9 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/key-storage.mdx @@ -0,0 +1,152 @@ +--- +title: Key Storage +sidebar_label: Key Storage +description: Explain the use of the storage interfaces and how they can be implemented +image: /img/Identity_icon.png +tags: + - key storage + - storage interfaces + - json web key + - json web algorithm + - signing +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Introduction + +The `JwkDocumentExt` API allows you to modify a DID document, for example, adding new verification methods. +It enables storing the secrets that verification methods represent securely. +It does so using the two storage interfaces, the `JwkStorage` and `KeyIdStorage`. +We refer to both of these as the **key storage**. + +The main idea behind the key storage is strongly inspired by the architecture of key management systems (KMS) +or secure enclaves: once private keys are entered into the system, they can never be retrieved again. +Instead, all operations using the key will have to go through that system. + +This approach allows the key storage to be architected more securely than simply storing and loading private keys from +a regular database. +Of course, security is directly dependent on the concrete implementation, +which is why we provide [Stronghold](https://github.com/iotaledger/stronghold.rs/), a best-effort in-software enclave, by default. + +However, there are cases where one cannot use `Stronghold`, +or may want to integrate key management of identities into their own KMS or similar, +which is why the key storage is an abstraction over such systems. +Any implementation of a key storage can be used by the `JwkDocumentExt` API. + +The two interfaces making up the key storage have two respective responsibilities. + +:::info + +Even though there are two separate interfaces, you can implement them using the same backing storage. + +::: + +## Function Overview + +A brief overview of those functions: + +- `JwkStorage`: CRUD and signing operations on [JSON Web Keys](https://www.rfc-editor.org/rfc/rfc7517). + - `generate`: Generate a new key represented as a JSON Web Key. + - `insert`: Insert an existing JSON Web Key into the storage. + - `sign`: Signs the provided data using the stored private key. + - `delete`: Permanently deletes a key. + - `exists`: Returns whether a key exists. +- `KeyIdStorage`: Stores the mappings from verification methods to their corresponding key identifier in the `JwkStorage`. + - `insert_key_id`: Inserts a mapping from a verification method identifier to a key identifier. + - `get_key_id`: Returns the key identifier for a given verification method identifier. + - `delete_key_id`: Deletes a mapping. + +## Key Identifier + +A `JwkStorage` stores and operates on keys, so they must be identified. +In general, Key Management Systems use some form of an identifier for their keys. +To abstract over those, the `JwkStorage` interface has a general-purpose `KeyId` type, +which is effectively a wrapper around a string. + +A `KeyIdStorage` is needed to store the key id that represents the private key for a given verification method. +To that end, a verification method itself must be identified. + +While within a document, each fragment must be unique, the same is not true given multiple documents, +so we cannot rely only on fragments if we don't want to partition the `KeyIdStorage` by DID. +The solution to this is using a `MethodDigest`, a hash over a verification method. + +When following best security practices, each verification method has its own associated key and, thus, a unique public key. +That, plus the fragment of a method, ensures the `MethodDigest` is unique. + +So, in essence, a `JwkStorage` stores a `KeyId -> JWK` mapping while a `KeyIdStorage` stores a `MethodDigest -> KeyId` mapping. + +:::caution + +Given the construction and limitations of the method digest, +no two documents should contain a method that shares both the same fragment and public key. +This should not happen under typical circumstances, but it is good to keep it in mind. + +::: + +## Key Types + +To express what key types a given `JwkStorage` implementation supports, you should use the `KeyType`, +which is another simple wrapper around a string. + +The reason for this design might seem odd in Rust, given the existence of associated types. +This more simplistic design is necessary to accommodate implementing the interface via the bindings to the library. + +Implementations are expected to export constants of the key types they support, +so users have an easy way to discover the supported types. +In general, storage implementations are free to support any [JSON Web Algorithm](https://www.rfc-editor.org/rfc/rfc7518.html)-compatible key. +However, the recommended default used by IOTA Identity is the `EdDSA` algorithm with curve `Ed25519`. + +## Implementation + +The IOTA Identity library ships two implementations of key storage. +The `JwkMemStore` and `KeyIdMemstore` are insecure in-memory implementations +intended as example implementations and for testing. + +The default key storage implementation is `Stronghold`, +which is an example of a storage that implements both storage interfaces simultaneously. +[`Stronghold`](https://github.com/iotaledger/stronghold.rs/) may be interesting for implementers to look at, +as it needs to deal with some challenges the in-memory version does not have to deal with. Note that the `Stronghold` implementation is only available in Rust. + +## Examples + +This section shows the Rust and TypeScript `Memstore` implementations. + +### `JwkMemStore` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/lib/jwk_storage.ts +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/identity_storage/src/key_storage/memstore.rs +``` + + + + +### `KeyIdMemstore` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/lib/key_id_storage.ts +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/identity_storage/src/key_id_storage/memstore.rs +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/create.mdx b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/create.mdx new file mode 100644 index 00000000000..4598ecac57b --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/create.mdx @@ -0,0 +1,141 @@ +--- +title: Create a Verifiable Credential +sidebar_label: Create and Sign +description: Explain how a VC is created and verified +image: /img/Identity_icon.png +tags: + - verifiable + - credentials + - Create + - sign +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +A [Verifiable Credential (VC)](./../../explanations/verifiable-credentials.mdx) can represent all +information that a physical credential represents, such as a passport or university +degree. However, by allowing other parties to cryptographically verify the authorship +and integrity of the claims, verifiable credentials can be seen as more tamper-evident +and more trustworthy than their physical counterparts. + +## Verifiable Credential Properties + +In the IOTA Identity Framework, you can create a Verifiable Credential with the following properties: + +- [**Context**](https://www.w3.org/TR/vc-data-model/#contexts): List of JSON-LD context URIs. Includes `"https://www.w3.org/2018/credentials/v1"` by default. +- [**Types**](https://www.w3.org/TR/vc-data-model/#types): List of types describing the credential. Includes `"VerifiableCredential"` by default. +- [**Subject**](https://www.w3.org/TR/vc-data-model/#credential-subject): The issuer's claims; a set of objects that contain one or more properties that are each related to a subject. +- [**Issuer**](https://www.w3.org/TR/vc-data-model/#issuer): The identifier of the issuer, typically their [DID](../../explanations/decentralized-identifiers.mdx). +- [**ID**](https://www.w3.org/TR/vc-data-model/#identifiers): Optional URI identifier for the credential. +- [**Issuance Date**](https://www.w3.org/TR/vc-data-model/#issuance-date): Timestamp for expressing the date and time when a credential becomes valid. +- [**Expiration Date**](https://www.w3.org/TR/vc-data-model/#expiration): Optional timestamp for expressing the date and time when a credential ceases to be valid. +- [**Status**](https://www.w3.org/TR/vc-data-model/#status): Optional information used to determine the current status of a credential, i.e. whether or not it has been [revoked](./revocation.mdx). +- [**Schema**](https://www.w3.org/TR/vc-data-model/#data-schemas): Optional list of objects specifying the schema that the data must conform to. +- [**Refresh Service**](https://www.w3.org/TR/vc-data-model/#refreshing): Optional link to a service where the recipient may refresh the included credentials. +- [**Terms of Use**](https://www.w3.org/TR/vc-data-model/#terms-of-use): Optional list of policies defining obligations, prohibitions, or permissions of the presentation recipient. +- [**Evidence**](https://www.w3.org/TR/vc-data-model/#evidence): Optional list of objects that can be used by the issuer to provide the verifier with additional supporting information in a verifiable credential. +- [**Non-Transferable**](https://www.w3.org/TR/vc-data-model/#nontransferable-property): Optional flag that indicates that a verifiable credential must only be encapsulated in a [verifiable presentation](./../../explanations/verifiable-presentations.mdx) whose proof was issued by the credential subject. + + + + +## Signing {#signing} + +After preparing the verifiable credential, the issuer creates a signed JWT containing VC in the claims using one of their private keys. This is what allows verifiers to validate the credential independently using the corresponding public key from the issuer's DID Document. + +## Validation + +Verifiers should ensure certain credential properties are valid when receiving one or more in a [verifiable presentation](./../../explanations/verifiable-presentations.mdx). Both issuers and holders may also wish to validate their credentials, particularly directly after creating or receiving one. Validation may be performed at any point in time and can be a useful way of checking whether a credential has expired or been revoked. + +### Validation Checks + +The IOTA Identity Framework supports the following checks during credential validation: + +- **Semantic structure**: Ensures the credential adheres to the specification. +- **Signature**: Verifies the JWS against the issuer's DID Document. +- **Optional validations**: Additional checks on credential properties, and the signature can be configured by specifying [Validation Options](#validation-options). + +### Validation Options + +These options specify conditions that specific properties in a credential must satisfy. + +- **Expiration Date**: Check that the [`expirationDate`](https://www.w3.org/TR/vc-data-model/#expiration) property, if present, is not before a specific date-time. Defaults to the current datetime if unset. +- **Issuance Date**: Check that [`issuanceDate`](https://www.w3.org/TR/vc-data-model/#issuance-date) property, if present, is not after a specific date-time. Defaults to the current datetime if unset. +- **Verifier Options**: Validates aspects of the credential signature. + +## Sharing Verifiable Credentials + +A [verifiable presentation](./../../explanations/verifiable-presentations.mdx) is the recommended data format for sharing one or more verifiable credentials, +as it provides cryptographic means of proving the DID of the holder presenting them, +and for enforcing [subject-holder relationships](https://www.w3.org/TR/vc-data-model/#subject-holder-relationships). + +## Example + +The following code showcases how an issuer can [create, sign](#create-and-sign-vc), +and [validate](#validate-a-vc) a verifiable credential. +In this example, the issuer signs a `UniversityDegreeCredential` with Alice's name and DID. + +### Create and Sign a VC + + +
+ + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/5_create_vc.rs#L67-L98 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/5_create_vc.ts#L51-L74 +``` + + + +
+ +### Validate a VC + +
+ + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/5_create_vc.rs#L105-L113 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/5_create_vc.ts#L83-L88 +``` + + + +
+ +This Verifiable Credential can be [verified by anyone](./../../explanations/verifiable-presentations.mdx), +allowing Alice to take control of it and share it with anyone. + +### Full Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/5_create_vc.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/5_create_vc.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/revocation.mdx b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/revocation.mdx new file mode 100644 index 00000000000..2e7c35e497d --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/revocation.mdx @@ -0,0 +1,208 @@ +--- +sidebar_label: Revoke +description: Explain how a VC can be revoked +image: /img/Identity_icon.png +tags: + - verifiable + - credentials + - revoke + - revocation +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Revoke a Verifiable Credential + +The [example](#example) below demonstrates two methods that an issuer can use to revoke a verifiable credential +using the IOTA Identity Framework: + +1. By using the [`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) field in a credential and linking +to a [revocation method](#revocation-methods). +2. By [removing the verification method](#removing-the-verification-method) that signed the credential. +This invalidates all credentials that were signed with that verification method. + +## Revocation methods +The IOTA Identity Framework supports two different revocation methods: `RevocationBitmap2022` and `StatusList2021`. +### Revocation Bitmap +[RevocationBitmap2022](../../references/specifications/revocation-bitmap-2022.mdx) is the default credential revocation method used in the IOTA Identity Framework. It allows +issuers to control whether a credential is _valid_ or _revoked_. To do so, a revocation list (represented +as a bitmap) is stored in the issuer's DID document. +When a credential is issued, a unique index from the issuer's revocation list +is chosen, linking the credential's status to the value of the list entry. To change the status of a credential, the issuer +simply updates the corresponding entry in its revocation list. + +With `RevocationBitmap2022` the `identity.rs` library completely handles the processes required to handle credentials revocation; +from creation and storage of the revocation list to its lookup. +This makes `RevocationBitmap2022` the preferred way for users to handle credential revocation, but it requires sufficient +funds to rent out the required on-tangle space. + +:::note + +DLT's size constraints limit the size of the revocation list. With the assumption of only one such revocation list +per the issuer's DID document, one may expect to be able to handle roughly 50k entries. + +::: + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/7_revoke_vc.rs#L167 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts#L156 +``` + + + + +If the binary value of the index in the bitmap is 1 (one), the verifiable credential is revoked, +if it is 0 (zero) it is not revoked. + +For example, with this approach the issuer adds an index to a credential in the `credentialStatus` field, such as `"5"`. +This part of the credential might then look like this: + +```json +"credentialStatus": { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#revocation", + "type": "RevocationBitmap2022", + "revocationBitmapIndex": "5" +}, +``` + +The verifier uses the `id` field (`did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#revocation`) to look up the +service in the issuer's DID document: + +```json +{ + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#revocation", + "type": "RevocationBitmap2022", + "serviceEndpoint": "data:application/octet-stream;base64,ZUp5ek1tQmdZR1NBQUFFZ1ptVUFBQWZPQUlF" +} +``` + +During verification, the verifier decodes the revocation bitmap embedded in the `data` URL. +This bitmap written as a bitstring looks like this: `000001`. +Here, the 5th bit is set, which means the credential with that index is revoked, +while all other credentials aren't revoked. + +### StatusList2021 +[StatusList2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427) offers similar functionalities to `RevocationBitmap2022` +but in a more flexible and scalable way. +The main difference is that `StatusList2021` is completely agnostic in regards to how the issuer's status list +is stored and fetched, as long as its location can be encoded through a URL. For instance, the status list +can be made available over HTTP (e.g. `https://example.com/credentials/status`) or through the +Interplanetary File System (e.g. `ipfs://QmXDWGdVBhbDoXXzKNMhJk5ejnZgxpMBVzW4EhQaHPD3Mi`). + +This flexibility, although it requires the issuer to manually fetch and update its status list, allows for an arbitrary number of +entries in the status list, in contrast with `RevocationBitmap2022`, where the length of the list is limited by the DLT's constraints. + +Furthermore, `StatusList2021` introduces a new credential state: _suspended_. Suspended credentials are credentials that a validator will not accept as _valid_, but that might become valid again in the future. Instead, _revoked_ credentials **cannot** ever +be valid again, as the _revoked_ state is irreversible. + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/8_status_list_2021.rs#L86-L90 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts#L72-L76 +``` + + + + +First, an issuer creates a credential that encodes a certain status list, specifying its purpose (either `revocation` or `suspension`) +and the location at which it will be available (`https://example.com/credentials/status` in this case). After creation, the issuer +must make the credential available at the chosen URL so that verifiers can fetch it. + +Upon issuing a credential, to revoke it or suspend it later, the issuer sets the `credentialStatus` field, linking +to an entry in its status list. The snippet below shows what `credentialStatus` would look like when linking to the previously created +status list credential. + +```json +{ + "id": "https://example.com/credentials/status#94567", + "type": "StatusList2021Entry", + "statusPurpose": "revocation", + "statusListIndex": "94567", + "statusListCredential": "https://example.com/credentials/status" +} +``` + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/8_status_list_2021.rs#L173 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts#L147 +``` + + + + +To set the status of a credential, the issuer retrieves the status list credential and sets the value of the chosen entry index. + +## Removing the Verification Method + +A less efficient alternative is to remove the verification method that signed the credential from the DID Document of +the issuer. +This means the VC can no longer be validated. + +However, this will also invalidate every VC signed with that verification method, +meaning that the issuer will have to sign every VC with a different key to retain +precise control over which credential is revoked. + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/7_revoke_vc.rs#L197-L204 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts#L192C1-L195 +``` + + + + +## Full Example Code + +The following code exemplifies how you can revoke a [Verifiable Credential (VC)](../../explanations/verifiable-credentials.mdx). + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/7_revoke_vc.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/selective-disclosure.mdx b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/selective-disclosure.mdx new file mode 100644 index 00000000000..7b816429c09 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/selective-disclosure.mdx @@ -0,0 +1,141 @@ +--- +sidebar_label: Selective Disclosure +description: Explain VC with selective disclosure. +image: /img/Identity_icon.png +tags: + - verifiable + - credentials + - SD-JWT + - Disclosure +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Selective Disclosure (SD-JWT) + + +Holders of verifiable credentials may prefer to keep all the information contained within the credential private from a verifier. Instead, they may opt only to share a specific subset of the properties included in the VC. The identity library implements the [IETF Specifications](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html), which outlines a mechanism to enable the selective disclosure of individual properties within the JSON object of JWT claims. + +## Concept + +### Issuance + +During the issuance process, the issuer replaces a subset of the fields in a credential with digests of their salted values and creates a signed JWT. Next, JWT, alongside the plain text disclosures and the salt used for digest creation are sent to the holder. + +### Presentation + +At this stage, the holder can selectively choose which fields to disclose to the verifier. The disclosures are sent in plain text, with the JWT containing the digests to the verifier. + +:::note +Only values replaced by digests through the issuer can be selectively disclosed. The holder **can not** conceal values provided in plain text in the JWT claims. +::: + + +### Validation + +With these values and a valid signature, the verifier is able to reconstruct a Verified Credential (VC) that exclusively contains the information the holder intended to disclose. + +## How It Works + +A SD JWT can be constructed from the following JWT claim of an address credential in accordance with the [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token): + + +```json +{ + "iss": "did:iota:tst:0x899d07a766f93c2af1a19a3f4583ad338fc94c5d84b6afcadf49b197e1cb693e", + "jti": "https://example.com/credentials/3732", + "nbf": 1705925652, + "sub": "did:iota:tst:0x6c045e1f658197b432cfc7c66350b8781dca50f820e9de0fcdf0029b4b384355", + "vc": { + "@context": "https://www.w3.org/2018/credentials/v1", + "credentialSubject": { + "address": { + "country": "DE", + "locality": "Maxstadt", + "postal_code": "12344", + "street_address": "Weidenstraße 22" + }, + "name": "Alice" + }, + "type": [ + "VerifiableCredential", + "AddressCredential" + ] + } +} + +``` + +The issuer makes the values of "locality", "postal_code", and "street_address" selectively disclosable, giving the holder the freedom to select what details of the address to be disclosed and presented. + +```json +{ + "_sd_alg": "sha-256", + "iss": "did:iota:tst:0x899d07a766f93c2af1a19a3f4583ad338fc94c5d84b6afcadf49b197e1cb693e", + "jti": "https://example.com/credentials/3732", + "nbf": 1705925652, + "sub": "did:iota:tst:0x6c045e1f658197b432cfc7c66350b8781dca50f820e9de0fcdf0029b4b384355", + "vc": { + "@context": "https://www.w3.org/2018/credentials/v1", + "credentialSubject": { + "address": { + "_sd": [ + "8Dai0-GMZgkzmdryGzjYufUaRFkiNWzVsJJdWucwu84", + "jemTNaG_wiHauwmwWiWREsirAlr91qugPds4MA8e2xo", + "iakC9Dfe2r9fGnOaAr_pGg1b7CwITBjcwE7-O7WlMnY" + ], + "country": "DE" + }, + "name": "Alice" + }, + "type": [ + "VerifiableCredential", + "AddressCredential" + ] + } +} +``` + +:::note +The digests are contained in the `_sd` property in `address`. This allows both keys and values to be concealed. +::: + +For further details, see the [example](#full-example-code) below and the [sd-jwt-payload crate](https://github.com/iotaledger/sd-jwt-payload). + +## Presentation format + +The SD-JWT is presented in the following [format](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#section-5): + +> `~~~...~~` + +## Key Binding JWT + +When a verifier receives an SD-JWT, it may be desirable to verify that the presenter's identity matches the holder of the Credential. For that purpose, a [Key Binding JWT (KB-JWT)](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#section-4.3) can be used. + + +- The verifier sends a nonce to the holder. +- The holder creates a JWT containing the nonce and the digest of the issuer-signed JWT and the disclosures 1→N. +- The holder sends the KB-JWT to the verifier as a part of the presentation. +- By verifying the KB-JWT, the verifier ensures the identity of the holder, the integrity of the data, the freshness of the signature, and the intended audience. + + + +## Full Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/7_sd_jwt.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/zero-knowledge-selective-disclosure.mdx b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/zero-knowledge-selective-disclosure.mdx new file mode 100644 index 00000000000..e11ad510239 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-credentials/zero-knowledge-selective-disclosure.mdx @@ -0,0 +1,151 @@ +--- +sidebar_label: Zero Knowledge Selective Disclosure +description: Zero Knowledge selectively disclosable VCs. +image: /img/Identity_icon.png +tags: + - verifiable + - credentials + - Zero Knowledge + - Disclosure +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Zero Knowledge Selective Disclosure (ZK-SD-VCs) +ZK-SD-VCs allow holders to verify their VCs without having to disclose the entire VC's claim set to verifiers. +This is done through the creation of a Zero Knowledge Proof (ZKP) that guarantees the integrity and authenticity +of the VC, even when only partially disclosed to the verifier. + +:::note +Although ZK-SD-VCs offer similar functionalities to [SD-JWT VCs](../selective-disclosure) - at least on a high level - they rely on completely different +concepts and security concerns. For a user, the most notable difference is the shifted capability of choosing which fields can +be concealed from a verifier. For ZK-SD-VCs it's the holder that has total control over which parts of the credential can be +undisclosed, whereas for SD-JWT VCs it's the issuer that decides which fields may be concealed by the holder. +::: + +## Concepts +### Issuance +The issuer of a ZK-SD-VC creates the credential, signs it using the [BBS+](https://www.ietf.org/archive/id/draft-irtf-cfrg-bbs-signatures-05.html) signature scheme +and sends both the credential and the signature to the holder. To facilitate this process, the credential is first encoded +as a [JSON Proof Token](https://www.ietf.org/archive/id/draft-ietf-jose-json-proof-token-02.html) (JPT), which is then used as the payload of a +[JSON Web Proof](https://www.ietf.org/archive/id/draft-ietf-jose-json-web-proof-02.html) (JWP) and sent to the holder as JPT. +:::note +JWPs and JPTs can be reasoned about as the Zero Knowledge (ZK) based counterparts of JWSs and JWTs. +::: +In code, this process would look like the following snippet: + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/9_zkp.rs#L114-L141 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/8_zkp.ts#L109-L133 +``` + + + + + +Note how the VC issuer makes no prescription whatsoever regarding the disclosability of the VC's fields. + +### Holder presentation + +Once the holder receives a presentation challenge from a verifier, they construct a selective disclosure presentation for the requested credential +and send it back for verification. For this process the JWP in possession of the holder undergoes a transformation that allows the holder +to conceal any fields from the credentials claims through the creation of a Zero Knowledge Proof (ZKP) of the issuer's signature and becomes a _presented JWP_. +The proof value depends on the selected [JSON Proof Algorithm](https://www.ietf.org/archive/id/draft-ietf-jose-json-proof-algorithms-02.html) (JPA). + + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/9_zkp.rs#L197-L223 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/8_zkp.ts#L178-L199 +``` + + + + +Here's an example presented JWP in its JPT JSON serialization format where the undisclosed values are replaced by `null`: +``` +{ + "payloads": [ + null, + "IkpheSI", + null, + "NDI" + ], + "issuer": "eyJpc3MiOiJodHRwczovL2lzc3Vlci50bGQiLCJjbGFpbXMiOlsiZmFt + aWx5X25hbWUiLCJnaXZlbl9uYW1lIiwiZW1haWwiLCJhZ2UiXSwidHlwIjoiSlBUIiw + icHJvb2ZfandrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiYWNiSVFpdU + 1zM2k4X3VzekVqSjJ0cFR0Uk00RVUzeXo5MVBINkNkSDJWMCIsInkiOiJfS2N5TGo5d + ldNcHRubUt0bTQ2R3FEejh3Zjc0STVMS2dybDJHekgzblNFIn0sInByZXNlbnRhdGlv + bl9qd2siOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJvQjFUUHJFX1FKSUw + 2MWZVT09LNURwS2dkOGoyemJaSnRxcElMRFRKWDZJIiwieSI6IjNKcW5ya3VjTG9ia2 + RSdU9xWlhPUDlNTWxiRnllbkZPTHlHbEctRlBBQ00ifSwiYWxnIjoiU1UtRVMyNTYif + Q", + "proof": "LJMiN6caEqShMJ5jPNts8OescqNq5vKSqkfAdSuGJA1GyJyyrfjkpAG0c + DJKZoUgomHu5MzYhTUsa0YRXVBnMB91RjonrnWVsakfXtfm2h7gHxA_8G1wkB09x09k + on2eK9gTv4iKw4GP6Rh02PEIAVAvnhtuiShMnPqVw1tCBdhweWzjyxJbG86J7Y8MDt2 + H9f5hhHIwmSLwXYzCbD37WmvUEQ2_6whgAYB5ugSQN3BjXEviCA__VX3lbhH1RVc27E + YkRHdRgGQwWNtuExKz7OmwH8oWizplEtjWJ5WIlJpee79gQ9HTa2QIOT9bUDvjjkkO- + jK_zuDjZwh5MkrcaQ", + "presentation": "eyJub25jZSI6InVURUIzNzFsMXB6V0psN2FmQjB3aTBIV1VOaz + FMZS1iQ29tRkx4YThLLXMifQ" +} +``` + +### Verification + +The verifier decodes the received JPT presentation and asserts the validity of the ZKP it contains, thus proving the +authenticity and integrity of the presented credential, without knowledge of any of the undisclosed fields and of the issuer signature. + + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/9_zkp.rs#L244-L257 +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/8_zkp.ts#L217-L225 +``` + + + + +## Full Example Code + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/1_advanced/9_zkp.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/1_advanced/8_zkp.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/how-tos/verifiable-presentations/create-and-validate.mdx b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-presentations/create-and-validate.mdx new file mode 100644 index 00000000000..4bf74231f28 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/how-tos/verifiable-presentations/create-and-validate.mdx @@ -0,0 +1,116 @@ +--- +sidebar_label: Create and Validate +description: Explain how a VP is created and verified +image: /img/Identity_icon.png +tags: + - verifiable + - presentations +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Create and Validate Verifiable Presentations + +The IOTA Identity Framework enables holders to easily construct +[verifiable presentations](./../../explanations/verifiable-presentations.mdx). +As demonstrated in the [example](#example-code), +holders only need to pass in their credentials to create a JWT presentation. + +## Properties + +You can specify the following properties in a presentation: + +- [**ID**](https://www.w3.org/TR/vc-data-model/#identifiers): Optional URI identifier for the presentation. +- [**Context**](https://www.w3.org/TR/vc-data-model/#contexts): List of JSON-LD context URIs. Includes `"https://www.w3.org/2018/credentials/v1"` by default. +- [**Types**](https://www.w3.org/TR/vc-data-model/#types): List of types describing the presentation. Includes `"VerifiablePresentation"` by default. +- [**Credentials**](https://www.w3.org/TR/vc-data-model/#dfn-verifiable-credentials): List of verifiable credentials to present. +- [**Holder**](https://www.w3.org/TR/vc-data-model/#dfn-holders): Optional URI, typically a DID, of the entity that generated the presentation. +- [**Refresh Service**](https://www.w3.org/TR/vc-data-model/#refreshing): Optional link to a service where the recipient may refresh the included credentials. +- [**Terms of Use**](https://www.w3.org/TR/vc-data-model/#terms-of-use): Optional list of policies defining obligations, prohibitions, or permissions of the presentation recipient. + +Of the above, **only the list of credentials is required** when creating a presentation using the framework. +However, the holder property should be included to satisfy [subject-holder relationship](#subject-holder-relationship) checks during validation. + +After creation, the holder signs the verifiable presentation using a private key linked to one of the verification +methods in their DID Document and transmits it to a verifier for validation. + +## Creation and Validation + +A Verifiable Presentation can be issued as a JWT that provides data integrity, +and also proves the [DID](../../explanations/decentralized-identifiers.mdx) of the holder. + +:::note + +Verifiers should always send a challenge +to [mitigate replay attacks](./../../explanations/verifiable-presentations.mdx#security-considerations). +::: + + +The IOTA Identity Framework provides several options for verifiers to validate various sections of a verifiable presentation. +See the [example](#example-code) for a demonstration of how to validate a presentation. + +The framework checks: + +- **Semantic structure**: Ensures the presentation and its credentials adhere to the specification. +- **Presentation proof**: Verifies the presentation signature against the holder's DID document. +- **Credential proofs**: Verifies the credential signatures against the DID Documents of their respective issuers. + + +Currently, the following are **not** checked automatically: + +- **Data schemas**: Credentials that specify a [schema](https://www.w3.org/TR/vc-data-model/#data-schemas) property +should be examined to ensure conformance. +- **Fitness for purpose**: Whether the credentials in a presentation and the data within them are acceptable and +valid depends on the context in which they are used. Verifiers should ensure that the credential types, subjects, +and schemas sent by a holder match what was requested. +- **Issuer trustworthiness**: Verifiers must check that they trust the issuer on each individual credential in a +presentation. The framework only verifies that the issuer's signature on each credential is current and valid +against the given options. + +The default validation behavior may be modified by the following options. + +## Subject-Holder Relationship + +Specifies the expected relationship between the holder that signed the verifiable presentation and the subject +specified in each [verifiable credential](./../../explanations/verifiable-credentials.mdx). +This can be restricted by the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property, +which indicates that a verifiable credential must only be encapsulated into a verifiable presentation whose holder matches the credential subject. + +By default, the framework always enforces that the holder matches the subject. + +The following options are available to modify that behavior: + +- **`AlwaysSubject` (default)**: The holder DID that signed the presentation must match the [`credentialSubject` `id`](https://www.w3.org/TR/vc-data-model/#credential-subject) field in each of the attached credentials. This is the safest option which ensures holders may only present credentials that were directly issued to their DID. An error is thrown on a mismatch or if no subject `id` is present. +- **`SubjectOnNonTransferable`**: The holder DID must match the subject only for credentials where the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property is `true`. This is appropriate for accepting [bearer credentials](https://www.w3.org/TR/vc-data-model/#bearer-credentials) while still adhering to the specification. +- **`Any`**: The holder DID is not required to have any kind of relationship to any credential subject. This option performs no checks and ignores the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property. + +:::note + +See the [Verifiable Credentials Data Model Specification](https://www.w3.org/TR/vc-data-model/#subject-holder-relationships) +for further discussion on the different subject-holder relationships. + +::: + + +## Example Code + +The following code demonstrates how to use the IOTA Identity Framework end-to-end to create and sign a verifiable +presentation as a holder, serialize it to JSON for transmission, deserialize it on the receiving side as a verifier, +and finally validate it with various options. + + + + +```rust reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/examples/0_basic/6_create_vp.rs +``` + + + + +```ts reference +https://github.com/iotaledger/identity.rs/blob/v1.3.0/bindings/wasm/examples/src/0_basic/6_create_vp.ts +``` + + + diff --git a/docs/build/identity.rs/1.3/docs/references/api/wasm.mdx b/docs/build/identity.rs/1.3/docs/references/api/wasm.mdx new file mode 100644 index 00000000000..48885d9e986 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/references/api/wasm.mdx @@ -0,0 +1,7684 @@ +--- +title: WASM API Reference +description: WASM API reference. +image: /img/Identity_icon.png +tags: + - WASM + - API Reference +--- +# Wasm Api Reference + +## Classes + +
+
CoreDID
+

A method-agnostic Decentralized Identifier (DID).

+
+
CoreDocument
+

A method-agnostic DID Document.

+

Note: All methods that involve reading from this class may potentially raise an error +if the object is being concurrently modified.

+
+
Credential
+
+
CustomMethodData
+

A custom verification method data format.

+
+
DIDUrl
+

A method agnostic DID Url.

+
+
DecodedJptCredential
+
+
DecodedJptPresentation
+
+
DecodedJws
+

A cryptographically verified decoded token from a JWS.

+

Contains the decoded headers and the raw claims.

+
+
DecodedJwtCredential
+

A cryptographically verified and decoded Credential.

+

Note that having an instance of this type only means the JWS it was constructed from was verified. +It does not imply anything about a potentially present proof property on the credential itself.

+
+
DecodedJwtPresentation
+

A cryptographically verified and decoded presentation.

+

Note that having an instance of this type only means the JWS it was constructed from was verified. +It does not imply anything about a potentially present proof property on the presentation itself.

+
+
Disclosure
+

Represents an elements constructing a disclosure. +Object properties and array elements disclosures are supported.

+

See: https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-disclosures

+
+
DomainLinkageConfiguration
+

DID Configuration Resource which contains Domain Linkage Credentials. +It can be placed in an origin's .well-known directory to prove linkage between the origin and a DID. +See: https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource

+

Note:

+ +
+
Duration
+

A span of time.

+
+
EdDSAJwsVerifier
+

An implementor of IJwsVerifier that can handle the +EdDSA algorithm.

+
+
IotaDID
+

A DID conforming to the IOTA DID method specification.

+
+
IotaDocument
+

A DID Document adhering to the IOTA DID method specification.

+

Note: All methods that involve reading from this class may potentially raise an error +if the object is being concurrently modified.

+
+
IotaDocumentMetadata
+

Additional attributes related to an IOTA DID Document.

+
+
IotaIdentityClientExt
+

An extension interface that provides helper functions for publication +and resolution of DID documents in Alias Outputs.

+
+
IssuerProtectedHeader
+
+
Jpt
+

A JSON Proof Token (JPT).

+
+
JptCredentialValidationOptions
+

Options to declare validation criteria for Jpt.

+
+
JptCredentialValidator
+
+
JptCredentialValidatorUtils
+

Utility functions for validating JPT credentials.

+
+
JptPresentationValidationOptions
+

Options to declare validation criteria for a Jpt presentation.

+
+
JptPresentationValidator
+
+
JptPresentationValidatorUtils
+

Utility functions for verifying JPT presentations.

+
+
Jwk
+
+
JwkGenOutput
+

The result of a key generation in JwkStorage.

+
+
JwpCredentialOptions
+
+
JwpIssued
+
+
JwpPresentationOptions
+

Options to be set in the JWT claims of a verifiable presentation.

+
+
JwpVerificationOptions
+
+
Jws
+

A wrapper around a JSON Web Signature (JWS).

+
+
JwsHeader
+
+
JwsSignatureOptions
+
+
JwsVerificationOptions
+
+
Jwt
+

A wrapper around a JSON Web Token (JWK).

+
+
JwtCredentialValidationOptions
+

Options to declare validation criteria when validating credentials.

+
+
JwtCredentialValidator
+

A type for decoding and validating Credential.

+
+
JwtDomainLinkageValidator
+

A validator for a Domain Linkage Configuration and Credentials.

+
+
JwtPresentationOptions
+
+
JwtPresentationValidationOptions
+

Options to declare validation criteria when validating presentation.

+
+
JwtPresentationValidator
+
+
KeyBindingJWTValidationOptions
+

Options to declare validation criteria when validating credentials.

+
+
KeyBindingJwtClaims
+

Claims set for key binding JWT.

+
+
LinkedDomainService
+
+
MethodData
+

Supported verification method data formats.

+
+
MethodDigest
+

Unique identifier of a VerificationMethod.

+

NOTE: +This class does not have a JSON representation, +use the methods pack and unpack instead.

+
+
MethodScope
+

Supported verification method types.

+
+
MethodType
+

Supported verification method types.

+
+
PayloadEntry
+
+
Payloads
+
+
Presentation
+
+
PresentationProtectedHeader
+
+
Proof
+

Represents a cryptographic proof that can be used to validate verifiable credentials and +presentations.

+

This representation does not inherently implement any standard; instead, it +can be utilized to implement standards or user-defined proofs. The presence of the +type field is necessary to accommodate different types of cryptographic proofs.

+

Note that this proof is not related to JWT and can be used in combination or as an alternative +to it.

+
+
ProofUpdateCtx
+
+
Resolver
+

Convenience type for resolving DID documents from different DID methods.

+

Also provides methods for resolving DID Documents associated with +verifiable Credentials and Presentations.

+

Configuration

+

The resolver will only be able to resolve DID documents for methods it has been configured for in the constructor.

+
+
RevocationBitmap
+

A compressed bitmap for managing credential revocation.

+
+
RevocationTimeframeStatus
+

Information used to determine the current status of a Credential.

+
+
SdJwt
+

Representation of an SD-JWT of the format +<Issuer-signed JWT>~<Disclosure 1>~<Disclosure 2>~...~<Disclosure N>~<optional KB-JWT>.

+
+
SdJwtCredentialValidator
+

A type for decoding and validating Credential.

+
+
SdObjectDecoder
+

Substitutes digests in an SD-JWT object by their corresponding plaintext values provided by disclosures.

+
+
SdObjectEncoder
+

Transforms a JSON object into an SD-JWT object by substituting selected values +with their corresponding disclosure digests.

+

Note: digests are created using the sha-256 algorithm.

+
+
SelectiveDisclosurePresentation
+

Used to construct a JwpPresentedBuilder and handle the selective disclosure of attributes

+
    +
  • @context MUST NOT be blinded
  • +
  • id MUST be blinded
  • +
  • type MUST NOT be blinded
  • +
  • issuer MUST NOT be blinded
  • +
  • issuanceDate MUST be blinded (if Timeframe Revocation mechanism is used)
  • +
  • expirationDate MUST be blinded (if Timeframe Revocation mechanism is used)
  • +
  • credentialSubject (User have to choose which attribute must be blinded)
  • +
  • credentialSchema MUST NOT be blinded
  • +
  • credentialStatus MUST NOT be blinded
  • +
  • refreshService MUST NOT be blinded (probably will be used for Timeslot Revocation mechanism)
  • +
  • termsOfUse NO reason to use it in ZK VC (will be in any case blinded)
  • +
  • evidence (User have to choose which attribute must be blinded)
  • +
+
+
Service
+

A DID Document Service used to enable trusted interactions associated with a DID subject.

+
+
StatusList2021
+

StatusList2021 data structure as described in W3C's VC status list 2021.

+
+
StatusList2021Credential
+

A parsed StatusList2021Credential.

+
+
StatusList2021CredentialBuilder
+

Builder type to construct valid StatusList2021Credential istances.

+
+
StatusList2021Entry
+

StatusList2021Entry implementation.

+
+
Storage
+

A type wrapping a JwkStorage and KeyIdStorage that should always be used together when +working with storage backed DID documents.

+
+
Timestamp
+
+
UnknownCredential
+
+
VerificationMethod
+

A DID Document Verification Method.

+
+
+ +## Members + +
+
StatusCheck
+

Controls validation behaviour when checking whether or not a credential has been revoked by its +credentialStatus.

+
+
Strict
+

Validate the status if supported, reject any unsupported +credentialStatus types.

+

Only RevocationBitmap2022 is currently supported.

+

This is the default.

+
+
SkipUnsupported
+

Validate the status if supported, skip any unsupported +credentialStatus types.

+
+
SkipAll
+

Skip all status checks.

+
+
CredentialStatus
+
+
PayloadType
+
+
ProofAlgorithm
+
+
StatusPurpose
+

Purpose of a StatusList2021.

+
+
FailFast
+

Declares when validation should return if an error occurs.

+
+
AllErrors
+

Return all errors that occur during validation.

+
+
FirstError
+

Return after the first error occurs.

+
+
StateMetadataEncoding
+
+
SerializationType
+
+
MethodRelationship
+
+
PresentationProofAlgorithm
+
+
SubjectHolderRelationship
+

Declares how credential subjects must relate to the presentation holder.

+

See also the Subject-Holder Relationship section of the specification.

+
+
AlwaysSubject
+

The holder must always match the subject on all credentials, regardless of their nonTransferable property. +This variant is the default.

+
+
SubjectOnNonTransferable
+

The holder must match the subject only for credentials where the nonTransferable property is true.

+
+
Any
+

The holder is not required to have any kind of relationship to any credential subject.

+
+
+ +## Functions + +
+
encodeB64(data)string
+

Encode the given bytes in url-safe base64.

+
+
decodeB64(data)Uint8Array
+

Decode the given url-safe base64-encoded slice into its raw bytes.

+
+
start()
+

Initializes the console error panic hook for better error messages

+
+
verifyEd25519(alg, signingInput, decodedSignature, publicKey)
+

Verify a JWS signature secured with the EdDSA algorithm and curve Ed25519.

+

This function is useful when one is composing a IJwsVerifier that delegates +EdDSA verification with curve Ed25519 to this function.

+

Warning

+

This function does not check whether alg = EdDSA in the protected header. Callers are expected to assert this +prior to calling the function.

+
+
+ + + +## CoreDID +A method-agnostic Decentralized Identifier (DID). + +**Kind**: global class + +* [CoreDID](#CoreDID) + * _instance_ + * [.setMethodName(value)](#CoreDID+setMethodName) + * [.setMethodId(value)](#CoreDID+setMethodId) + * [.scheme()](#CoreDID+scheme) ⇒ string + * [.authority()](#CoreDID+authority) ⇒ string + * [.method()](#CoreDID+method) ⇒ string + * [.methodId()](#CoreDID+methodId) ⇒ string + * [.join(segment)](#CoreDID+join) ⇒ [DIDUrl](#DIDUrl) + * [.toUrl()](#CoreDID+toUrl) ⇒ [DIDUrl](#DIDUrl) + * [.intoUrl()](#CoreDID+intoUrl) ⇒ [DIDUrl](#DIDUrl) + * [.toString()](#CoreDID+toString) ⇒ string + * [.toCoreDid()](#CoreDID+toCoreDid) ⇒ [CoreDID](#CoreDID) + * [.toJSON()](#CoreDID+toJSON) ⇒ any + * [.clone()](#CoreDID+clone) ⇒ [CoreDID](#CoreDID) + * _static_ + * [.parse(input)](#CoreDID.parse) ⇒ [CoreDID](#CoreDID) + * [.validMethodName(value)](#CoreDID.validMethodName) ⇒ boolean + * [.validMethodId(value)](#CoreDID.validMethodId) ⇒ boolean + * [.fromJSON(json)](#CoreDID.fromJSON) ⇒ [CoreDID](#CoreDID) + + + +### coreDID.setMethodName(value) +Set the method name of the [CoreDID](#CoreDID). + +**Kind**: instance method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| value | string | + + + +### coreDID.setMethodId(value) +Set the method-specific-id of the `DID`. + +**Kind**: instance method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| value | string | + + + +### coreDID.scheme() ⇒ string +Returns the [CoreDID](#CoreDID) scheme. + +E.g. +- `"did:example:12345678" -> "did"` +- `"did:iota:smr:12345678" -> "did"` + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.authority() ⇒ string +Returns the [CoreDID](#CoreDID) authority: the method name and method-id. + +E.g. +- `"did:example:12345678" -> "example:12345678"` +- `"did:iota:smr:12345678" -> "iota:smr:12345678"` + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.method() ⇒ string +Returns the [CoreDID](#CoreDID) method name. + +E.g. +- `"did:example:12345678" -> "example"` +- `"did:iota:smr:12345678" -> "iota"` + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.methodId() ⇒ string +Returns the [CoreDID](#CoreDID) method-specific ID. + +E.g. +- `"did:example:12345678" -> "12345678"` +- `"did:iota:smr:12345678" -> "smr:12345678"` + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.join(segment) ⇒ [DIDUrl](#DIDUrl) +Construct a new [DIDUrl](#DIDUrl) by joining with a relative DID Url string. + +**Kind**: instance method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| segment | string | + + + +### coreDID.toUrl() ⇒ [DIDUrl](#DIDUrl) +Clones the [CoreDID](#CoreDID) into a [DIDUrl](#DIDUrl). + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.intoUrl() ⇒ [DIDUrl](#DIDUrl) +Converts the [CoreDID](#CoreDID) into a [DIDUrl](#DIDUrl), consuming it. + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.toString() ⇒ string +Returns the [CoreDID](#CoreDID) as a string. + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.toCoreDid() ⇒ [CoreDID](#CoreDID) +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### coreDID.clone() ⇒ [CoreDID](#CoreDID) +Deep clones the object. + +**Kind**: instance method of [CoreDID](#CoreDID) + + +### CoreDID.parse(input) ⇒ [CoreDID](#CoreDID) +Parses a [CoreDID](#CoreDID) from the given `input`. + +### Errors + +Throws an error if the input is not a valid [CoreDID](#CoreDID). + +**Kind**: static method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| input | string | + + + +### CoreDID.validMethodName(value) ⇒ boolean +Validates whether a string is a valid DID method name. + +**Kind**: static method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| value | string | + + + +### CoreDID.validMethodId(value) ⇒ boolean +Validates whether a string is a valid `DID` method-id. + +**Kind**: static method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| value | string | + + + +### CoreDID.fromJSON(json) ⇒ [CoreDID](#CoreDID) +Deserializes an instance from a JSON object. + +**Kind**: static method of [CoreDID](#CoreDID) + +| Param | Type | +| --- | --- | +| json | any | + + + +## CoreDocument +A method-agnostic DID Document. + +Note: All methods that involve reading from this class may potentially raise an error +if the object is being concurrently modified. + +**Kind**: global class + +* [CoreDocument](#CoreDocument) + * [new CoreDocument(values)](#new_CoreDocument_new) + * _instance_ + * [.id()](#CoreDocument+id) ⇒ [CoreDID](#CoreDID) + * [.setId(id)](#CoreDocument+setId) + * [.controller()](#CoreDocument+controller) ⇒ [Array.<CoreDID>](#CoreDID) + * [.setController(controllers)](#CoreDocument+setController) + * [.alsoKnownAs()](#CoreDocument+alsoKnownAs) ⇒ Array.<string> + * [.setAlsoKnownAs(urls)](#CoreDocument+setAlsoKnownAs) + * [.verificationMethod()](#CoreDocument+verificationMethod) ⇒ [Array.<VerificationMethod>](#VerificationMethod) + * [.authentication()](#CoreDocument+authentication) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.assertionMethod()](#CoreDocument+assertionMethod) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.keyAgreement()](#CoreDocument+keyAgreement) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.capabilityDelegation()](#CoreDocument+capabilityDelegation) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.capabilityInvocation()](#CoreDocument+capabilityInvocation) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.properties()](#CoreDocument+properties) ⇒ Map.<string, any> + * [.setPropertyUnchecked(key, value)](#CoreDocument+setPropertyUnchecked) + * [.service()](#CoreDocument+service) ⇒ [Array.<Service>](#Service) + * [.insertService(service)](#CoreDocument+insertService) + * [.removeService(didUrl)](#CoreDocument+removeService) ⇒ [Service](#Service) \| undefined + * [.resolveService(query)](#CoreDocument+resolveService) ⇒ [Service](#Service) \| undefined + * [.methods([scope])](#CoreDocument+methods) ⇒ [Array.<VerificationMethod>](#VerificationMethod) + * [.verificationRelationships()](#CoreDocument+verificationRelationships) ⇒ Array.<(DIDUrl\|VerificationMethod)> + * [.insertMethod(method, scope)](#CoreDocument+insertMethod) + * [.removeMethod(did)](#CoreDocument+removeMethod) ⇒ [VerificationMethod](#VerificationMethod) \| undefined + * [.resolveMethod(query, [scope])](#CoreDocument+resolveMethod) ⇒ [VerificationMethod](#VerificationMethod) \| undefined + * [.attachMethodRelationship(didUrl, relationship)](#CoreDocument+attachMethodRelationship) ⇒ boolean + * [.detachMethodRelationship(didUrl, relationship)](#CoreDocument+detachMethodRelationship) ⇒ boolean + * [.verifyJws(jws, options, signatureVerifier, [detachedPayload])](#CoreDocument+verifyJws) ⇒ [DecodedJws](#DecodedJws) + * [.revokeCredentials(serviceQuery, indices)](#CoreDocument+revokeCredentials) + * [.unrevokeCredentials(serviceQuery, indices)](#CoreDocument+unrevokeCredentials) + * [.clone()](#CoreDocument+clone) ⇒ [CoreDocument](#CoreDocument) + * [._shallowCloneInternal()](#CoreDocument+_shallowCloneInternal) ⇒ [CoreDocument](#CoreDocument) + * [._strongCountInternal()](#CoreDocument+_strongCountInternal) ⇒ number + * [.toJSON()](#CoreDocument+toJSON) ⇒ any + * [.generateMethod(storage, keyType, alg, fragment, scope)](#CoreDocument+generateMethod) ⇒ Promise.<string> + * [.purgeMethod(storage, id)](#CoreDocument+purgeMethod) ⇒ Promise.<void> + * [.createJws(storage, fragment, payload, options)](#CoreDocument+createJws) ⇒ [Promise.<Jws>](#Jws) + * [.createCredentialJwt(storage, fragment, credential, options, [custom_claims])](#CoreDocument+createCredentialJwt) ⇒ [Promise.<Jwt>](#Jwt) + * [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#CoreDocument+createPresentationJwt) ⇒ [Promise.<Jwt>](#Jwt) + * _static_ + * [.fromJSON(json)](#CoreDocument.fromJSON) ⇒ [CoreDocument](#CoreDocument) + + + +### new CoreDocument(values) +Creates a new [CoreDocument](#CoreDocument) with the given properties. + + +| Param | Type | +| --- | --- | +| values | ICoreDocument | + + + +### coreDocument.id() ⇒ [CoreDID](#CoreDID) +Returns a copy of the DID Document `id`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.setId(id) +Sets the DID of the document. + +### Warning + +Changing the identifier can drastically alter the results of +`resolve_method`, `resolve_service` and the related +[DID URL dereferencing](https://w3c-ccg.github.io/did-resolution/#dereferencing) algorithm. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| id | [CoreDID](#CoreDID) | + + + +### coreDocument.controller() ⇒ [Array.<CoreDID>](#CoreDID) +Returns a copy of the document controllers. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.setController(controllers) +Sets the controllers of the DID Document. + +Note: Duplicates will be ignored. +Use `null` to remove all controllers. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| controllers | [CoreDID](#CoreDID) \| [Array.<CoreDID>](#CoreDID) \| null | + + + +### coreDocument.alsoKnownAs() ⇒ Array.<string> +Returns a copy of the document's `alsoKnownAs` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.setAlsoKnownAs(urls) +Sets the `alsoKnownAs` property in the DID document. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| urls | string \| Array.<string> \| null | + + + +### coreDocument.verificationMethod() ⇒ [Array.<VerificationMethod>](#VerificationMethod) +Returns a copy of the document's `verificationMethod` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.authentication() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns a copy of the document's `authentication` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.assertionMethod() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns a copy of the document's `assertionMethod` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.keyAgreement() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns a copy of the document's `keyAgreement` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.capabilityDelegation() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns a copy of the document's `capabilityDelegation` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.capabilityInvocation() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns a copy of the document's `capabilityInvocation` set. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.properties() ⇒ Map.<string, any> +Returns a copy of the custom DID Document properties. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.setPropertyUnchecked(key, value) +Sets a custom property in the DID Document. +If the value is set to `null`, the custom property will be removed. + +### WARNING + +This method can overwrite existing properties like `id` and result in an invalid document. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| key | string | +| value | any | + + + +### coreDocument.service() ⇒ [Array.<Service>](#Service) +Returns a set of all [Service](#Service) in the document. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.insertService(service) +Add a new [Service](#Service) to the document. + +Errors if there already exists a service or verification method with the same id. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| service | [Service](#Service) | + + + +### coreDocument.removeService(didUrl) ⇒ [Service](#Service) \| undefined +Remove a [Service](#Service) identified by the given [DIDUrl](#DIDUrl) from the document. + +Returns `true` if the service was removed. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| didUrl | [DIDUrl](#DIDUrl) | + + + +### coreDocument.resolveService(query) ⇒ [Service](#Service) \| undefined +Returns the first [Service](#Service) with an `id` property matching the provided `query`, +if present. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| query | [DIDUrl](#DIDUrl) \| string | + + + +### coreDocument.methods([scope]) ⇒ [Array.<VerificationMethod>](#VerificationMethod) +Returns a list of all [VerificationMethod](#VerificationMethod) in the DID Document, +whose verification relationship matches `scope`. + +If `scope` is not set, a list over the **embedded** methods is returned. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| [scope] | [MethodScope](#MethodScope) \| undefined | + + + +### coreDocument.verificationRelationships() ⇒ Array.<(DIDUrl\|VerificationMethod)> +Returns an array of all verification relationships. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.insertMethod(method, scope) +Adds a new `method` to the document in the given `scope`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| method | [VerificationMethod](#VerificationMethod) | +| scope | [MethodScope](#MethodScope) | + + + +### coreDocument.removeMethod(did) ⇒ [VerificationMethod](#VerificationMethod) \| undefined +Removes all references to the specified Verification Method. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| did | [DIDUrl](#DIDUrl) | + + + +### coreDocument.resolveMethod(query, [scope]) ⇒ [VerificationMethod](#VerificationMethod) \| undefined +Returns a copy of the first verification method with an `id` property +matching the provided `query` and the verification relationship +specified by `scope`, if present. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| query | [DIDUrl](#DIDUrl) \| string | +| [scope] | [MethodScope](#MethodScope) \| undefined | + + + +### coreDocument.attachMethodRelationship(didUrl, relationship) ⇒ boolean +Attaches the relationship to the given method, if the method exists. + +Note: The method needs to be in the set of verification methods, +so it cannot be an embedded one. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| didUrl | [DIDUrl](#DIDUrl) | +| relationship | [MethodRelationship](#MethodRelationship) | + + + +### coreDocument.detachMethodRelationship(didUrl, relationship) ⇒ boolean +Detaches the given relationship from the given method, if the method exists. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| didUrl | [DIDUrl](#DIDUrl) | +| relationship | [MethodRelationship](#MethodRelationship) | + + + +### coreDocument.verifyJws(jws, options, signatureVerifier, [detachedPayload]) ⇒ [DecodedJws](#DecodedJws) +Decodes and verifies the provided JWS according to the passed `options` and `signatureVerifier`. + If no `signatureVerifier` argument is provided a default verifier will be used that is (only) capable of +verifying EdDSA signatures. + +Regardless of which options are passed the following conditions must be met in order for a verification attempt to +take place. +- The JWS must be encoded according to the JWS compact serialization. +- The `kid` value in the protected header must be an identifier of a verification method in this DID document, +or set explicitly in the `options`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| jws | [Jws](#Jws) | +| options | [JwsVerificationOptions](#JwsVerificationOptions) | +| signatureVerifier | IJwsVerifier | +| [detachedPayload] | string \| undefined | + + + +### coreDocument.revokeCredentials(serviceQuery, indices) +If the document has a [RevocationBitmap](#RevocationBitmap) service identified by `serviceQuery`, +revoke all specified `indices`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| serviceQuery | [DIDUrl](#DIDUrl) \| string | +| indices | number \| Array.<number> | + + + +### coreDocument.unrevokeCredentials(serviceQuery, indices) +If the document has a [RevocationBitmap](#RevocationBitmap) service identified by `serviceQuery`, +unrevoke all specified `indices`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| serviceQuery | [DIDUrl](#DIDUrl) \| string | +| indices | number \| Array.<number> | + + + +### coreDocument.clone() ⇒ [CoreDocument](#CoreDocument) +Deep clones the [CoreDocument](#CoreDocument). + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.\_shallowCloneInternal() ⇒ [CoreDocument](#CoreDocument) +### Warning +This is for internal use only. Do not rely on or call this method. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.\_strongCountInternal() ⇒ number +### Warning +This is for internal use only. Do not rely on or call this method. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.toJSON() ⇒ any +Serializes to a plain JS representation. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + + +### coreDocument.generateMethod(storage, keyType, alg, fragment, scope) ⇒ Promise.<string> +Generate new key material in the given `storage` and insert a new verification method with the corresponding +public key material into the DID document. + +- If no fragment is given the `kid` of the generated JWK is used, if it is set, otherwise an error is returned. +- The `keyType` must be compatible with the given `storage`. `Storage`s are expected to export key type constants +for that use case. + +The fragment of the generated method is returned. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| keyType | string | +| alg | JwsAlgorithm | +| fragment | string \| undefined | +| scope | [MethodScope](#MethodScope) | + + + +### coreDocument.purgeMethod(storage, id) ⇒ Promise.<void> +Remove the method identified by the `fragment` from the document and delete the corresponding key material in +the `storage`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| id | [DIDUrl](#DIDUrl) | + + + +### coreDocument.createJws(storage, fragment, payload, options) ⇒ [Promise.<Jws>](#Jws) +Sign the `payload` according to `options` with the storage backed private key corresponding to the public key +material in the verification method identified by the given `fragment. + +Upon success a string representing a JWS encoded according to the Compact JWS Serialization format is returned. +See [RFC7515 section 3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1). + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| payload | string | +| options | [JwsSignatureOptions](#JwsSignatureOptions) | + + + +### coreDocument.createCredentialJwt(storage, fragment, credential, options, [custom_claims]) ⇒ [Promise.<Jwt>](#Jwt) +Produces a JWT where the payload is produced from the given `credential` +in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token). + +Unless the `kid` is explicitly set in the options, the `kid` in the protected header is the `id` +of the method identified by `fragment` and the JWS signature will be produced by the corresponding +private key backed by the `storage` in accordance with the passed `options`. + +The `custom_claims` can be used to set additional claims on the resulting JWT. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| credential | [Credential](#Credential) | +| options | [JwsSignatureOptions](#JwsSignatureOptions) | +| [custom_claims] | Record.<string, any> \| undefined | + + + +### coreDocument.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options) ⇒ [Promise.<Jwt>](#Jwt) +Produces a JWT where the payload is produced from the given presentation. +in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token). + +Unless the `kid` is explicitly set in the options, the `kid` in the protected header is the `id` +of the method identified by `fragment` and the JWS signature will be produced by the corresponding +private key backed by the `storage` in accordance with the passed `options`. + +**Kind**: instance method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| presentation | [Presentation](#Presentation) | +| signature_options | [JwsSignatureOptions](#JwsSignatureOptions) | +| presentation_options | [JwtPresentationOptions](#JwtPresentationOptions) | + + + +### CoreDocument.fromJSON(json) ⇒ [CoreDocument](#CoreDocument) +Deserializes an instance from a plain JS representation. + +**Kind**: static method of [CoreDocument](#CoreDocument) + +| Param | Type | +| --- | --- | +| json | any | + + + +## Credential +**Kind**: global class + +* [Credential](#Credential) + * [new Credential(values)](#new_Credential_new) + * _instance_ + * [.context()](#Credential+context) ⇒ Array.<(string\|Record.<string, any>)> + * [.id()](#Credential+id) ⇒ string \| undefined + * [.type()](#Credential+type) ⇒ Array.<string> + * [.credentialSubject()](#Credential+credentialSubject) ⇒ Array.<Subject> + * [.issuer()](#Credential+issuer) ⇒ string \| Issuer + * [.issuanceDate()](#Credential+issuanceDate) ⇒ [Timestamp](#Timestamp) + * [.expirationDate()](#Credential+expirationDate) ⇒ [Timestamp](#Timestamp) \| undefined + * [.credentialStatus()](#Credential+credentialStatus) ⇒ Array.<Status> + * [.credentialSchema()](#Credential+credentialSchema) ⇒ Array.<Schema> + * [.refreshService()](#Credential+refreshService) ⇒ Array.<RefreshService> + * [.termsOfUse()](#Credential+termsOfUse) ⇒ Array.<Policy> + * [.evidence()](#Credential+evidence) ⇒ Array.<Evidence> + * [.nonTransferable()](#Credential+nonTransferable) ⇒ boolean \| undefined + * [.proof()](#Credential+proof) ⇒ [Proof](#Proof) \| undefined + * [.properties()](#Credential+properties) ⇒ Map.<string, any> + * [.setProof([proof])](#Credential+setProof) + * [.toJwtClaims([custom_claims])](#Credential+toJwtClaims) ⇒ Record.<string, any> + * [.toJSON()](#Credential+toJSON) ⇒ any + * [.clone()](#Credential+clone) ⇒ [Credential](#Credential) + * _static_ + * [.BaseContext()](#Credential.BaseContext) ⇒ string + * [.BaseType()](#Credential.BaseType) ⇒ string + * [.createDomainLinkageCredential(values)](#Credential.createDomainLinkageCredential) ⇒ [Credential](#Credential) + * [.fromJSON(json)](#Credential.fromJSON) ⇒ [Credential](#Credential) + + + +### new Credential(values) +Constructs a new [Credential](#Credential). + + +| Param | Type | +| --- | --- | +| values | ICredential | + + + +### credential.context() ⇒ Array.<(string\|Record.<string, any>)> +Returns a copy of the JSON-LD context(s) applicable to the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.id() ⇒ string \| undefined +Returns a copy of the unique `URI` identifying the [Credential](#Credential) . + +**Kind**: instance method of [Credential](#Credential) + + +### credential.type() ⇒ Array.<string> +Returns a copy of the URIs defining the type of the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.credentialSubject() ⇒ Array.<Subject> +Returns a copy of the [Credential](#Credential) subject(s). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.issuer() ⇒ string \| Issuer +Returns a copy of the issuer of the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.issuanceDate() ⇒ [Timestamp](#Timestamp) +Returns a copy of the timestamp of when the [Credential](#Credential) becomes valid. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.expirationDate() ⇒ [Timestamp](#Timestamp) \| undefined +Returns a copy of the timestamp of when the [Credential](#Credential) should no longer be considered valid. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.credentialStatus() ⇒ Array.<Status> +Returns a copy of the information used to determine the current status of the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.credentialSchema() ⇒ Array.<Schema> +Returns a copy of the information used to assist in the enforcement of a specific [Credential](#Credential) structure. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.refreshService() ⇒ Array.<RefreshService> +Returns a copy of the service(s) used to refresh an expired [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.termsOfUse() ⇒ Array.<Policy> +Returns a copy of the terms-of-use specified by the [Credential](#Credential) issuer. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.evidence() ⇒ Array.<Evidence> +Returns a copy of the human-readable evidence used to support the claims within the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.nonTransferable() ⇒ boolean \| undefined +Returns whether or not the [Credential](#Credential) must only be contained within a [Presentation](#Presentation) +with a proof issued from the [Credential](#Credential) subject. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.proof() ⇒ [Proof](#Proof) \| undefined +Optional cryptographic proof, unrelated to JWT. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.properties() ⇒ Map.<string, any> +Returns a copy of the miscellaneous properties on the [Credential](#Credential). + +**Kind**: instance method of [Credential](#Credential) + + +### credential.setProof([proof]) +Sets the `proof` property of the [Credential](#Credential). + +Note that this proof is not related to JWT. + +**Kind**: instance method of [Credential](#Credential) + +| Param | Type | +| --- | --- | +| [proof] | [Proof](#Proof) \| undefined | + + + +### credential.toJwtClaims([custom_claims]) ⇒ Record.<string, any> +Serializes the `Credential` as a JWT claims set +in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token). + +The resulting object can be used as the payload of a JWS when issuing the credential. + +**Kind**: instance method of [Credential](#Credential) + +| Param | Type | +| --- | --- | +| [custom_claims] | Record.<string, any> \| undefined | + + + +### credential.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Credential](#Credential) + + +### credential.clone() ⇒ [Credential](#Credential) +Deep clones the object. + +**Kind**: instance method of [Credential](#Credential) + + +### Credential.BaseContext() ⇒ string +Returns the base JSON-LD context. + +**Kind**: static method of [Credential](#Credential) + + +### Credential.BaseType() ⇒ string +Returns the base type. + +**Kind**: static method of [Credential](#Credential) + + +### Credential.createDomainLinkageCredential(values) ⇒ [Credential](#Credential) +**Kind**: static method of [Credential](#Credential) + +| Param | Type | +| --- | --- | +| values | IDomainLinkageCredential | + + + +### Credential.fromJSON(json) ⇒ [Credential](#Credential) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Credential](#Credential) + +| Param | Type | +| --- | --- | +| json | any | + + + +## CustomMethodData +A custom verification method data format. + +**Kind**: global class + +* [CustomMethodData](#CustomMethodData) + * [new CustomMethodData(name, data)](#new_CustomMethodData_new) + * _instance_ + * [.clone()](#CustomMethodData+clone) ⇒ [CustomMethodData](#CustomMethodData) + * [.toJSON()](#CustomMethodData+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#CustomMethodData.fromJSON) ⇒ [CustomMethodData](#CustomMethodData) + + + +### new CustomMethodData(name, data) + +| Param | Type | +| --- | --- | +| name | string | +| data | any | + + + +### customMethodData.clone() ⇒ [CustomMethodData](#CustomMethodData) +Deep clones the object. + +**Kind**: instance method of [CustomMethodData](#CustomMethodData) + + +### customMethodData.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [CustomMethodData](#CustomMethodData) + + +### CustomMethodData.fromJSON(json) ⇒ [CustomMethodData](#CustomMethodData) +Deserializes an instance from a JSON object. + +**Kind**: static method of [CustomMethodData](#CustomMethodData) + +| Param | Type | +| --- | --- | +| json | any | + + + +## DIDUrl +A method agnostic DID Url. + +**Kind**: global class + +* [DIDUrl](#DIDUrl) + * _instance_ + * [.did()](#DIDUrl+did) ⇒ [CoreDID](#CoreDID) + * [.urlStr()](#DIDUrl+urlStr) ⇒ string + * [.fragment()](#DIDUrl+fragment) ⇒ string \| undefined + * [.setFragment([value])](#DIDUrl+setFragment) + * [.path()](#DIDUrl+path) ⇒ string \| undefined + * [.setPath([value])](#DIDUrl+setPath) + * [.query()](#DIDUrl+query) ⇒ string \| undefined + * [.setQuery([value])](#DIDUrl+setQuery) + * [.join(segment)](#DIDUrl+join) ⇒ [DIDUrl](#DIDUrl) + * [.toString()](#DIDUrl+toString) ⇒ string + * [.toJSON()](#DIDUrl+toJSON) ⇒ any + * [.clone()](#DIDUrl+clone) ⇒ [DIDUrl](#DIDUrl) + * _static_ + * [.parse(input)](#DIDUrl.parse) ⇒ [DIDUrl](#DIDUrl) + * [.fromJSON(json)](#DIDUrl.fromJSON) ⇒ [DIDUrl](#DIDUrl) + + + +### didUrl.did() ⇒ [CoreDID](#CoreDID) +Return a copy of the [CoreDID](#CoreDID) section of the [DIDUrl](#DIDUrl). + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.urlStr() ⇒ string +Return a copy of the relative DID Url as a string, including only the path, query, and fragment. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.fragment() ⇒ string \| undefined +Returns a copy of the [DIDUrl](#DIDUrl) method fragment, if any. Excludes the leading '#'. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.setFragment([value]) +Sets the `fragment` component of the [DIDUrl](#DIDUrl). + +**Kind**: instance method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| [value] | string \| undefined | + + + +### didUrl.path() ⇒ string \| undefined +Returns a copy of the [DIDUrl](#DIDUrl) path. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.setPath([value]) +Sets the `path` component of the [DIDUrl](#DIDUrl). + +**Kind**: instance method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| [value] | string \| undefined | + + + +### didUrl.query() ⇒ string \| undefined +Returns a copy of the [DIDUrl](#DIDUrl) method query, if any. Excludes the leading '?'. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.setQuery([value]) +Sets the `query` component of the [DIDUrl](#DIDUrl). + +**Kind**: instance method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| [value] | string \| undefined | + + + +### didUrl.join(segment) ⇒ [DIDUrl](#DIDUrl) +Append a string representing a path, query, and/or fragment, returning a new [DIDUrl](#DIDUrl). + +Must begin with a valid delimiter character: '/', '?', '#'. Overwrites the existing URL +segment and any following segments in order of path, query, then fragment. + +I.e. +- joining a path will clear the query and fragment. +- joining a query will clear the fragment. +- joining a fragment will only overwrite the fragment. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| segment | string | + + + +### didUrl.toString() ⇒ string +Returns the [DIDUrl](#DIDUrl) as a string. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### didUrl.clone() ⇒ [DIDUrl](#DIDUrl) +Deep clones the object. + +**Kind**: instance method of [DIDUrl](#DIDUrl) + + +### DIDUrl.parse(input) ⇒ [DIDUrl](#DIDUrl) +Parses a [DIDUrl](#DIDUrl) from the input string. + +**Kind**: static method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| input | string | + + + +### DIDUrl.fromJSON(json) ⇒ [DIDUrl](#DIDUrl) +Deserializes an instance from a JSON object. + +**Kind**: static method of [DIDUrl](#DIDUrl) + +| Param | Type | +| --- | --- | +| json | any | + + + +## DecodedJptCredential +**Kind**: global class + +* [DecodedJptCredential](#DecodedJptCredential) + * [.clone()](#DecodedJptCredential+clone) ⇒ [DecodedJptCredential](#DecodedJptCredential) + * [.credential()](#DecodedJptCredential+credential) ⇒ [Credential](#Credential) + * [.customClaims()](#DecodedJptCredential+customClaims) ⇒ Map.<string, any> + * [.decodedJwp()](#DecodedJptCredential+decodedJwp) ⇒ [JwpIssued](#JwpIssued) + + + +### decodedJptCredential.clone() ⇒ [DecodedJptCredential](#DecodedJptCredential) +Deep clones the object. + +**Kind**: instance method of [DecodedJptCredential](#DecodedJptCredential) + + +### decodedJptCredential.credential() ⇒ [Credential](#Credential) +Returns the [Credential](#Credential) embedded into this JPT. + +**Kind**: instance method of [DecodedJptCredential](#DecodedJptCredential) + + +### decodedJptCredential.customClaims() ⇒ Map.<string, any> +Returns the custom claims parsed from the JPT. + +**Kind**: instance method of [DecodedJptCredential](#DecodedJptCredential) + + +### decodedJptCredential.decodedJwp() ⇒ [JwpIssued](#JwpIssued) +**Kind**: instance method of [DecodedJptCredential](#DecodedJptCredential) + + +## DecodedJptPresentation +**Kind**: global class + +* [DecodedJptPresentation](#DecodedJptPresentation) + * [.clone()](#DecodedJptPresentation+clone) ⇒ [DecodedJptPresentation](#DecodedJptPresentation) + * [.credential()](#DecodedJptPresentation+credential) ⇒ [Credential](#Credential) + * [.customClaims()](#DecodedJptPresentation+customClaims) ⇒ Map.<string, any> + * [.aud()](#DecodedJptPresentation+aud) ⇒ string \| undefined + + + +### decodedJptPresentation.clone() ⇒ [DecodedJptPresentation](#DecodedJptPresentation) +Deep clones the object. + +**Kind**: instance method of [DecodedJptPresentation](#DecodedJptPresentation) + + +### decodedJptPresentation.credential() ⇒ [Credential](#Credential) +Returns the [Credential](#Credential) embedded into this JPT. + +**Kind**: instance method of [DecodedJptPresentation](#DecodedJptPresentation) + + +### decodedJptPresentation.customClaims() ⇒ Map.<string, any> +Returns the custom claims parsed from the JPT. + +**Kind**: instance method of [DecodedJptPresentation](#DecodedJptPresentation) + + +### decodedJptPresentation.aud() ⇒ string \| undefined +Returns the `aud` property parsed from the JWT claims. + +**Kind**: instance method of [DecodedJptPresentation](#DecodedJptPresentation) + + +## DecodedJws +A cryptographically verified decoded token from a JWS. + +Contains the decoded headers and the raw claims. + +**Kind**: global class + +* [DecodedJws](#DecodedJws) + * [.claims()](#DecodedJws+claims) ⇒ string + * [.claimsBytes()](#DecodedJws+claimsBytes) ⇒ Uint8Array + * [.protectedHeader()](#DecodedJws+protectedHeader) ⇒ [JwsHeader](#JwsHeader) + * [.clone()](#DecodedJws+clone) ⇒ [DecodedJws](#DecodedJws) + * [.toJSON()](#DecodedJws+toJSON) ⇒ any + + + +### decodedJws.claims() ⇒ string +Returns a copy of the parsed claims represented as a string. + +# Errors +An error is thrown if the claims cannot be represented as a string. + +This error can only occur if the Token was decoded from a detached payload. + +**Kind**: instance method of [DecodedJws](#DecodedJws) + + +### decodedJws.claimsBytes() ⇒ Uint8Array +Return a copy of the parsed claims represented as an array of bytes. + +**Kind**: instance method of [DecodedJws](#DecodedJws) + + +### decodedJws.protectedHeader() ⇒ [JwsHeader](#JwsHeader) +Returns a copy of the protected header. + +**Kind**: instance method of [DecodedJws](#DecodedJws) + + +### decodedJws.clone() ⇒ [DecodedJws](#DecodedJws) +Deep clones the object. + +**Kind**: instance method of [DecodedJws](#DecodedJws) + + +### decodedJws.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [DecodedJws](#DecodedJws) + + +## DecodedJwtCredential +A cryptographically verified and decoded Credential. + +Note that having an instance of this type only means the JWS it was constructed from was verified. +It does not imply anything about a potentially present proof property on the credential itself. + +**Kind**: global class + +* [DecodedJwtCredential](#DecodedJwtCredential) + * [.credential()](#DecodedJwtCredential+credential) ⇒ [Credential](#Credential) + * [.protectedHeader()](#DecodedJwtCredential+protectedHeader) ⇒ [JwsHeader](#JwsHeader) + * [.customClaims()](#DecodedJwtCredential+customClaims) ⇒ Record.<string, any> \| undefined + * [.intoCredential()](#DecodedJwtCredential+intoCredential) ⇒ [Credential](#Credential) + + + +### decodedJwtCredential.credential() ⇒ [Credential](#Credential) +Returns a copy of the credential parsed to the [Verifiable Credentials Data model](https://www.w3.org/TR/vc-data-model/). + +**Kind**: instance method of [DecodedJwtCredential](#DecodedJwtCredential) + + +### decodedJwtCredential.protectedHeader() ⇒ [JwsHeader](#JwsHeader) +Returns a copy of the protected header parsed from the decoded JWS. + +**Kind**: instance method of [DecodedJwtCredential](#DecodedJwtCredential) + + +### decodedJwtCredential.customClaims() ⇒ Record.<string, any> \| undefined +The custom claims parsed from the JWT. + +**Kind**: instance method of [DecodedJwtCredential](#DecodedJwtCredential) + + +### decodedJwtCredential.intoCredential() ⇒ [Credential](#Credential) +Consumes the object and returns the decoded credential. + +### Warning + +This destroys the [DecodedJwtCredential](#DecodedJwtCredential) object. + +**Kind**: instance method of [DecodedJwtCredential](#DecodedJwtCredential) + + +## DecodedJwtPresentation +A cryptographically verified and decoded presentation. + +Note that having an instance of this type only means the JWS it was constructed from was verified. +It does not imply anything about a potentially present proof property on the presentation itself. + +**Kind**: global class + +* [DecodedJwtPresentation](#DecodedJwtPresentation) + * [.presentation()](#DecodedJwtPresentation+presentation) ⇒ [Presentation](#Presentation) + * [.protectedHeader()](#DecodedJwtPresentation+protectedHeader) ⇒ [JwsHeader](#JwsHeader) + * [.intoPresentation()](#DecodedJwtPresentation+intoPresentation) ⇒ [Presentation](#Presentation) + * [.expirationDate()](#DecodedJwtPresentation+expirationDate) ⇒ [Timestamp](#Timestamp) \| undefined + * [.issuanceDate()](#DecodedJwtPresentation+issuanceDate) ⇒ [Timestamp](#Timestamp) \| undefined + * [.audience()](#DecodedJwtPresentation+audience) ⇒ string \| undefined + * [.customClaims()](#DecodedJwtPresentation+customClaims) ⇒ Record.<string, any> \| undefined + + + +### decodedJwtPresentation.presentation() ⇒ [Presentation](#Presentation) +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.protectedHeader() ⇒ [JwsHeader](#JwsHeader) +Returns a copy of the protected header parsed from the decoded JWS. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.intoPresentation() ⇒ [Presentation](#Presentation) +Consumes the object and returns the decoded presentation. + +### Warning +This destroys the [DecodedJwtPresentation](#DecodedJwtPresentation) object. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.expirationDate() ⇒ [Timestamp](#Timestamp) \| undefined +The expiration date parsed from the JWT claims. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.issuanceDate() ⇒ [Timestamp](#Timestamp) \| undefined +The issuance date parsed from the JWT claims. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.audience() ⇒ string \| undefined +The `aud` property parsed from JWT claims. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +### decodedJwtPresentation.customClaims() ⇒ Record.<string, any> \| undefined +The custom claims parsed from the JWT. + +**Kind**: instance method of [DecodedJwtPresentation](#DecodedJwtPresentation) + + +## Disclosure +Represents an elements constructing a disclosure. +Object properties and array elements disclosures are supported. + +See: https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-disclosures + +**Kind**: global class + +* [Disclosure](#Disclosure) + * [new Disclosure(salt, claim_name, claim_value)](#new_Disclosure_new) + * _instance_ + * [.disclosure()](#Disclosure+disclosure) ⇒ string + * [.toEncodedString()](#Disclosure+toEncodedString) ⇒ string + * [.toString()](#Disclosure+toString) ⇒ string + * [.salt()](#Disclosure+salt) ⇒ string + * [.claimName()](#Disclosure+claimName) ⇒ string \| undefined + * [.claimValue()](#Disclosure+claimValue) ⇒ any + * [.toJSON()](#Disclosure+toJSON) ⇒ any + * _static_ + * [.parse(disclosure)](#Disclosure.parse) ⇒ [Disclosure](#Disclosure) + * [.fromJSON(json)](#Disclosure.fromJSON) ⇒ [Disclosure](#Disclosure) + + + +### new Disclosure(salt, claim_name, claim_value) + +| Param | Type | +| --- | --- | +| salt | string | +| claim_name | string \| undefined | +| claim_value | any | + + + +### disclosure.disclosure() ⇒ string +Returns a copy of the base64url-encoded string. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.toEncodedString() ⇒ string +Returns a copy of the base64url-encoded string. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.toString() ⇒ string +Returns a copy of the base64url-encoded string. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.salt() ⇒ string +Returns a copy of the salt value. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.claimName() ⇒ string \| undefined +Returns a copy of the claim name, optional for array elements. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.claimValue() ⇒ any +Returns a copy of the claim Value which can be of any type. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### disclosure.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Disclosure](#Disclosure) + + +### Disclosure.parse(disclosure) ⇒ [Disclosure](#Disclosure) +Parses a Base64 encoded disclosure into a `Disclosure`. + +## Error + +Returns an `InvalidDisclosure` if input is not a valid disclosure. + +**Kind**: static method of [Disclosure](#Disclosure) + +| Param | Type | +| --- | --- | +| disclosure | string | + + + +### Disclosure.fromJSON(json) ⇒ [Disclosure](#Disclosure) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Disclosure](#Disclosure) + +| Param | Type | +| --- | --- | +| json | any | + + + +## DomainLinkageConfiguration +DID Configuration Resource which contains Domain Linkage Credentials. +It can be placed in an origin's `.well-known` directory to prove linkage between the origin and a DID. +See: + +Note: +- Only the [JSON Web Token Proof Format](https://identity.foundation/.well-known/resources/did-configuration/#json-web-token-proof-format) + +**Kind**: global class + +* [DomainLinkageConfiguration](#DomainLinkageConfiguration) + * [new DomainLinkageConfiguration(linkedDids)](#new_DomainLinkageConfiguration_new) + * _instance_ + * [.linkedDids()](#DomainLinkageConfiguration+linkedDids) ⇒ [Array.<Jwt>](#Jwt) + * [.issuers()](#DomainLinkageConfiguration+issuers) ⇒ [Array.<CoreDID>](#CoreDID) + * [.toJSON()](#DomainLinkageConfiguration+toJSON) ⇒ any + * [.clone()](#DomainLinkageConfiguration+clone) ⇒ [DomainLinkageConfiguration](#DomainLinkageConfiguration) + * _static_ + * [.fromJSON(json)](#DomainLinkageConfiguration.fromJSON) ⇒ [DomainLinkageConfiguration](#DomainLinkageConfiguration) + + + +### new DomainLinkageConfiguration(linkedDids) +Constructs a new [DomainLinkageConfiguration](#DomainLinkageConfiguration). + + +| Param | Type | +| --- | --- | +| linkedDids | [Array.<Jwt>](#Jwt) | + + + +### domainLinkageConfiguration.linkedDids() ⇒ [Array.<Jwt>](#Jwt) +List of the Domain Linkage Credentials. + +**Kind**: instance method of [DomainLinkageConfiguration](#DomainLinkageConfiguration) + + +### domainLinkageConfiguration.issuers() ⇒ [Array.<CoreDID>](#CoreDID) +List of the issuers of the Domain Linkage Credentials. + +**Kind**: instance method of [DomainLinkageConfiguration](#DomainLinkageConfiguration) + + +### domainLinkageConfiguration.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [DomainLinkageConfiguration](#DomainLinkageConfiguration) + + +### domainLinkageConfiguration.clone() ⇒ [DomainLinkageConfiguration](#DomainLinkageConfiguration) +Deep clones the object. + +**Kind**: instance method of [DomainLinkageConfiguration](#DomainLinkageConfiguration) + + +### DomainLinkageConfiguration.fromJSON(json) ⇒ [DomainLinkageConfiguration](#DomainLinkageConfiguration) +Deserializes an instance from a JSON object. + +**Kind**: static method of [DomainLinkageConfiguration](#DomainLinkageConfiguration) + +| Param | Type | +| --- | --- | +| json | any | + + + +## Duration +A span of time. + +**Kind**: global class + +* [Duration](#Duration) + * _instance_ + * [.toJSON()](#Duration+toJSON) ⇒ any + * _static_ + * [.seconds(seconds)](#Duration.seconds) ⇒ [Duration](#Duration) + * [.minutes(minutes)](#Duration.minutes) ⇒ [Duration](#Duration) + * [.hours(hours)](#Duration.hours) ⇒ [Duration](#Duration) + * [.days(days)](#Duration.days) ⇒ [Duration](#Duration) + * [.weeks(weeks)](#Duration.weeks) ⇒ [Duration](#Duration) + * [.fromJSON(json)](#Duration.fromJSON) ⇒ [Duration](#Duration) + + + +### duration.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Duration](#Duration) + + +### Duration.seconds(seconds) ⇒ [Duration](#Duration) +Create a new [Duration](#Duration) with the given number of seconds. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| seconds | number | + + + +### Duration.minutes(minutes) ⇒ [Duration](#Duration) +Create a new [Duration](#Duration) with the given number of minutes. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| minutes | number | + + + +### Duration.hours(hours) ⇒ [Duration](#Duration) +Create a new [Duration](#Duration) with the given number of hours. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| hours | number | + + + +### Duration.days(days) ⇒ [Duration](#Duration) +Create a new [Duration](#Duration) with the given number of days. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| days | number | + + + +### Duration.weeks(weeks) ⇒ [Duration](#Duration) +Create a new [Duration](#Duration) with the given number of weeks. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| weeks | number | + + + +### Duration.fromJSON(json) ⇒ [Duration](#Duration) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Duration](#Duration) + +| Param | Type | +| --- | --- | +| json | any | + + + +## EdDSAJwsVerifier +An implementor of `IJwsVerifier` that can handle the +`EdDSA` algorithm. + +**Kind**: global class + +* [EdDSAJwsVerifier](#EdDSAJwsVerifier) + * [new EdDSAJwsVerifier()](#new_EdDSAJwsVerifier_new) + * [.verify(alg, signingInput, decodedSignature, publicKey)](#EdDSAJwsVerifier+verify) + + + +### new EdDSAJwsVerifier() +Constructs an EdDSAJwsVerifier. + + + +### edDSAJwsVerifier.verify(alg, signingInput, decodedSignature, publicKey) +Verify a JWS signature secured with the `EdDSA` algorithm. +Only the `Ed25519` curve is supported for now. + +This function is useful when one is building an `IJwsVerifier` that extends the default provided by +the IOTA Identity Framework. + +# Warning + +This function does not check whether `alg = EdDSA` in the protected header. Callers are expected to assert this +prior to calling the function. + +**Kind**: instance method of [EdDSAJwsVerifier](#EdDSAJwsVerifier) + +| Param | Type | +| --- | --- | +| alg | JwsAlgorithm | +| signingInput | Uint8Array | +| decodedSignature | Uint8Array | +| publicKey | [Jwk](#Jwk) | + + + +## IotaDID +A DID conforming to the IOTA DID method specification. + +**Kind**: global class + +* [IotaDID](#IotaDID) + * [new IotaDID(bytes, network)](#new_IotaDID_new) + * _instance_ + * [.network()](#IotaDID+network) ⇒ string + * [.tag()](#IotaDID+tag) ⇒ string + * [.toCoreDid()](#IotaDID+toCoreDid) ⇒ [CoreDID](#CoreDID) + * [.scheme()](#IotaDID+scheme) ⇒ string + * [.authority()](#IotaDID+authority) ⇒ string + * [.method()](#IotaDID+method) ⇒ string + * [.methodId()](#IotaDID+methodId) ⇒ string + * [.join(segment)](#IotaDID+join) ⇒ [DIDUrl](#DIDUrl) + * [.toUrl()](#IotaDID+toUrl) ⇒ [DIDUrl](#DIDUrl) + * [.toAliasId()](#IotaDID+toAliasId) ⇒ string + * [.intoUrl()](#IotaDID+intoUrl) ⇒ [DIDUrl](#DIDUrl) + * [.toString()](#IotaDID+toString) ⇒ string + * [.toJSON()](#IotaDID+toJSON) ⇒ any + * [.clone()](#IotaDID+clone) ⇒ [IotaDID](#IotaDID) + * _static_ + * [.METHOD](#IotaDID.METHOD) ⇒ string + * [.DEFAULT_NETWORK](#IotaDID.DEFAULT_NETWORK) ⇒ string + * [.fromAliasId(aliasId, network)](#IotaDID.fromAliasId) ⇒ [IotaDID](#IotaDID) + * [.placeholder(network)](#IotaDID.placeholder) ⇒ [IotaDID](#IotaDID) + * [.parse(input)](#IotaDID.parse) ⇒ [IotaDID](#IotaDID) + * [.fromJSON(json)](#IotaDID.fromJSON) ⇒ [IotaDID](#IotaDID) + + + +### new IotaDID(bytes, network) +Constructs a new [IotaDID](#IotaDID) from a byte representation of the tag and the given +network name. + +See also [placeholder](#IotaDID.placeholder). + + +| Param | Type | +| --- | --- | +| bytes | Uint8Array | +| network | string | + + + +### did.network() ⇒ string +Returns the Tangle network name of the [IotaDID](#IotaDID). + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.tag() ⇒ string +Returns a copy of the unique tag of the [IotaDID](#IotaDID). + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.toCoreDid() ⇒ [CoreDID](#CoreDID) +Returns the DID represented as a [CoreDID](#CoreDID). + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.scheme() ⇒ string +Returns the `DID` scheme. + +E.g. +- `"did:example:12345678" -> "did"` +- `"did:iota:main:12345678" -> "did"` + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.authority() ⇒ string +Returns the `DID` authority: the method name and method-id. + +E.g. +- `"did:example:12345678" -> "example:12345678"` +- `"did:iota:main:12345678" -> "iota:main:12345678"` + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.method() ⇒ string +Returns the `DID` method name. + +E.g. +- `"did:example:12345678" -> "example"` +- `"did:iota:main:12345678" -> "iota"` + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.methodId() ⇒ string +Returns the `DID` method-specific ID. + +E.g. +- `"did:example:12345678" -> "12345678"` +- `"did:iota:main:12345678" -> "main:12345678"` + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.join(segment) ⇒ [DIDUrl](#DIDUrl) +Construct a new [DIDUrl](#DIDUrl) by joining with a relative DID Url string. + +**Kind**: instance method of [IotaDID](#IotaDID) + +| Param | Type | +| --- | --- | +| segment | string | + + + +### did.toUrl() ⇒ [DIDUrl](#DIDUrl) +Clones the `DID` into a [DIDUrl](#DIDUrl). + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.toAliasId() ⇒ string +Returns the hex-encoded AliasId with a '0x' prefix, from the DID tag. + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.intoUrl() ⇒ [DIDUrl](#DIDUrl) +Converts the `DID` into a [DIDUrl](#DIDUrl), consuming it. + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.toString() ⇒ string +Returns the `DID` as a string. + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### did.clone() ⇒ [IotaDID](#IotaDID) +Deep clones the object. + +**Kind**: instance method of [IotaDID](#IotaDID) + + +### IotaDID.METHOD ⇒ string +The IOTA DID method name (`"iota"`). + +**Kind**: static property of [IotaDID](#IotaDID) + + +### IotaDID.DEFAULT\_NETWORK ⇒ string +The default Tangle network (`"iota"`). + +**Kind**: static property of [IotaDID](#IotaDID) + + +### IotaDID.fromAliasId(aliasId, network) ⇒ [IotaDID](#IotaDID) +Constructs a new [IotaDID](#IotaDID) from a hex representation of an Alias Id and the given +network name. + +**Kind**: static method of [IotaDID](#IotaDID) + +| Param | Type | +| --- | --- | +| aliasId | string | +| network | string | + + + +### IotaDID.placeholder(network) ⇒ [IotaDID](#IotaDID) +Creates a new placeholder [IotaDID](#IotaDID) with the given network name. + +E.g. `did:iota:smr:0x0000000000000000000000000000000000000000000000000000000000000000`. + +**Kind**: static method of [IotaDID](#IotaDID) + +| Param | Type | +| --- | --- | +| network | string | + + + +### IotaDID.parse(input) ⇒ [IotaDID](#IotaDID) +Parses a [IotaDID](#IotaDID) from the input string. + +**Kind**: static method of [IotaDID](#IotaDID) + +| Param | Type | +| --- | --- | +| input | string | + + + +### IotaDID.fromJSON(json) ⇒ [IotaDID](#IotaDID) +Deserializes an instance from a JSON object. + +**Kind**: static method of [IotaDID](#IotaDID) + +| Param | Type | +| --- | --- | +| json | any | + + + +## IotaDocument +A DID Document adhering to the IOTA DID method specification. + +Note: All methods that involve reading from this class may potentially raise an error +if the object is being concurrently modified. + +**Kind**: global class + +* [IotaDocument](#IotaDocument) + * [new IotaDocument(network)](#new_IotaDocument_new) + * _instance_ + * [.id()](#IotaDocument+id) ⇒ [IotaDID](#IotaDID) + * [.controller()](#IotaDocument+controller) ⇒ [Array.<IotaDID>](#IotaDID) + * [.setController(controller)](#IotaDocument+setController) + * [.alsoKnownAs()](#IotaDocument+alsoKnownAs) ⇒ Array.<string> + * [.setAlsoKnownAs(urls)](#IotaDocument+setAlsoKnownAs) + * [.properties()](#IotaDocument+properties) ⇒ Map.<string, any> + * [.setPropertyUnchecked(key, value)](#IotaDocument+setPropertyUnchecked) + * [.service()](#IotaDocument+service) ⇒ [Array.<Service>](#Service) + * [.insertService(service)](#IotaDocument+insertService) + * [.removeService(did)](#IotaDocument+removeService) ⇒ [Service](#Service) \| undefined + * [.resolveService(query)](#IotaDocument+resolveService) ⇒ [Service](#Service) \| undefined + * [.methods([scope])](#IotaDocument+methods) ⇒ [Array.<VerificationMethod>](#VerificationMethod) + * [.insertMethod(method, scope)](#IotaDocument+insertMethod) + * [.removeMethod(did)](#IotaDocument+removeMethod) ⇒ [VerificationMethod](#VerificationMethod) \| undefined + * [.resolveMethod(query, [scope])](#IotaDocument+resolveMethod) ⇒ [VerificationMethod](#VerificationMethod) \| undefined + * [.attachMethodRelationship(didUrl, relationship)](#IotaDocument+attachMethodRelationship) ⇒ boolean + * [.detachMethodRelationship(didUrl, relationship)](#IotaDocument+detachMethodRelationship) ⇒ boolean + * [.verifyJws(jws, options, signatureVerifier, [detachedPayload])](#IotaDocument+verifyJws) ⇒ [DecodedJws](#DecodedJws) + * [.pack()](#IotaDocument+pack) ⇒ Uint8Array + * [.packWithEncoding(encoding)](#IotaDocument+packWithEncoding) ⇒ Uint8Array + * [.metadata()](#IotaDocument+metadata) ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) + * [.metadataCreated()](#IotaDocument+metadataCreated) ⇒ [Timestamp](#Timestamp) \| undefined + * [.setMetadataCreated(timestamp)](#IotaDocument+setMetadataCreated) + * [.metadataUpdated()](#IotaDocument+metadataUpdated) ⇒ [Timestamp](#Timestamp) \| undefined + * [.setMetadataUpdated(timestamp)](#IotaDocument+setMetadataUpdated) + * [.metadataDeactivated()](#IotaDocument+metadataDeactivated) ⇒ boolean \| undefined + * [.setMetadataDeactivated([deactivated])](#IotaDocument+setMetadataDeactivated) + * [.metadataStateControllerAddress()](#IotaDocument+metadataStateControllerAddress) ⇒ string \| undefined + * [.metadataGovernorAddress()](#IotaDocument+metadataGovernorAddress) ⇒ string \| undefined + * [.setMetadataPropertyUnchecked(key, value)](#IotaDocument+setMetadataPropertyUnchecked) + * [.revokeCredentials(serviceQuery, indices)](#IotaDocument+revokeCredentials) + * [.unrevokeCredentials(serviceQuery, indices)](#IotaDocument+unrevokeCredentials) + * [.clone()](#IotaDocument+clone) ⇒ [IotaDocument](#IotaDocument) + * [._shallowCloneInternal()](#IotaDocument+_shallowCloneInternal) ⇒ [IotaDocument](#IotaDocument) + * [._strongCountInternal()](#IotaDocument+_strongCountInternal) ⇒ number + * [.toJSON()](#IotaDocument+toJSON) ⇒ any + * [.toCoreDocument()](#IotaDocument+toCoreDocument) ⇒ [CoreDocument](#CoreDocument) + * [.generateMethod(storage, keyType, alg, fragment, scope)](#IotaDocument+generateMethod) ⇒ Promise.<string> + * [.purgeMethod(storage, id)](#IotaDocument+purgeMethod) ⇒ Promise.<void> + * ~~[.createJwt(storage, fragment, payload, options)](#IotaDocument+createJwt) ⇒ [Promise.<Jws>](#Jws)~~ + * [.createJws(storage, fragment, payload, options)](#IotaDocument+createJws) ⇒ [Promise.<Jws>](#Jws) + * [.createCredentialJwt(storage, fragment, credential, options, [custom_claims])](#IotaDocument+createCredentialJwt) ⇒ [Promise.<Jwt>](#Jwt) + * [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#IotaDocument+createPresentationJwt) ⇒ [Promise.<Jwt>](#Jwt) + * [.generateMethodJwp(storage, alg, fragment, scope)](#IotaDocument+generateMethodJwp) ⇒ Promise.<string> + * [.createIssuedJwp(storage, fragment, jpt_claims, options)](#IotaDocument+createIssuedJwp) ⇒ Promise.<string> + * [.createPresentedJwp(presentation, method_id, options)](#IotaDocument+createPresentedJwp) ⇒ Promise.<string> + * [.createCredentialJpt(credential, storage, fragment, options, [custom_claims])](#IotaDocument+createCredentialJpt) ⇒ [Promise.<Jpt>](#Jpt) + * [.createPresentationJpt(presentation, method_id, options)](#IotaDocument+createPresentationJpt) ⇒ [Promise.<Jpt>](#Jpt) + * _static_ + * [.newWithId(id)](#IotaDocument.newWithId) ⇒ [IotaDocument](#IotaDocument) + * [.unpackFromOutput(did, aliasOutput, allowEmpty)](#IotaDocument.unpackFromOutput) ⇒ [IotaDocument](#IotaDocument) + * [.unpackFromBlock(network, block)](#IotaDocument.unpackFromBlock) ⇒ [Array.<IotaDocument>](#IotaDocument) + * [.fromJSON(json)](#IotaDocument.fromJSON) ⇒ [IotaDocument](#IotaDocument) + + + +### new IotaDocument(network) +Constructs an empty IOTA DID Document with a [placeholder](#IotaDID.placeholder) identifier +for the given `network`. + + +| Param | Type | +| --- | --- | +| network | string | + + + +### iotaDocument.id() ⇒ [IotaDID](#IotaDID) +Returns a copy of the DID Document `id`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.controller() ⇒ [Array.<IotaDID>](#IotaDID) +Returns a copy of the list of document controllers. + +NOTE: controllers are determined by the `state_controller` unlock condition of the output +during resolution and are omitted when publishing. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setController(controller) +Sets the controllers of the document. + +Note: Duplicates will be ignored. +Use `null` to remove all controllers. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| controller | [Array.<IotaDID>](#IotaDID) \| null | + + + +### iotaDocument.alsoKnownAs() ⇒ Array.<string> +Returns a copy of the document's `alsoKnownAs` set. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setAlsoKnownAs(urls) +Sets the `alsoKnownAs` property in the DID document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| urls | string \| Array.<string> \| null | + + + +### iotaDocument.properties() ⇒ Map.<string, any> +Returns a copy of the custom DID Document properties. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setPropertyUnchecked(key, value) +Sets a custom property in the DID Document. +If the value is set to `null`, the custom property will be removed. + +### WARNING + +This method can overwrite existing properties like `id` and result in an invalid document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| key | string | +| value | any | + + + +### iotaDocument.service() ⇒ [Array.<Service>](#Service) +Return a set of all [Service](#Service) in the document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.insertService(service) +Add a new [Service](#Service) to the document. + +Returns `true` if the service was added. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| service | [Service](#Service) | + + + +### iotaDocument.removeService(did) ⇒ [Service](#Service) \| undefined +Remove a [Service](#Service) identified by the given [DIDUrl](#DIDUrl) from the document. + +Returns `true` if a service was removed. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| did | [DIDUrl](#DIDUrl) | + + + +### iotaDocument.resolveService(query) ⇒ [Service](#Service) \| undefined +Returns the first [Service](#Service) with an `id` property matching the provided `query`, +if present. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| query | [DIDUrl](#DIDUrl) \| string | + + + +### iotaDocument.methods([scope]) ⇒ [Array.<VerificationMethod>](#VerificationMethod) +Returns a list of all [VerificationMethod](#VerificationMethod) in the DID Document, +whose verification relationship matches `scope`. + +If `scope` is not set, a list over the **embedded** methods is returned. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| [scope] | [MethodScope](#MethodScope) \| undefined | + + + +### iotaDocument.insertMethod(method, scope) +Adds a new `method` to the document in the given `scope`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| method | [VerificationMethod](#VerificationMethod) | +| scope | [MethodScope](#MethodScope) | + + + +### iotaDocument.removeMethod(did) ⇒ [VerificationMethod](#VerificationMethod) \| undefined +Removes all references to the specified Verification Method. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| did | [DIDUrl](#DIDUrl) | + + + +### iotaDocument.resolveMethod(query, [scope]) ⇒ [VerificationMethod](#VerificationMethod) \| undefined +Returns a copy of the first verification method with an `id` property +matching the provided `query` and the verification relationship +specified by `scope`, if present. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| query | [DIDUrl](#DIDUrl) \| string | +| [scope] | [MethodScope](#MethodScope) \| undefined | + + + +### iotaDocument.attachMethodRelationship(didUrl, relationship) ⇒ boolean +Attaches the relationship to the given method, if the method exists. + +Note: The method needs to be in the set of verification methods, +so it cannot be an embedded one. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| didUrl | [DIDUrl](#DIDUrl) | +| relationship | [MethodRelationship](#MethodRelationship) | + + + +### iotaDocument.detachMethodRelationship(didUrl, relationship) ⇒ boolean +Detaches the given relationship from the given method, if the method exists. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| didUrl | [DIDUrl](#DIDUrl) | +| relationship | [MethodRelationship](#MethodRelationship) | + + + +### iotaDocument.verifyJws(jws, options, signatureVerifier, [detachedPayload]) ⇒ [DecodedJws](#DecodedJws) +Decodes and verifies the provided JWS according to the passed `options` and `signatureVerifier`. + If no `signatureVerifier` argument is provided a default verifier will be used that is (only) capable of +verifying EdDSA signatures. + +Regardless of which options are passed the following conditions must be met in order for a verification attempt to +take place. +- The JWS must be encoded according to the JWS compact serialization. +- The `kid` value in the protected header must be an identifier of a verification method in this DID document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| jws | [Jws](#Jws) | +| options | [JwsVerificationOptions](#JwsVerificationOptions) | +| signatureVerifier | IJwsVerifier | +| [detachedPayload] | string \| undefined | + + + +### iotaDocument.pack() ⇒ Uint8Array +Serializes the document for inclusion in an Alias Output's state metadata +with the default [StateMetadataEncoding](#StateMetadataEncoding). + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.packWithEncoding(encoding) ⇒ Uint8Array +Serializes the document for inclusion in an Alias Output's state metadata. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| encoding | [StateMetadataEncoding](#StateMetadataEncoding) | + + + +### iotaDocument.metadata() ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) +Returns a copy of the metadata associated with this document. + +NOTE: Copies all the metadata. See also `metadataCreated`, `metadataUpdated`, +`metadataPreviousMessageId`, `metadataProof` if only a subset of the metadata required. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.metadataCreated() ⇒ [Timestamp](#Timestamp) \| undefined +Returns a copy of the timestamp of when the DID document was created. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setMetadataCreated(timestamp) +Sets the timestamp of when the DID document was created. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| timestamp | [Timestamp](#Timestamp) \| undefined | + + + +### iotaDocument.metadataUpdated() ⇒ [Timestamp](#Timestamp) \| undefined +Returns a copy of the timestamp of the last DID document update. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setMetadataUpdated(timestamp) +Sets the timestamp of the last DID document update. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| timestamp | [Timestamp](#Timestamp) \| undefined | + + + +### iotaDocument.metadataDeactivated() ⇒ boolean \| undefined +Returns a copy of the deactivated status of the DID document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setMetadataDeactivated([deactivated]) +Sets the deactivated status of the DID document. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| [deactivated] | boolean \| undefined | + + + +### iotaDocument.metadataStateControllerAddress() ⇒ string \| undefined +Returns a copy of the Bech32-encoded state controller address, if present. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.metadataGovernorAddress() ⇒ string \| undefined +Returns a copy of the Bech32-encoded governor address, if present. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.setMetadataPropertyUnchecked(key, value) +Sets a custom property in the document metadata. +If the value is set to `null`, the custom property will be removed. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| key | string | +| value | any | + + + +### iotaDocument.revokeCredentials(serviceQuery, indices) +If the document has a [RevocationBitmap](#RevocationBitmap) service identified by `serviceQuery`, +revoke all specified `indices`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| serviceQuery | [DIDUrl](#DIDUrl) \| string | +| indices | number \| Array.<number> | + + + +### iotaDocument.unrevokeCredentials(serviceQuery, indices) +If the document has a [RevocationBitmap](#RevocationBitmap) service identified by `serviceQuery`, +unrevoke all specified `indices`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| serviceQuery | [DIDUrl](#DIDUrl) \| string | +| indices | number \| Array.<number> | + + + +### iotaDocument.clone() ⇒ [IotaDocument](#IotaDocument) +Returns a deep clone of the [IotaDocument](#IotaDocument). + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.\_shallowCloneInternal() ⇒ [IotaDocument](#IotaDocument) +### Warning +This is for internal use only. Do not rely on or call this method. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.\_strongCountInternal() ⇒ number +### Warning +This is for internal use only. Do not rely on or call this method. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.toJSON() ⇒ any +Serializes to a plain JS representation. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.toCoreDocument() ⇒ [CoreDocument](#CoreDocument) +Transforms the [IotaDocument](#IotaDocument) to its [CoreDocument](#CoreDocument) representation. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + + +### iotaDocument.generateMethod(storage, keyType, alg, fragment, scope) ⇒ Promise.<string> +Generate new key material in the given `storage` and insert a new verification method with the corresponding +public key material into the DID document. + +- If no fragment is given the `kid` of the generated JWK is used, if it is set, otherwise an error is returned. +- The `keyType` must be compatible with the given `storage`. `Storage`s are expected to export key type constants +for that use case. + +The fragment of the generated method is returned. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| keyType | string | +| alg | JwsAlgorithm | +| fragment | string \| undefined | +| scope | [MethodScope](#MethodScope) | + + + +### iotaDocument.purgeMethod(storage, id) ⇒ Promise.<void> +Remove the method identified by the given fragment from the document and delete the corresponding key material in +the given `storage`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| id | [DIDUrl](#DIDUrl) | + + + +### ~~iotaDocument.createJwt(storage, fragment, payload, options) ⇒ [Promise.<Jws>](#Jws)~~ +***Deprecated*** + +Sign the `payload` according to `options` with the storage backed private key corresponding to the public key +material in the verification method identified by the given `fragment. + +Upon success a string representing a JWS encoded according to the Compact JWS Serialization format is returned. +See [RFC7515 section 3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1). + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| payload | string | +| options | [JwsSignatureOptions](#JwsSignatureOptions) | + + + +### iotaDocument.createJws(storage, fragment, payload, options) ⇒ [Promise.<Jws>](#Jws) +Sign the `payload` according to `options` with the storage backed private key corresponding to the public key +material in the verification method identified by the given `fragment. + +Upon success a string representing a JWS encoded according to the Compact JWS Serialization format is returned. +See [RFC7515 section 3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1). + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| payload | string | +| options | [JwsSignatureOptions](#JwsSignatureOptions) | + + + +### iotaDocument.createCredentialJwt(storage, fragment, credential, options, [custom_claims]) ⇒ [Promise.<Jwt>](#Jwt) +Produces a JWS where the payload is produced from the given `credential` +in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token). + +Unless the `kid` is explicitly set in the options, the `kid` in the protected header is the `id` +of the method identified by `fragment` and the JWS signature will be produced by the corresponding +private key backed by the `storage` in accordance with the passed `options`. + +The `custom_claims` can be used to set additional claims on the resulting JWT. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| credential | [Credential](#Credential) | +| options | [JwsSignatureOptions](#JwsSignatureOptions) | +| [custom_claims] | Record.<string, any> \| undefined | + + + +### iotaDocument.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options) ⇒ [Promise.<Jwt>](#Jwt) +Produces a JWT where the payload is produced from the given presentation. +in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token). + +Unless the `kid` is explicitly set in the options, the `kid` in the protected header is the `id` +of the method identified by `fragment` and the JWS signature will be produced by the corresponding +private key backed by the `storage` in accordance with the passed `options`. + +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| presentation | [Presentation](#Presentation) | +| signature_options | [JwsSignatureOptions](#JwsSignatureOptions) | +| presentation_options | [JwtPresentationOptions](#JwtPresentationOptions) | + + + +### iotaDocument.generateMethodJwp(storage, alg, fragment, scope) ⇒ Promise.<string> +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| alg | [ProofAlgorithm](#ProofAlgorithm) | +| fragment | string \| undefined | +| scope | [MethodScope](#MethodScope) | + + + +### iotaDocument.createIssuedJwp(storage, fragment, jpt_claims, options) ⇒ Promise.<string> +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| storage | [Storage](#Storage) | +| fragment | string | +| jpt_claims | JptClaims | +| options | [JwpCredentialOptions](#JwpCredentialOptions) | + + + +### iotaDocument.createPresentedJwp(presentation, method_id, options) ⇒ Promise.<string> +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| presentation | [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) | +| method_id | string | +| options | [JwpPresentationOptions](#JwpPresentationOptions) | + + + +### iotaDocument.createCredentialJpt(credential, storage, fragment, options, [custom_claims]) ⇒ [Promise.<Jpt>](#Jpt) +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| storage | [Storage](#Storage) | +| fragment | string | +| options | [JwpCredentialOptions](#JwpCredentialOptions) | +| [custom_claims] | Map.<string, any> \| undefined | + + + +### iotaDocument.createPresentationJpt(presentation, method_id, options) ⇒ [Promise.<Jpt>](#Jpt) +**Kind**: instance method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| presentation | [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) | +| method_id | string | +| options | [JwpPresentationOptions](#JwpPresentationOptions) | + + + +### IotaDocument.newWithId(id) ⇒ [IotaDocument](#IotaDocument) +Constructs an empty DID Document with the given identifier. + +**Kind**: static method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| id | [IotaDID](#IotaDID) | + + + +### IotaDocument.unpackFromOutput(did, aliasOutput, allowEmpty) ⇒ [IotaDocument](#IotaDocument) +Deserializes the document from an Alias Output. + +If `allowEmpty` is true, this will return an empty DID document marked as `deactivated` +if `stateMetadata` is empty. + +The `tokenSupply` must be equal to the token supply of the network the DID is associated with. + +NOTE: `did` is required since it is omitted from the serialized DID Document and +cannot be inferred from the state metadata. It also indicates the network, which is not +encoded in the `AliasId` alone. + +**Kind**: static method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| did | [IotaDID](#IotaDID) | +| aliasOutput | AliasOutputBuilderParams | +| allowEmpty | boolean | + + + +### IotaDocument.unpackFromBlock(network, block) ⇒ [Array.<IotaDocument>](#IotaDocument) +Returns all DID documents of the Alias Outputs contained in the block's transaction payload +outputs, if any. + +Errors if any Alias Output does not contain a valid or empty DID Document. + +**Kind**: static method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| network | string | +| block | Block | + + + +### IotaDocument.fromJSON(json) ⇒ [IotaDocument](#IotaDocument) +Deserializes an instance from a plain JS representation. + +**Kind**: static method of [IotaDocument](#IotaDocument) + +| Param | Type | +| --- | --- | +| json | any | + + + +## IotaDocumentMetadata +Additional attributes related to an IOTA DID Document. + +**Kind**: global class + +* [IotaDocumentMetadata](#IotaDocumentMetadata) + * _instance_ + * [.created()](#IotaDocumentMetadata+created) ⇒ [Timestamp](#Timestamp) \| undefined + * [.updated()](#IotaDocumentMetadata+updated) ⇒ [Timestamp](#Timestamp) \| undefined + * [.deactivated()](#IotaDocumentMetadata+deactivated) ⇒ boolean \| undefined + * [.stateControllerAddress()](#IotaDocumentMetadata+stateControllerAddress) ⇒ string \| undefined + * [.governorAddress()](#IotaDocumentMetadata+governorAddress) ⇒ string \| undefined + * [.properties()](#IotaDocumentMetadata+properties) ⇒ Map.<string, any> + * [.toJSON()](#IotaDocumentMetadata+toJSON) ⇒ any + * [.clone()](#IotaDocumentMetadata+clone) ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) + * _static_ + * [.fromJSON(json)](#IotaDocumentMetadata.fromJSON) ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) + + + +### iotaDocumentMetadata.created() ⇒ [Timestamp](#Timestamp) \| undefined +Returns a copy of the timestamp of when the DID document was created. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.updated() ⇒ [Timestamp](#Timestamp) \| undefined +Returns a copy of the timestamp of the last DID document update. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.deactivated() ⇒ boolean \| undefined +Returns a copy of the deactivated status of the DID document. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.stateControllerAddress() ⇒ string \| undefined +Returns a copy of the Bech32-encoded state controller address, if present. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.governorAddress() ⇒ string \| undefined +Returns a copy of the Bech32-encoded governor address, if present. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.properties() ⇒ Map.<string, any> +Returns a copy of the custom metadata properties. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### iotaDocumentMetadata.clone() ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) +Deep clones the object. + +**Kind**: instance method of [IotaDocumentMetadata](#IotaDocumentMetadata) + + +### IotaDocumentMetadata.fromJSON(json) ⇒ [IotaDocumentMetadata](#IotaDocumentMetadata) +Deserializes an instance from a JSON object. + +**Kind**: static method of [IotaDocumentMetadata](#IotaDocumentMetadata) + +| Param | Type | +| --- | --- | +| json | any | + + + +## IotaIdentityClientExt +An extension interface that provides helper functions for publication +and resolution of DID documents in Alias Outputs. + +**Kind**: global class + +* [IotaIdentityClientExt](#IotaIdentityClientExt) + * [.newDidOutput(client, address, document, [rentStructure])](#IotaIdentityClientExt.newDidOutput) ⇒ Promise.<AliasOutputBuilderParams> + * [.updateDidOutput(client, document)](#IotaIdentityClientExt.updateDidOutput) ⇒ Promise.<AliasOutputBuilderParams> + * [.deactivateDidOutput(client, did)](#IotaIdentityClientExt.deactivateDidOutput) ⇒ Promise.<AliasOutputBuilderParams> + * [.resolveDid(client, did)](#IotaIdentityClientExt.resolveDid) ⇒ [Promise.<IotaDocument>](#IotaDocument) + * [.resolveDidOutput(client, did)](#IotaIdentityClientExt.resolveDidOutput) ⇒ Promise.<AliasOutputBuilderParams> + + + +### IotaIdentityClientExt.newDidOutput(client, address, document, [rentStructure]) ⇒ Promise.<AliasOutputBuilderParams> +Create a DID with a new Alias Output containing the given `document`. + +The `address` will be set as the state controller and governor unlock conditions. +The minimum required token deposit amount will be set according to the given +`rent_structure`, which will be fetched from the node if not provided. +The returned Alias Output can be further customised before publication, if desired. + +NOTE: this does *not* publish the Alias Output. + +**Kind**: static method of [IotaIdentityClientExt](#IotaIdentityClientExt) + +| Param | Type | +| --- | --- | +| client | IIotaIdentityClient | +| address | Address | +| document | [IotaDocument](#IotaDocument) | +| [rentStructure] | IRent \| undefined | + + + +### IotaIdentityClientExt.updateDidOutput(client, document) ⇒ Promise.<AliasOutputBuilderParams> +Fetches the associated Alias Output and updates it with `document` in its state metadata. +The storage deposit on the output is left unchanged. If the size of the document increased, +the amount should be increased manually. + +NOTE: this does *not* publish the updated Alias Output. + +**Kind**: static method of [IotaIdentityClientExt](#IotaIdentityClientExt) + +| Param | Type | +| --- | --- | +| client | IIotaIdentityClient | +| document | [IotaDocument](#IotaDocument) | + + + +### IotaIdentityClientExt.deactivateDidOutput(client, did) ⇒ Promise.<AliasOutputBuilderParams> +Removes the DID document from the state metadata of its Alias Output, +effectively deactivating it. The storage deposit on the output is left unchanged, +and should be reallocated manually. + +Deactivating does not destroy the output. Hence, it can be re-activated by publishing +an update containing a DID document. + +NOTE: this does *not* publish the updated Alias Output. + +**Kind**: static method of [IotaIdentityClientExt](#IotaIdentityClientExt) + +| Param | Type | +| --- | --- | +| client | IIotaIdentityClient | +| did | [IotaDID](#IotaDID) | + + + +### IotaIdentityClientExt.resolveDid(client, did) ⇒ [Promise.<IotaDocument>](#IotaDocument) +Resolve a [IotaDocument](#IotaDocument). Returns an empty, deactivated document if the state metadata +of the Alias Output is empty. + +**Kind**: static method of [IotaIdentityClientExt](#IotaIdentityClientExt) + +| Param | Type | +| --- | --- | +| client | IIotaIdentityClient | +| did | [IotaDID](#IotaDID) | + + + +### IotaIdentityClientExt.resolveDidOutput(client, did) ⇒ Promise.<AliasOutputBuilderParams> +Fetches the `IAliasOutput` associated with the given DID. + +**Kind**: static method of [IotaIdentityClientExt](#IotaIdentityClientExt) + +| Param | Type | +| --- | --- | +| client | IIotaIdentityClient | +| did | [IotaDID](#IotaDID) | + + + +## IssuerProtectedHeader +**Kind**: global class + +* [IssuerProtectedHeader](#IssuerProtectedHeader) + * [.typ](#IssuerProtectedHeader+typ) ⇒ string \| undefined + * [.typ](#IssuerProtectedHeader+typ) + * [.alg](#IssuerProtectedHeader+alg) ⇒ [ProofAlgorithm](#ProofAlgorithm) + * [.alg](#IssuerProtectedHeader+alg) + * [.kid](#IssuerProtectedHeader+kid) ⇒ string \| undefined + * [.kid](#IssuerProtectedHeader+kid) + * [.cid](#IssuerProtectedHeader+cid) ⇒ string \| undefined + * [.cid](#IssuerProtectedHeader+cid) + * [.claims()](#IssuerProtectedHeader+claims) ⇒ Array.<string> + + + +### issuerProtectedHeader.typ ⇒ string \| undefined +JWP type (JPT). + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + + +### issuerProtectedHeader.typ +JWP type (JPT). + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### issuerProtectedHeader.alg ⇒ [ProofAlgorithm](#ProofAlgorithm) +Algorithm used for the JWP. + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + + +### issuerProtectedHeader.alg +Algorithm used for the JWP. + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + +| Param | Type | +| --- | --- | +| arg0 | [ProofAlgorithm](#ProofAlgorithm) | + + + +### issuerProtectedHeader.kid ⇒ string \| undefined +ID for the key used for the JWP. + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + + +### issuerProtectedHeader.kid +ID for the key used for the JWP. + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### issuerProtectedHeader.cid ⇒ string \| undefined +Not handled for now. Will be used in the future to resolve external claims + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + + +### issuerProtectedHeader.cid +Not handled for now. Will be used in the future to resolve external claims + +**Kind**: instance property of [IssuerProtectedHeader](#IssuerProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### issuerProtectedHeader.claims() ⇒ Array.<string> +**Kind**: instance method of [IssuerProtectedHeader](#IssuerProtectedHeader) + + +## Jpt +A JSON Proof Token (JPT). + +**Kind**: global class + +* [Jpt](#Jpt) + * [new Jpt(jpt_string)](#new_Jpt_new) + * [.toString()](#Jpt+toString) ⇒ string + * [.clone()](#Jpt+clone) ⇒ [Jpt](#Jpt) + + + +### new Jpt(jpt_string) +Creates a new [Jpt](#Jpt). + + +| Param | Type | +| --- | --- | +| jpt_string | string | + + + +### jpt.toString() ⇒ string +**Kind**: instance method of [Jpt](#Jpt) + + +### jpt.clone() ⇒ [Jpt](#Jpt) +Deep clones the object. + +**Kind**: instance method of [Jpt](#Jpt) + + +## JptCredentialValidationOptions +Options to declare validation criteria for [Jpt](#Jpt). + +**Kind**: global class + +* [JptCredentialValidationOptions](#JptCredentialValidationOptions) + * [new JptCredentialValidationOptions([opts])](#new_JptCredentialValidationOptions_new) + * _instance_ + * [.clone()](#JptCredentialValidationOptions+clone) ⇒ [JptCredentialValidationOptions](#JptCredentialValidationOptions) + * [.toJSON()](#JptCredentialValidationOptions+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#JptCredentialValidationOptions.fromJSON) ⇒ [JptCredentialValidationOptions](#JptCredentialValidationOptions) + + + +### new JptCredentialValidationOptions([opts]) +Creates a new default istance. + + +| Param | Type | +| --- | --- | +| [opts] | IJptCredentialValidationOptions \| undefined | + + + +### jptCredentialValidationOptions.clone() ⇒ [JptCredentialValidationOptions](#JptCredentialValidationOptions) +Deep clones the object. + +**Kind**: instance method of [JptCredentialValidationOptions](#JptCredentialValidationOptions) + + +### jptCredentialValidationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JptCredentialValidationOptions](#JptCredentialValidationOptions) + + +### JptCredentialValidationOptions.fromJSON(json) ⇒ [JptCredentialValidationOptions](#JptCredentialValidationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JptCredentialValidationOptions](#JptCredentialValidationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JptCredentialValidator +**Kind**: global class + + +### JptCredentialValidator.validate(credential_jpt, issuer, options, fail_fast) ⇒ [DecodedJptCredential](#DecodedJptCredential) +**Kind**: static method of [JptCredentialValidator](#JptCredentialValidator) + +| Param | Type | +| --- | --- | +| credential_jpt | [Jpt](#Jpt) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| options | [JptCredentialValidationOptions](#JptCredentialValidationOptions) | +| fail_fast | [FailFast](#FailFast) | + + + +## JptCredentialValidatorUtils +Utility functions for validating JPT credentials. + +**Kind**: global class + +* [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + * [.extractIssuer(credential)](#JptCredentialValidatorUtils.extractIssuer) ⇒ [CoreDID](#CoreDID) + * [.extractIssuerFromIssuedJpt(credential)](#JptCredentialValidatorUtils.extractIssuerFromIssuedJpt) ⇒ [CoreDID](#CoreDID) + * [.checkTimeframesWithValidityTimeframe2024(credential, validity_timeframe, status_check)](#JptCredentialValidatorUtils.checkTimeframesWithValidityTimeframe2024) + * [.checkRevocationWithValidityTimeframe2024(credential, issuer, status_check)](#JptCredentialValidatorUtils.checkRevocationWithValidityTimeframe2024) + * [.checkTimeframesAndRevocationWithValidityTimeframe2024(credential, issuer, validity_timeframe, status_check)](#JptCredentialValidatorUtils.checkTimeframesAndRevocationWithValidityTimeframe2024) + + + +### JptCredentialValidatorUtils.extractIssuer(credential) ⇒ [CoreDID](#CoreDID) +Utility for extracting the issuer field of a [Credential](#Credential) as a DID. +# Errors +Fails if the issuer field is not a valid DID. + +**Kind**: static method of [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | + + + +### JptCredentialValidatorUtils.extractIssuerFromIssuedJpt(credential) ⇒ [CoreDID](#CoreDID) +Utility for extracting the issuer field of a credential in JPT representation as DID. +# Errors +If the JPT decoding fails or the issuer field is not a valid DID. + +**Kind**: static method of [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Jpt](#Jpt) | + + + +### JptCredentialValidatorUtils.checkTimeframesWithValidityTimeframe2024(credential, validity_timeframe, status_check) +**Kind**: static method of [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| validity_timeframe | [Timestamp](#Timestamp) \| undefined | +| status_check | [StatusCheck](#StatusCheck) | + + + +### JptCredentialValidatorUtils.checkRevocationWithValidityTimeframe2024(credential, issuer, status_check) +Checks whether the credential status has been revoked. + +Only supports `RevocationTimeframe2024`. + +**Kind**: static method of [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| status_check | [StatusCheck](#StatusCheck) | + + + +### JptCredentialValidatorUtils.checkTimeframesAndRevocationWithValidityTimeframe2024(credential, issuer, validity_timeframe, status_check) +Checks whether the credential status has been revoked or the timeframe interval is INVALID + +Only supports `RevocationTimeframe2024`. + +**Kind**: static method of [JptCredentialValidatorUtils](#JptCredentialValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| validity_timeframe | [Timestamp](#Timestamp) \| undefined | +| status_check | [StatusCheck](#StatusCheck) | + + + +## JptPresentationValidationOptions +Options to declare validation criteria for a [Jpt](#Jpt) presentation. + +**Kind**: global class + +* [JptPresentationValidationOptions](#JptPresentationValidationOptions) + * [new JptPresentationValidationOptions([opts])](#new_JptPresentationValidationOptions_new) + * _instance_ + * [.clone()](#JptPresentationValidationOptions+clone) ⇒ [JptPresentationValidationOptions](#JptPresentationValidationOptions) + * [.toJSON()](#JptPresentationValidationOptions+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#JptPresentationValidationOptions.fromJSON) ⇒ [JptPresentationValidationOptions](#JptPresentationValidationOptions) + + + +### new JptPresentationValidationOptions([opts]) + +| Param | Type | +| --- | --- | +| [opts] | IJptPresentationValidationOptions \| undefined | + + + +### jptPresentationValidationOptions.clone() ⇒ [JptPresentationValidationOptions](#JptPresentationValidationOptions) +Deep clones the object. + +**Kind**: instance method of [JptPresentationValidationOptions](#JptPresentationValidationOptions) + + +### jptPresentationValidationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JptPresentationValidationOptions](#JptPresentationValidationOptions) + + +### JptPresentationValidationOptions.fromJSON(json) ⇒ [JptPresentationValidationOptions](#JptPresentationValidationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JptPresentationValidationOptions](#JptPresentationValidationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JptPresentationValidator +**Kind**: global class + + +### JptPresentationValidator.validate(presentation_jpt, issuer, options, fail_fast) ⇒ [DecodedJptPresentation](#DecodedJptPresentation) +Decodes and validates a Presented [Credential](#Credential) issued as a JPT (JWP Presented Form). A +[DecodedJptPresentation](#DecodedJptPresentation) is returned upon success. + +The following properties are validated according to `options`: +- the holder's proof on the JWP, +- the expiration date, +- the issuance date, +- the semantic structure. + +**Kind**: static method of [JptPresentationValidator](#JptPresentationValidator) + +| Param | Type | +| --- | --- | +| presentation_jpt | [Jpt](#Jpt) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| options | [JptPresentationValidationOptions](#JptPresentationValidationOptions) | +| fail_fast | [FailFast](#FailFast) | + + + +## JptPresentationValidatorUtils +Utility functions for verifying JPT presentations. + +**Kind**: global class + +* [JptPresentationValidatorUtils](#JptPresentationValidatorUtils) + * [.extractIssuerFromPresentedJpt(presentation)](#JptPresentationValidatorUtils.extractIssuerFromPresentedJpt) ⇒ [CoreDID](#CoreDID) + * [.checkTimeframesWithValidityTimeframe2024(credential, validity_timeframe, status_check)](#JptPresentationValidatorUtils.checkTimeframesWithValidityTimeframe2024) + + + +### JptPresentationValidatorUtils.extractIssuerFromPresentedJpt(presentation) ⇒ [CoreDID](#CoreDID) +Utility for extracting the issuer field of a credential in JPT representation as DID. +# Errors +If the JPT decoding fails or the issuer field is not a valid DID. + +**Kind**: static method of [JptPresentationValidatorUtils](#JptPresentationValidatorUtils) + +| Param | Type | +| --- | --- | +| presentation | [Jpt](#Jpt) | + + + +### JptPresentationValidatorUtils.checkTimeframesWithValidityTimeframe2024(credential, validity_timeframe, status_check) +Check timeframe interval in credentialStatus with `RevocationTimeframeStatus`. + +**Kind**: static method of [JptPresentationValidatorUtils](#JptPresentationValidatorUtils) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| validity_timeframe | [Timestamp](#Timestamp) \| undefined | +| status_check | [StatusCheck](#StatusCheck) | + + + +## Jwk +**Kind**: global class + +* [Jwk](#Jwk) + * [new Jwk(jwk)](#new_Jwk_new) + * _instance_ + * [.kty()](#Jwk+kty) ⇒ JwkType + * [.use()](#Jwk+use) ⇒ JwkUse \| undefined + * [.keyOps()](#Jwk+keyOps) ⇒ Array.<JwkOperation> + * [.alg()](#Jwk+alg) ⇒ JwsAlgorithm \| undefined + * [.kid()](#Jwk+kid) ⇒ string \| undefined + * [.x5u()](#Jwk+x5u) ⇒ string \| undefined + * [.x5c()](#Jwk+x5c) ⇒ Array.<string> + * [.x5t()](#Jwk+x5t) ⇒ string \| undefined + * [.x5t256()](#Jwk+x5t256) ⇒ string \| undefined + * [.paramsEc()](#Jwk+paramsEc) ⇒ JwkParamsEc \| undefined + * [.paramsOkp()](#Jwk+paramsOkp) ⇒ JwkParamsOkp \| undefined + * [.paramsOct()](#Jwk+paramsOct) ⇒ JwkParamsOct \| undefined + * [.paramsRsa()](#Jwk+paramsRsa) ⇒ JwkParamsRsa \| undefined + * [.toPublic()](#Jwk+toPublic) ⇒ [Jwk](#Jwk) \| undefined + * [.isPublic()](#Jwk+isPublic) ⇒ boolean + * [.isPrivate()](#Jwk+isPrivate) ⇒ boolean + * [.toJSON()](#Jwk+toJSON) ⇒ any + * [.clone()](#Jwk+clone) ⇒ [Jwk](#Jwk) + * _static_ + * [.fromJSON(json)](#Jwk.fromJSON) ⇒ [Jwk](#Jwk) + + + +### new Jwk(jwk) + +| Param | Type | +| --- | --- | +| jwk | IJwkParams | + + + +### jwk.kty() ⇒ JwkType +Returns the value for the key type parameter (kty). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.use() ⇒ JwkUse \| undefined +Returns the value for the use property (use). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.keyOps() ⇒ Array.<JwkOperation> +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.alg() ⇒ JwsAlgorithm \| undefined +Returns the value for the algorithm property (alg). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.kid() ⇒ string \| undefined +Returns the value of the key ID property (kid). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.x5u() ⇒ string \| undefined +Returns the value of the X.509 URL property (x5u). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.x5c() ⇒ Array.<string> +Returns the value of the X.509 certificate chain property (x5c). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.x5t() ⇒ string \| undefined +Returns the value of the X.509 certificate SHA-1 thumbprint property (x5t). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.x5t256() ⇒ string \| undefined +Returns the value of the X.509 certificate SHA-256 thumbprint property (x5t#S256). + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.paramsEc() ⇒ JwkParamsEc \| undefined +If this JWK is of kty EC, returns those parameters. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.paramsOkp() ⇒ JwkParamsOkp \| undefined +If this JWK is of kty OKP, returns those parameters. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.paramsOct() ⇒ JwkParamsOct \| undefined +If this JWK is of kty OCT, returns those parameters. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.paramsRsa() ⇒ JwkParamsRsa \| undefined +If this JWK is of kty RSA, returns those parameters. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.toPublic() ⇒ [Jwk](#Jwk) \| undefined +Returns a clone of the [Jwk](#Jwk) with _all_ private key components unset. +Nothing is returned when `kty = oct` as this key type is not considered public by this library. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.isPublic() ⇒ boolean +Returns `true` if _all_ private key components of the key are unset, `false` otherwise. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.isPrivate() ⇒ boolean +Returns `true` if _all_ private key components of the key are set, `false` otherwise. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Jwk](#Jwk) + + +### jwk.clone() ⇒ [Jwk](#Jwk) +Deep clones the object. + +**Kind**: instance method of [Jwk](#Jwk) + + +### Jwk.fromJSON(json) ⇒ [Jwk](#Jwk) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Jwk](#Jwk) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwkGenOutput +The result of a key generation in `JwkStorage`. + +**Kind**: global class + +* [JwkGenOutput](#JwkGenOutput) + * [new JwkGenOutput(key_id, jwk)](#new_JwkGenOutput_new) + * _instance_ + * [.jwk()](#JwkGenOutput+jwk) ⇒ [Jwk](#Jwk) + * [.keyId()](#JwkGenOutput+keyId) ⇒ string + * [.toJSON()](#JwkGenOutput+toJSON) ⇒ any + * [.clone()](#JwkGenOutput+clone) ⇒ [JwkGenOutput](#JwkGenOutput) + * _static_ + * [.fromJSON(json)](#JwkGenOutput.fromJSON) ⇒ [JwkGenOutput](#JwkGenOutput) + + + +### new JwkGenOutput(key_id, jwk) + +| Param | Type | +| --- | --- | +| key_id | string | +| jwk | [Jwk](#Jwk) | + + + +### jwkGenOutput.jwk() ⇒ [Jwk](#Jwk) +Returns the generated public [Jwk](#Jwk). + +**Kind**: instance method of [JwkGenOutput](#JwkGenOutput) + + +### jwkGenOutput.keyId() ⇒ string +Returns the key id of the generated [Jwk](#Jwk). + +**Kind**: instance method of [JwkGenOutput](#JwkGenOutput) + + +### jwkGenOutput.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwkGenOutput](#JwkGenOutput) + + +### jwkGenOutput.clone() ⇒ [JwkGenOutput](#JwkGenOutput) +Deep clones the object. + +**Kind**: instance method of [JwkGenOutput](#JwkGenOutput) + + +### JwkGenOutput.fromJSON(json) ⇒ [JwkGenOutput](#JwkGenOutput) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwkGenOutput](#JwkGenOutput) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwpCredentialOptions +**Kind**: global class + +* [JwpCredentialOptions](#JwpCredentialOptions) + * _instance_ + * [.kid](#JwpCredentialOptions+kid) ⇒ string \| undefined + * [.kid](#JwpCredentialOptions+kid) + * [.toJSON()](#JwpCredentialOptions+toJSON) ⇒ any + * _static_ + * [.fromJSON(value)](#JwpCredentialOptions.fromJSON) ⇒ [JwpCredentialOptions](#JwpCredentialOptions) + + + +### jwpCredentialOptions.kid ⇒ string \| undefined +**Kind**: instance property of [JwpCredentialOptions](#JwpCredentialOptions) + + +### jwpCredentialOptions.kid +**Kind**: instance property of [JwpCredentialOptions](#JwpCredentialOptions) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### jwpCredentialOptions.toJSON() ⇒ any +**Kind**: instance method of [JwpCredentialOptions](#JwpCredentialOptions) + + +### JwpCredentialOptions.fromJSON(value) ⇒ [JwpCredentialOptions](#JwpCredentialOptions) +**Kind**: static method of [JwpCredentialOptions](#JwpCredentialOptions) + +| Param | Type | +| --- | --- | +| value | any | + + + +## JwpIssued +**Kind**: global class + +* [JwpIssued](#JwpIssued) + * _instance_ + * [.toJSON()](#JwpIssued+toJSON) ⇒ any + * [.clone()](#JwpIssued+clone) ⇒ [JwpIssued](#JwpIssued) + * [.encode(serialization)](#JwpIssued+encode) ⇒ string + * [.setProof(proof)](#JwpIssued+setProof) + * [.getProof()](#JwpIssued+getProof) ⇒ Uint8Array + * [.getPayloads()](#JwpIssued+getPayloads) ⇒ [Payloads](#Payloads) + * [.setPayloads(payloads)](#JwpIssued+setPayloads) + * [.getIssuerProtectedHeader()](#JwpIssued+getIssuerProtectedHeader) ⇒ [IssuerProtectedHeader](#IssuerProtectedHeader) + * _static_ + * [.fromJSON(json)](#JwpIssued.fromJSON) ⇒ [JwpIssued](#JwpIssued) + + + +### jwpIssued.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwpIssued](#JwpIssued) + + +### jwpIssued.clone() ⇒ [JwpIssued](#JwpIssued) +Deep clones the object. + +**Kind**: instance method of [JwpIssued](#JwpIssued) + + +### jwpIssued.encode(serialization) ⇒ string +**Kind**: instance method of [JwpIssued](#JwpIssued) + +| Param | Type | +| --- | --- | +| serialization | [SerializationType](#SerializationType) | + + + +### jwpIssued.setProof(proof) +**Kind**: instance method of [JwpIssued](#JwpIssued) + +| Param | Type | +| --- | --- | +| proof | Uint8Array | + + + +### jwpIssued.getProof() ⇒ Uint8Array +**Kind**: instance method of [JwpIssued](#JwpIssued) + + +### jwpIssued.getPayloads() ⇒ [Payloads](#Payloads) +**Kind**: instance method of [JwpIssued](#JwpIssued) + + +### jwpIssued.setPayloads(payloads) +**Kind**: instance method of [JwpIssued](#JwpIssued) + +| Param | Type | +| --- | --- | +| payloads | [Payloads](#Payloads) | + + + +### jwpIssued.getIssuerProtectedHeader() ⇒ [IssuerProtectedHeader](#IssuerProtectedHeader) +**Kind**: instance method of [JwpIssued](#JwpIssued) + + +### JwpIssued.fromJSON(json) ⇒ [JwpIssued](#JwpIssued) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwpIssued](#JwpIssued) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwpPresentationOptions +Options to be set in the JWT claims of a verifiable presentation. + +**Kind**: global class + +* [JwpPresentationOptions](#JwpPresentationOptions) + * [.audience](#JwpPresentationOptions+audience) ⇒ string \| undefined + * [.audience](#JwpPresentationOptions+audience) + * [.nonce](#JwpPresentationOptions+nonce) ⇒ string \| undefined + * [.nonce](#JwpPresentationOptions+nonce) + + + +### jwpPresentationOptions.audience ⇒ string \| undefined +Sets the audience for presentation (`aud` property in JWP Presentation Header). + +**Kind**: instance property of [JwpPresentationOptions](#JwpPresentationOptions) + + +### jwpPresentationOptions.audience +Sets the audience for presentation (`aud` property in JWP Presentation Header). + +**Kind**: instance property of [JwpPresentationOptions](#JwpPresentationOptions) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### jwpPresentationOptions.nonce ⇒ string \| undefined +The nonce to be placed in the Presentation Protected Header. + +**Kind**: instance property of [JwpPresentationOptions](#JwpPresentationOptions) + + +### jwpPresentationOptions.nonce +The nonce to be placed in the Presentation Protected Header. + +**Kind**: instance property of [JwpPresentationOptions](#JwpPresentationOptions) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +## JwpVerificationOptions +**Kind**: global class + +* [JwpVerificationOptions](#JwpVerificationOptions) + * _instance_ + * [.clone()](#JwpVerificationOptions+clone) ⇒ [JwpVerificationOptions](#JwpVerificationOptions) + * [.toJSON()](#JwpVerificationOptions+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#JwpVerificationOptions.fromJSON) ⇒ [JwpVerificationOptions](#JwpVerificationOptions) + * [.new([opts])](#JwpVerificationOptions.new) ⇒ [JwpVerificationOptions](#JwpVerificationOptions) + + + +### jwpVerificationOptions.clone() ⇒ [JwpVerificationOptions](#JwpVerificationOptions) +Deep clones the object. + +**Kind**: instance method of [JwpVerificationOptions](#JwpVerificationOptions) + + +### jwpVerificationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwpVerificationOptions](#JwpVerificationOptions) + + +### JwpVerificationOptions.fromJSON(json) ⇒ [JwpVerificationOptions](#JwpVerificationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwpVerificationOptions](#JwpVerificationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +### JwpVerificationOptions.new([opts]) ⇒ [JwpVerificationOptions](#JwpVerificationOptions) +**Kind**: static method of [JwpVerificationOptions](#JwpVerificationOptions) + +| Param | Type | +| --- | --- | +| [opts] | IJwpVerificationOptions \| undefined | + + + +## Jws +A wrapper around a JSON Web Signature (JWS). + +**Kind**: global class + +* [Jws](#Jws) + * [new Jws(jws_string)](#new_Jws_new) + * [.toString()](#Jws+toString) ⇒ string + + + +### new Jws(jws_string) +Creates a new [Jws](#Jws) from the given string. + + +| Param | Type | +| --- | --- | +| jws_string | string | + + + +### jws.toString() ⇒ string +Returns a clone of the JWS string. + +**Kind**: instance method of [Jws](#Jws) + + +## JwsHeader +**Kind**: global class + +* [JwsHeader](#JwsHeader) + * [new JwsHeader()](#new_JwsHeader_new) + * _instance_ + * [.alg()](#JwsHeader+alg) ⇒ JwsAlgorithm \| undefined + * [.setAlg(value)](#JwsHeader+setAlg) + * [.b64()](#JwsHeader+b64) ⇒ boolean \| undefined + * [.setB64(value)](#JwsHeader+setB64) + * [.custom()](#JwsHeader+custom) ⇒ Record.<string, any> \| undefined + * [.has(claim)](#JwsHeader+has) ⇒ boolean + * [.isDisjoint(other)](#JwsHeader+isDisjoint) ⇒ boolean + * [.jku()](#JwsHeader+jku) ⇒ string \| undefined + * [.setJku(value)](#JwsHeader+setJku) + * [.jwk()](#JwsHeader+jwk) ⇒ [Jwk](#Jwk) \| undefined + * [.setJwk(value)](#JwsHeader+setJwk) + * [.kid()](#JwsHeader+kid) ⇒ string \| undefined + * [.setKid(value)](#JwsHeader+setKid) + * [.x5u()](#JwsHeader+x5u) ⇒ string \| undefined + * [.setX5u(value)](#JwsHeader+setX5u) + * [.x5c()](#JwsHeader+x5c) ⇒ Array.<string> + * [.setX5c(value)](#JwsHeader+setX5c) + * [.x5t()](#JwsHeader+x5t) ⇒ string \| undefined + * [.setX5t(value)](#JwsHeader+setX5t) + * [.x5tS256()](#JwsHeader+x5tS256) ⇒ string \| undefined + * [.setX5tS256(value)](#JwsHeader+setX5tS256) + * [.typ()](#JwsHeader+typ) ⇒ string \| undefined + * [.setTyp(value)](#JwsHeader+setTyp) + * [.cty()](#JwsHeader+cty) ⇒ string \| undefined + * [.setCty(value)](#JwsHeader+setCty) + * [.crit()](#JwsHeader+crit) ⇒ Array.<string> + * [.setCrit(value)](#JwsHeader+setCrit) + * [.url()](#JwsHeader+url) ⇒ string \| undefined + * [.setUrl(value)](#JwsHeader+setUrl) + * [.nonce()](#JwsHeader+nonce) ⇒ string \| undefined + * [.setNonce(value)](#JwsHeader+setNonce) + * [.toJSON()](#JwsHeader+toJSON) ⇒ any + * [.clone()](#JwsHeader+clone) ⇒ [JwsHeader](#JwsHeader) + * _static_ + * [.fromJSON(json)](#JwsHeader.fromJSON) ⇒ [JwsHeader](#JwsHeader) + + + +### new JwsHeader() +Create a new empty [JwsHeader](#JwsHeader). + + + +### jwsHeader.alg() ⇒ JwsAlgorithm \| undefined +Returns the value for the algorithm claim (alg). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setAlg(value) +Sets a value for the algorithm claim (alg). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | JwsAlgorithm | + + + +### jwsHeader.b64() ⇒ boolean \| undefined +Returns the value of the base64url-encode payload claim (b64). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setB64(value) +Sets a value for the base64url-encode payload claim (b64). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | boolean | + + + +### jwsHeader.custom() ⇒ Record.<string, any> \| undefined +Additional header parameters. + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.has(claim) ⇒ boolean +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| claim | string | + + + +### jwsHeader.isDisjoint(other) ⇒ boolean +Returns `true` if none of the fields are set in both `self` and `other`. + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| other | [JwsHeader](#JwsHeader) | + + + +### jwsHeader.jku() ⇒ string \| undefined +Returns the value of the JWK Set URL claim (jku). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setJku(value) +Sets a value for the JWK Set URL claim (jku). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.jwk() ⇒ [Jwk](#Jwk) \| undefined +Returns the value of the JWK claim (jwk). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setJwk(value) +Sets a value for the JWK claim (jwk). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | [Jwk](#Jwk) | + + + +### jwsHeader.kid() ⇒ string \| undefined +Returns the value of the key ID claim (kid). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setKid(value) +Sets a value for the key ID claim (kid). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.x5u() ⇒ string \| undefined +Returns the value of the X.509 URL claim (x5u). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setX5u(value) +Sets a value for the X.509 URL claim (x5u). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.x5c() ⇒ Array.<string> +Returns the value of the X.509 certificate chain claim (x5c). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setX5c(value) +Sets values for the X.509 certificate chain claim (x5c). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | Array.<string> | + + + +### jwsHeader.x5t() ⇒ string \| undefined +Returns the value of the X.509 certificate SHA-1 thumbprint claim (x5t). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setX5t(value) +Sets a value for the X.509 certificate SHA-1 thumbprint claim (x5t). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.x5tS256() ⇒ string \| undefined +Returns the value of the X.509 certificate SHA-256 thumbprint claim +(x5t#S256). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setX5tS256(value) +Sets a value for the X.509 certificate SHA-256 thumbprint claim +(x5t#S256). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.typ() ⇒ string \| undefined +Returns the value of the token type claim (typ). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setTyp(value) +Sets a value for the token type claim (typ). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.cty() ⇒ string \| undefined +Returns the value of the content type claim (cty). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setCty(value) +Sets a value for the content type claim (cty). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.crit() ⇒ Array.<string> +Returns the value of the critical claim (crit). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setCrit(value) +Sets values for the critical claim (crit). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | Array.<string> | + + + +### jwsHeader.url() ⇒ string \| undefined +Returns the value of the url claim (url). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setUrl(value) +Sets a value for the url claim (url). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.nonce() ⇒ string \| undefined +Returns the value of the nonce claim (nonce). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.setNonce(value) +Sets a value for the nonce claim (nonce). + +**Kind**: instance method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsHeader.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### jwsHeader.clone() ⇒ [JwsHeader](#JwsHeader) +Deep clones the object. + +**Kind**: instance method of [JwsHeader](#JwsHeader) + + +### JwsHeader.fromJSON(json) ⇒ [JwsHeader](#JwsHeader) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwsHeader](#JwsHeader) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwsSignatureOptions +**Kind**: global class + +* [JwsSignatureOptions](#JwsSignatureOptions) + * [new JwsSignatureOptions([options])](#new_JwsSignatureOptions_new) + * _instance_ + * [.setAttachJwk(value)](#JwsSignatureOptions+setAttachJwk) + * [.setB64(value)](#JwsSignatureOptions+setB64) + * [.setTyp(value)](#JwsSignatureOptions+setTyp) + * [.setCty(value)](#JwsSignatureOptions+setCty) + * [.serUrl(value)](#JwsSignatureOptions+serUrl) + * [.setNonce(value)](#JwsSignatureOptions+setNonce) + * [.setKid(value)](#JwsSignatureOptions+setKid) + * [.setDetachedPayload(value)](#JwsSignatureOptions+setDetachedPayload) + * [.setCustomHeaderParameters(value)](#JwsSignatureOptions+setCustomHeaderParameters) + * [.toJSON()](#JwsSignatureOptions+toJSON) ⇒ any + * [.clone()](#JwsSignatureOptions+clone) ⇒ [JwsSignatureOptions](#JwsSignatureOptions) + * _static_ + * [.fromJSON(json)](#JwsSignatureOptions.fromJSON) ⇒ [JwsSignatureOptions](#JwsSignatureOptions) + + + +### new JwsSignatureOptions([options]) + +| Param | Type | +| --- | --- | +| [options] | IJwsSignatureOptions \| undefined | + + + +### jwsSignatureOptions.setAttachJwk(value) +Replace the value of the `attachJwk` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | boolean | + + + +### jwsSignatureOptions.setB64(value) +Replace the value of the `b64` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | boolean | + + + +### jwsSignatureOptions.setTyp(value) +Replace the value of the `typ` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsSignatureOptions.setCty(value) +Replace the value of the `cty` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsSignatureOptions.serUrl(value) +Replace the value of the `url` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsSignatureOptions.setNonce(value) +Replace the value of the `nonce` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsSignatureOptions.setKid(value) +Replace the value of the `kid` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsSignatureOptions.setDetachedPayload(value) +Replace the value of the `detached_payload` field. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | boolean | + + + +### jwsSignatureOptions.setCustomHeaderParameters(value) +Add additional header parameters. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| value | Record.<string, any> | + + + +### jwsSignatureOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + + +### jwsSignatureOptions.clone() ⇒ [JwsSignatureOptions](#JwsSignatureOptions) +Deep clones the object. + +**Kind**: instance method of [JwsSignatureOptions](#JwsSignatureOptions) + + +### JwsSignatureOptions.fromJSON(json) ⇒ [JwsSignatureOptions](#JwsSignatureOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwsSignatureOptions](#JwsSignatureOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwsVerificationOptions +**Kind**: global class + +* [JwsVerificationOptions](#JwsVerificationOptions) + * [new JwsVerificationOptions([options])](#new_JwsVerificationOptions_new) + * _instance_ + * [.setNonce(value)](#JwsVerificationOptions+setNonce) + * [.setMethodScope(value)](#JwsVerificationOptions+setMethodScope) + * [.setMethodId(value)](#JwsVerificationOptions+setMethodId) + * [.toJSON()](#JwsVerificationOptions+toJSON) ⇒ any + * [.clone()](#JwsVerificationOptions+clone) ⇒ [JwsVerificationOptions](#JwsVerificationOptions) + * _static_ + * [.fromJSON(json)](#JwsVerificationOptions.fromJSON) ⇒ [JwsVerificationOptions](#JwsVerificationOptions) + + + +### new JwsVerificationOptions([options]) +Creates a new [JwsVerificationOptions](#JwsVerificationOptions) from the given fields. + + +| Param | Type | +| --- | --- | +| [options] | IJwsVerificationOptions \| undefined | + + + +### jwsVerificationOptions.setNonce(value) +Set the expected value for the `nonce` parameter of the protected header. + +**Kind**: instance method of [JwsVerificationOptions](#JwsVerificationOptions) + +| Param | Type | +| --- | --- | +| value | string | + + + +### jwsVerificationOptions.setMethodScope(value) +Set the scope of the verification methods that may be used to verify the given JWS. + +**Kind**: instance method of [JwsVerificationOptions](#JwsVerificationOptions) + +| Param | Type | +| --- | --- | +| value | [MethodScope](#MethodScope) | + + + +### jwsVerificationOptions.setMethodId(value) +Set the DID URl of the method, whose JWK should be used to verify the JWS. + +**Kind**: instance method of [JwsVerificationOptions](#JwsVerificationOptions) + +| Param | Type | +| --- | --- | +| value | [DIDUrl](#DIDUrl) | + + + +### jwsVerificationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwsVerificationOptions](#JwsVerificationOptions) + + +### jwsVerificationOptions.clone() ⇒ [JwsVerificationOptions](#JwsVerificationOptions) +Deep clones the object. + +**Kind**: instance method of [JwsVerificationOptions](#JwsVerificationOptions) + + +### JwsVerificationOptions.fromJSON(json) ⇒ [JwsVerificationOptions](#JwsVerificationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwsVerificationOptions](#JwsVerificationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## Jwt +A wrapper around a JSON Web Token (JWK). + +**Kind**: global class + +* [Jwt](#Jwt) + * [new Jwt(jwt_string)](#new_Jwt_new) + * _instance_ + * [.toString()](#Jwt+toString) ⇒ string + * [.toJSON()](#Jwt+toJSON) ⇒ any + * [.clone()](#Jwt+clone) ⇒ [Jwt](#Jwt) + * _static_ + * [.fromJSON(json)](#Jwt.fromJSON) ⇒ [Jwt](#Jwt) + + + +### new Jwt(jwt_string) +Creates a new [Jwt](#Jwt) from the given string. + + +| Param | Type | +| --- | --- | +| jwt_string | string | + + + +### jwt.toString() ⇒ string +Returns a clone of the JWT string. + +**Kind**: instance method of [Jwt](#Jwt) + + +### jwt.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Jwt](#Jwt) + + +### jwt.clone() ⇒ [Jwt](#Jwt) +Deep clones the object. + +**Kind**: instance method of [Jwt](#Jwt) + + +### Jwt.fromJSON(json) ⇒ [Jwt](#Jwt) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Jwt](#Jwt) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwtCredentialValidationOptions +Options to declare validation criteria when validating credentials. + +**Kind**: global class + +* [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + * [new JwtCredentialValidationOptions([options])](#new_JwtCredentialValidationOptions_new) + * _instance_ + * [.toJSON()](#JwtCredentialValidationOptions+toJSON) ⇒ any + * [.clone()](#JwtCredentialValidationOptions+clone) ⇒ [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + * _static_ + * [.fromJSON(json)](#JwtCredentialValidationOptions.fromJSON) ⇒ [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + + + +### new JwtCredentialValidationOptions([options]) + +| Param | Type | +| --- | --- | +| [options] | IJwtCredentialValidationOptions \| undefined | + + + +### jwtCredentialValidationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + + +### jwtCredentialValidationOptions.clone() ⇒ [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) +Deep clones the object. + +**Kind**: instance method of [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + + +### JwtCredentialValidationOptions.fromJSON(json) ⇒ [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwtCredentialValidator +A type for decoding and validating [Credential](#Credential). + +**Kind**: global class + +* [JwtCredentialValidator](#JwtCredentialValidator) + * [new JwtCredentialValidator(signatureVerifier)](#new_JwtCredentialValidator_new) + * _instance_ + * [.validate(credential_jwt, issuer, options, fail_fast)](#JwtCredentialValidator+validate) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) + * [.verifySignature(credential, trustedIssuers, options)](#JwtCredentialValidator+verifySignature) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) + * _static_ + * [.checkExpiresOnOrAfter(credential, timestamp)](#JwtCredentialValidator.checkExpiresOnOrAfter) + * [.checkIssuedOnOrBefore(credential, timestamp)](#JwtCredentialValidator.checkIssuedOnOrBefore) + * [.checkSubjectHolderRelationship(credential, holder, relationship)](#JwtCredentialValidator.checkSubjectHolderRelationship) + * [.checkStatus(credential, trustedIssuers, statusCheck)](#JwtCredentialValidator.checkStatus) + * [.checkStatusWithStatusList2021(credential, status_list, status_check)](#JwtCredentialValidator.checkStatusWithStatusList2021) + * [.extractIssuer(credential)](#JwtCredentialValidator.extractIssuer) ⇒ [CoreDID](#CoreDID) + * [.extractIssuerFromJwt(credential)](#JwtCredentialValidator.extractIssuerFromJwt) ⇒ [CoreDID](#CoreDID) + + + +### new JwtCredentialValidator(signatureVerifier) +Creates a new [JwtCredentialValidator](#JwtCredentialValidator). If a `signatureVerifier` is provided it will be used when +verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA` +algorithm will be used. + + +| Param | Type | +| --- | --- | +| signatureVerifier | IJwsVerifier | + + + +### jwtCredentialValidator.validate(credential_jwt, issuer, options, fail_fast) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) +Decodes and validates a [Credential](#Credential) issued as a JWS. A [DecodedJwtCredential](#DecodedJwtCredential) is returned upon +success. + +The following properties are validated according to `options`: +- the issuer's signature on the JWS, +- the expiration date, +- the issuance date, +- the semantic structure. + +# Warning +The lack of an error returned from this method is in of itself not enough to conclude that the credential can be +trusted. This section contains more information on additional checks that should be carried out before and after +calling this method. + +## The state of the issuer's DID Document +The caller must ensure that `issuer` represents an up-to-date DID Document. + +## Properties that are not validated + There are many properties defined in [The Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) that are **not** validated, such as: +`proof`, `credentialStatus`, `type`, `credentialSchema`, `refreshService` **and more**. +These should be manually checked after validation, according to your requirements. + +# Errors +An error is returned whenever a validated condition is not satisfied. + +**Kind**: instance method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential_jwt | [Jwt](#Jwt) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| options | [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) | +| fail_fast | [FailFast](#FailFast) | + + + +### jwtCredentialValidator.verifySignature(credential, trustedIssuers, options) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) +Decode and verify the JWS signature of a [Credential](#Credential) issued as a JWT using the DID Document of a trusted +issuer. + +A [DecodedJwtCredential](#DecodedJwtCredential) is returned upon success. + +# Warning +The caller must ensure that the DID Documents of the trusted issuers are up-to-date. + +## Proofs + Only the JWS signature is verified. If the [Credential](#Credential) contains a `proof` property this will not be +verified by this method. + +# Errors +This method immediately returns an error if +the credential issuer' url cannot be parsed to a DID belonging to one of the trusted issuers. Otherwise an attempt +to verify the credential's signature will be made and an error is returned upon failure. + +**Kind**: instance method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Jwt](#Jwt) | +| trustedIssuers | Array.<(CoreDocument\|IToCoreDocument)> | +| options | [JwsVerificationOptions](#JwsVerificationOptions) | + + + +### JwtCredentialValidator.checkExpiresOnOrAfter(credential, timestamp) +Validate that the credential expires on or after the specified timestamp. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| timestamp | [Timestamp](#Timestamp) | + + + +### JwtCredentialValidator.checkIssuedOnOrBefore(credential, timestamp) +Validate that the credential is issued on or before the specified timestamp. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| timestamp | [Timestamp](#Timestamp) | + + + +### JwtCredentialValidator.checkSubjectHolderRelationship(credential, holder, relationship) +Validate that the relationship between the `holder` and the credential subjects is in accordance with +`relationship`. The `holder` parameter is expected to be the URL of the holder. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| holder | string | +| relationship | [SubjectHolderRelationship](#SubjectHolderRelationship) | + + + +### JwtCredentialValidator.checkStatus(credential, trustedIssuers, statusCheck) +Checks whether the credential status has been revoked. + +Only supports `RevocationBitmap2022`. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| trustedIssuers | Array.<(CoreDocument\|IToCoreDocument)> | +| statusCheck | [StatusCheck](#StatusCheck) | + + + +### JwtCredentialValidator.checkStatusWithStatusList2021(credential, status_list, status_check) +Checks wheter the credential status has been revoked using `StatusList2021`. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| status_list | [StatusList2021Credential](#StatusList2021Credential) | +| status_check | [StatusCheck](#StatusCheck) | + + + +### JwtCredentialValidator.extractIssuer(credential) ⇒ [CoreDID](#CoreDID) +Utility for extracting the issuer field of a [Credential](#Credential) as a DID. + +### Errors + +Fails if the issuer field is not a valid DID. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | + + + +### JwtCredentialValidator.extractIssuerFromJwt(credential) ⇒ [CoreDID](#CoreDID) +Utility for extracting the issuer field of a credential in JWT representation as DID. + +# Errors + +If the JWT decoding fails or the issuer field is not a valid DID. + +**Kind**: static method of [JwtCredentialValidator](#JwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [Jwt](#Jwt) | + + + +## JwtDomainLinkageValidator +A validator for a Domain Linkage Configuration and Credentials. + +**Kind**: global class + +* [JwtDomainLinkageValidator](#JwtDomainLinkageValidator) + * [new JwtDomainLinkageValidator(signatureVerifier)](#new_JwtDomainLinkageValidator_new) + * [.validateLinkage(issuer, configuration, domain, options)](#JwtDomainLinkageValidator+validateLinkage) + * [.validateCredential(issuer, credentialJwt, domain, options)](#JwtDomainLinkageValidator+validateCredential) + + + +### new JwtDomainLinkageValidator(signatureVerifier) +Creates a new [JwtDomainLinkageValidator](#JwtDomainLinkageValidator). If a `signatureVerifier` is provided it will be used when +verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA` +algorithm will be used. + + +| Param | Type | +| --- | --- | +| signatureVerifier | IJwsVerifier | + + + +### jwtDomainLinkageValidator.validateLinkage(issuer, configuration, domain, options) +Validates the linkage between a domain and a DID. +[DomainLinkageConfiguration](#DomainLinkageConfiguration) is validated according to [DID Configuration Resource Verification](https://identity.foundation/.well-known/resources/did-configuration/#did-configuration-resource-verification). + +Linkage is valid if no error is thrown. + +# Note: +- Only the [JSON Web Token Proof Format](https://identity.foundation/.well-known/resources/did-configuration/#json-web-token-proof-format) + is supported. +- Only the Credential issued by `issuer` is verified. + +# Errors + + - Semantic structure of `configuration` is invalid. + - `configuration` includes multiple credentials issued by `issuer`. + - Validation of the matched Domain Linkage Credential fails. + +**Kind**: instance method of [JwtDomainLinkageValidator](#JwtDomainLinkageValidator) + +| Param | Type | +| --- | --- | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| configuration | [DomainLinkageConfiguration](#DomainLinkageConfiguration) | +| domain | string | +| options | [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) | + + + +### jwtDomainLinkageValidator.validateCredential(issuer, credentialJwt, domain, options) +Validates a [Domain Linkage Credential](https://identity.foundation/.well-known/resources/did-configuration/#domain-linkage-credential). + +Error will be thrown in case the validation fails. + +**Kind**: instance method of [JwtDomainLinkageValidator](#JwtDomainLinkageValidator) + +| Param | Type | +| --- | --- | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| credentialJwt | [Jwt](#Jwt) | +| domain | string | +| options | [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) | + + + +## JwtPresentationOptions +**Kind**: global class + +* [JwtPresentationOptions](#JwtPresentationOptions) + * [new JwtPresentationOptions([options])](#new_JwtPresentationOptions_new) + * _instance_ + * [.toJSON()](#JwtPresentationOptions+toJSON) ⇒ any + * [.clone()](#JwtPresentationOptions+clone) ⇒ [JwtPresentationOptions](#JwtPresentationOptions) + * _static_ + * [.fromJSON(json)](#JwtPresentationOptions.fromJSON) ⇒ [JwtPresentationOptions](#JwtPresentationOptions) + + + +### new JwtPresentationOptions([options]) +Creates a new [JwtPresentationOptions](#JwtPresentationOptions) from the given fields. + +Throws an error if any of the options are invalid. + + +| Param | Type | +| --- | --- | +| [options] | IJwtPresentationOptions \| undefined | + + + +### jwtPresentationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwtPresentationOptions](#JwtPresentationOptions) + + +### jwtPresentationOptions.clone() ⇒ [JwtPresentationOptions](#JwtPresentationOptions) +Deep clones the object. + +**Kind**: instance method of [JwtPresentationOptions](#JwtPresentationOptions) + + +### JwtPresentationOptions.fromJSON(json) ⇒ [JwtPresentationOptions](#JwtPresentationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwtPresentationOptions](#JwtPresentationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwtPresentationValidationOptions +Options to declare validation criteria when validating presentation. + +**Kind**: global class + +* [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + * [new JwtPresentationValidationOptions([options])](#new_JwtPresentationValidationOptions_new) + * _instance_ + * [.toJSON()](#JwtPresentationValidationOptions+toJSON) ⇒ any + * [.clone()](#JwtPresentationValidationOptions+clone) ⇒ [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + * _static_ + * [.fromJSON(json)](#JwtPresentationValidationOptions.fromJSON) ⇒ [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + + + +### new JwtPresentationValidationOptions([options]) +Creates a new [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) from the given fields. + +Throws an error if any of the options are invalid. + + +| Param | Type | +| --- | --- | +| [options] | IJwtPresentationValidationOptions \| undefined | + + + +### jwtPresentationValidationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + + +### jwtPresentationValidationOptions.clone() ⇒ [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) +Deep clones the object. + +**Kind**: instance method of [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + + +### JwtPresentationValidationOptions.fromJSON(json) ⇒ [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## JwtPresentationValidator +**Kind**: global class + +* [JwtPresentationValidator](#JwtPresentationValidator) + * [new JwtPresentationValidator(signatureVerifier)](#new_JwtPresentationValidator_new) + * _instance_ + * [.validate(presentationJwt, holder, validation_options)](#JwtPresentationValidator+validate) ⇒ [DecodedJwtPresentation](#DecodedJwtPresentation) + * _static_ + * [.checkStructure(presentation)](#JwtPresentationValidator.checkStructure) + * [.extractHolder(presentation)](#JwtPresentationValidator.extractHolder) ⇒ [CoreDID](#CoreDID) + + + +### new JwtPresentationValidator(signatureVerifier) +Creates a new [JwtPresentationValidator](#JwtPresentationValidator). If a `signatureVerifier` is provided it will be used when +verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA` +algorithm will be used. + + +| Param | Type | +| --- | --- | +| signatureVerifier | IJwsVerifier | + + + +### jwtPresentationValidator.validate(presentationJwt, holder, validation_options) ⇒ [DecodedJwtPresentation](#DecodedJwtPresentation) +Validates a [Presentation](#Presentation) encoded as a [Jwt](#Jwt). + +The following properties are validated according to `options`: +- the JWT can be decoded into a semantically valid presentation. +- the expiration and issuance date contained in the JWT claims. +- the holder's signature. + +Validation is done with respect to the properties set in `options`. + +# Warning + +* This method does NOT validate the constituent credentials and therefore also not the relationship between the +credentials' subjects and the presentation holder. This can be done with [JwtCredentialValidationOptions](#JwtCredentialValidationOptions). +* The lack of an error returned from this method is in of itself not enough to conclude that the presentation can +be trusted. This section contains more information on additional checks that should be carried out before and +after calling this method. + +## The state of the supplied DID Documents. + +The caller must ensure that the DID Documents in `holder` are up-to-date. + +# Errors + +An error is returned whenever a validated condition is not satisfied or when decoding fails. + +**Kind**: instance method of [JwtPresentationValidator](#JwtPresentationValidator) + +| Param | Type | +| --- | --- | +| presentationJwt | [Jwt](#Jwt) | +| holder | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| validation_options | [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) | + + + +### JwtPresentationValidator.checkStructure(presentation) +Validates the semantic structure of the [Presentation](#Presentation). + +**Kind**: static method of [JwtPresentationValidator](#JwtPresentationValidator) + +| Param | Type | +| --- | --- | +| presentation | [Presentation](#Presentation) | + + + +### JwtPresentationValidator.extractHolder(presentation) ⇒ [CoreDID](#CoreDID) +Attempt to extract the holder of the presentation. + +# Errors: +* If deserialization/decoding of the presentation fails. +* If the holder can't be parsed as DIDs. + +**Kind**: static method of [JwtPresentationValidator](#JwtPresentationValidator) + +| Param | Type | +| --- | --- | +| presentation | [Jwt](#Jwt) | + + + +## KeyBindingJWTValidationOptions +Options to declare validation criteria when validating credentials. + +**Kind**: global class + +* [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + * [new KeyBindingJWTValidationOptions([options])](#new_KeyBindingJWTValidationOptions_new) + * _instance_ + * [.toJSON()](#KeyBindingJWTValidationOptions+toJSON) ⇒ any + * [.clone()](#KeyBindingJWTValidationOptions+clone) ⇒ [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + * _static_ + * [.fromJSON(json)](#KeyBindingJWTValidationOptions.fromJSON) ⇒ [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + + + +### new KeyBindingJWTValidationOptions([options]) + +| Param | Type | +| --- | --- | +| [options] | IKeyBindingJWTValidationOptions \| undefined | + + + +### keyBindingJWTValidationOptions.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + + +### keyBindingJWTValidationOptions.clone() ⇒ [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) +Deep clones the object. + +**Kind**: instance method of [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + + +### KeyBindingJWTValidationOptions.fromJSON(json) ⇒ [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) +Deserializes an instance from a JSON object. + +**Kind**: static method of [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) + +| Param | Type | +| --- | --- | +| json | any | + + + +## KeyBindingJwtClaims +Claims set for key binding JWT. + +**Kind**: global class + +* [KeyBindingJwtClaims](#KeyBindingJwtClaims) + * [new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, [issued_at], [custom_properties])](#new_KeyBindingJwtClaims_new) + * _instance_ + * [.toString()](#KeyBindingJwtClaims+toString) ⇒ string + * [.iat()](#KeyBindingJwtClaims+iat) ⇒ bigint + * [.aud()](#KeyBindingJwtClaims+aud) ⇒ string + * [.nonce()](#KeyBindingJwtClaims+nonce) ⇒ string + * [.sdHash()](#KeyBindingJwtClaims+sdHash) ⇒ string + * [.customProperties()](#KeyBindingJwtClaims+customProperties) ⇒ Record.<string, any> + * [.toJSON()](#KeyBindingJwtClaims+toJSON) ⇒ any + * [.clone()](#KeyBindingJwtClaims+clone) ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) + * _static_ + * [.keyBindingJwtHeaderTyp()](#KeyBindingJwtClaims.keyBindingJwtHeaderTyp) ⇒ string + * [.fromJSON(json)](#KeyBindingJwtClaims.fromJSON) ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + + +### new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, [issued_at], [custom_properties]) +Creates a new [`KeyBindingJwtClaims`]. +When `issued_at` is left as None, it will automatically default to the current time. + +# Error +When `issued_at` is set to `None` and the system returns time earlier than `SystemTime::UNIX_EPOCH`. + + +| Param | Type | +| --- | --- | +| jwt | string | +| disclosures | Array.<string> | +| nonce | string | +| aud | string | +| [issued_at] | [Timestamp](#Timestamp) \| undefined | +| [custom_properties] | Record.<string, any> \| undefined | + + + +### keyBindingJwtClaims.toString() ⇒ string +Returns a string representation of the claims. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.iat() ⇒ bigint +Returns a copy of the issued at `iat` property. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.aud() ⇒ string +Returns a copy of the audience `aud` property. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.nonce() ⇒ string +Returns a copy of the `nonce` property. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.sdHash() ⇒ string +Returns a copy of the `sd_hash` property. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.customProperties() ⇒ Record.<string, any> +Returns a copy of the custom properties. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### keyBindingJwtClaims.clone() ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) +Deep clones the object. + +**Kind**: instance method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### KeyBindingJwtClaims.keyBindingJwtHeaderTyp() ⇒ string +Returns the value of the `typ` property of the JWT header according to +https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-key-binding-jwt + +**Kind**: static method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + +### KeyBindingJwtClaims.fromJSON(json) ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) +Deserializes an instance from a JSON object. + +**Kind**: static method of [KeyBindingJwtClaims](#KeyBindingJwtClaims) + +| Param | Type | +| --- | --- | +| json | any | + + + +## LinkedDomainService +**Kind**: global class + +* [LinkedDomainService](#LinkedDomainService) + * [new LinkedDomainService(options)](#new_LinkedDomainService_new) + * _instance_ + * [.domains()](#LinkedDomainService+domains) ⇒ Array.<string> + * [.toService()](#LinkedDomainService+toService) ⇒ [Service](#Service) + * [.clone()](#LinkedDomainService+clone) ⇒ [LinkedDomainService](#LinkedDomainService) + * _static_ + * [.fromService(service)](#LinkedDomainService.fromService) ⇒ [LinkedDomainService](#LinkedDomainService) + * [.isValid(service)](#LinkedDomainService.isValid) ⇒ boolean + + + +### new LinkedDomainService(options) +Constructs a new [LinkedDomainService](#LinkedDomainService) that wraps a spec compliant [Linked Domain Service Endpoint](https://identity.foundation/.well-known/resources/did-configuration/#linked-domain-service-endpoint). + +Domain URLs must include the `https` scheme in order to pass the domain linkage validation. + + +| Param | Type | +| --- | --- | +| options | ILinkedDomainService | + + + +### linkedDomainService.domains() ⇒ Array.<string> +Returns the domains contained in the Linked Domain Service. + +**Kind**: instance method of [LinkedDomainService](#LinkedDomainService) + + +### linkedDomainService.toService() ⇒ [Service](#Service) +Returns the inner service which can be added to a DID Document. + +**Kind**: instance method of [LinkedDomainService](#LinkedDomainService) + + +### linkedDomainService.clone() ⇒ [LinkedDomainService](#LinkedDomainService) +Deep clones the object. + +**Kind**: instance method of [LinkedDomainService](#LinkedDomainService) + + +### LinkedDomainService.fromService(service) ⇒ [LinkedDomainService](#LinkedDomainService) +Creates a new [LinkedDomainService](#LinkedDomainService) from a [Service](#Service). + +# Error + +Errors if `service` is not a valid Linked Domain Service. + +**Kind**: static method of [LinkedDomainService](#LinkedDomainService) + +| Param | Type | +| --- | --- | +| service | [Service](#Service) | + + + +### LinkedDomainService.isValid(service) ⇒ boolean +Returns `true` if a [Service](#Service) is a valid Linked Domain Service. + +**Kind**: static method of [LinkedDomainService](#LinkedDomainService) + +| Param | Type | +| --- | --- | +| service | [Service](#Service) | + + + +## MethodData +Supported verification method data formats. + +**Kind**: global class + +* [MethodData](#MethodData) + * _instance_ + * [.tryCustom()](#MethodData+tryCustom) ⇒ [CustomMethodData](#CustomMethodData) + * [.tryDecode()](#MethodData+tryDecode) ⇒ Uint8Array + * [.tryPublicKeyJwk()](#MethodData+tryPublicKeyJwk) ⇒ [Jwk](#Jwk) + * [.toJSON()](#MethodData+toJSON) ⇒ any + * [.clone()](#MethodData+clone) ⇒ [MethodData](#MethodData) + * _static_ + * [.newBase58(data)](#MethodData.newBase58) ⇒ [MethodData](#MethodData) + * [.newMultibase(data)](#MethodData.newMultibase) ⇒ [MethodData](#MethodData) + * [.newJwk(key)](#MethodData.newJwk) ⇒ [MethodData](#MethodData) + * [.newCustom(name, data)](#MethodData.newCustom) ⇒ [MethodData](#MethodData) + * [.fromJSON(json)](#MethodData.fromJSON) ⇒ [MethodData](#MethodData) + + + +### methodData.tryCustom() ⇒ [CustomMethodData](#CustomMethodData) +Returns the wrapped custom method data format is `Custom`. + +**Kind**: instance method of [MethodData](#MethodData) + + +### methodData.tryDecode() ⇒ Uint8Array +Returns a `Uint8Array` containing the decoded bytes of the [MethodData](#MethodData). + +This is generally a public key identified by a [MethodData](#MethodData) value. + +### Errors +Decoding can fail if [MethodData](#MethodData) has invalid content or cannot be +represented as a vector of bytes. + +**Kind**: instance method of [MethodData](#MethodData) + + +### methodData.tryPublicKeyJwk() ⇒ [Jwk](#Jwk) +Returns the wrapped [Jwk](#Jwk) if the format is `PublicKeyJwk`. + +**Kind**: instance method of [MethodData](#MethodData) + + +### methodData.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [MethodData](#MethodData) + + +### methodData.clone() ⇒ [MethodData](#MethodData) +Deep clones the object. + +**Kind**: instance method of [MethodData](#MethodData) + + +### MethodData.newBase58(data) ⇒ [MethodData](#MethodData) +Creates a new [MethodData](#MethodData) variant with Base58-BTC encoded content. + +**Kind**: static method of [MethodData](#MethodData) + +| Param | Type | +| --- | --- | +| data | Uint8Array | + + + +### MethodData.newMultibase(data) ⇒ [MethodData](#MethodData) +Creates a new [MethodData](#MethodData) variant with Multibase-encoded content. + +**Kind**: static method of [MethodData](#MethodData) + +| Param | Type | +| --- | --- | +| data | Uint8Array | + + + +### MethodData.newJwk(key) ⇒ [MethodData](#MethodData) +Creates a new [MethodData](#MethodData) variant consisting of the given `key`. + +### Errors +An error is thrown if the given `key` contains any private components. + +**Kind**: static method of [MethodData](#MethodData) + +| Param | Type | +| --- | --- | +| key | [Jwk](#Jwk) | + + + +### MethodData.newCustom(name, data) ⇒ [MethodData](#MethodData) +Creates a new custom [MethodData](#MethodData). + +**Kind**: static method of [MethodData](#MethodData) + +| Param | Type | +| --- | --- | +| name | string | +| data | any | + + + +### MethodData.fromJSON(json) ⇒ [MethodData](#MethodData) +Deserializes an instance from a JSON object. + +**Kind**: static method of [MethodData](#MethodData) + +| Param | Type | +| --- | --- | +| json | any | + + + +## MethodDigest +Unique identifier of a [VerificationMethod](#VerificationMethod). + +NOTE: +This class does not have a JSON representation, +use the methods `pack` and `unpack` instead. + +**Kind**: global class + +* [MethodDigest](#MethodDigest) + * [new MethodDigest(verification_method)](#new_MethodDigest_new) + * _instance_ + * [.pack()](#MethodDigest+pack) ⇒ Uint8Array + * [.clone()](#MethodDigest+clone) ⇒ [MethodDigest](#MethodDigest) + * _static_ + * [.unpack(bytes)](#MethodDigest.unpack) ⇒ [MethodDigest](#MethodDigest) + + + +### new MethodDigest(verification_method) + +| Param | Type | +| --- | --- | +| verification_method | [VerificationMethod](#VerificationMethod) | + + + +### methodDigest.pack() ⇒ Uint8Array +Packs [MethodDigest](#MethodDigest) into bytes. + +**Kind**: instance method of [MethodDigest](#MethodDigest) + + +### methodDigest.clone() ⇒ [MethodDigest](#MethodDigest) +Deep clones the object. + +**Kind**: instance method of [MethodDigest](#MethodDigest) + + +### MethodDigest.unpack(bytes) ⇒ [MethodDigest](#MethodDigest) +Unpacks bytes into [MethodDigest](#MethodDigest). + +**Kind**: static method of [MethodDigest](#MethodDigest) + +| Param | Type | +| --- | --- | +| bytes | Uint8Array | + + + +## MethodScope +Supported verification method types. + +**Kind**: global class + +* [MethodScope](#MethodScope) + * _instance_ + * [.toString()](#MethodScope+toString) ⇒ string + * [.toJSON()](#MethodScope+toJSON) ⇒ any + * [.clone()](#MethodScope+clone) ⇒ [MethodScope](#MethodScope) + * _static_ + * [.VerificationMethod()](#MethodScope.VerificationMethod) ⇒ [MethodScope](#MethodScope) + * [.Authentication()](#MethodScope.Authentication) ⇒ [MethodScope](#MethodScope) + * [.AssertionMethod()](#MethodScope.AssertionMethod) ⇒ [MethodScope](#MethodScope) + * [.KeyAgreement()](#MethodScope.KeyAgreement) ⇒ [MethodScope](#MethodScope) + * [.CapabilityDelegation()](#MethodScope.CapabilityDelegation) ⇒ [MethodScope](#MethodScope) + * [.CapabilityInvocation()](#MethodScope.CapabilityInvocation) ⇒ [MethodScope](#MethodScope) + * [.fromJSON(json)](#MethodScope.fromJSON) ⇒ [MethodScope](#MethodScope) + + + +### methodScope.toString() ⇒ string +Returns the [MethodScope](#MethodScope) as a string. + +**Kind**: instance method of [MethodScope](#MethodScope) + + +### methodScope.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [MethodScope](#MethodScope) + + +### methodScope.clone() ⇒ [MethodScope](#MethodScope) +Deep clones the object. + +**Kind**: instance method of [MethodScope](#MethodScope) + + +### MethodScope.VerificationMethod() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.Authentication() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.AssertionMethod() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.KeyAgreement() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.CapabilityDelegation() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.CapabilityInvocation() ⇒ [MethodScope](#MethodScope) +**Kind**: static method of [MethodScope](#MethodScope) + + +### MethodScope.fromJSON(json) ⇒ [MethodScope](#MethodScope) +Deserializes an instance from a JSON object. + +**Kind**: static method of [MethodScope](#MethodScope) + +| Param | Type | +| --- | --- | +| json | any | + + + +## MethodType +Supported verification method types. + +**Kind**: global class + +* [MethodType](#MethodType) + * _instance_ + * [.toString()](#MethodType+toString) ⇒ string + * [.toJSON()](#MethodType+toJSON) ⇒ any + * [.clone()](#MethodType+clone) ⇒ [MethodType](#MethodType) + * _static_ + * [.Ed25519VerificationKey2018()](#MethodType.Ed25519VerificationKey2018) ⇒ [MethodType](#MethodType) + * [.X25519KeyAgreementKey2019()](#MethodType.X25519KeyAgreementKey2019) ⇒ [MethodType](#MethodType) + * ~~[.JsonWebKey()](#MethodType.JsonWebKey)~~ + * [.JsonWebKey2020()](#MethodType.JsonWebKey2020) ⇒ [MethodType](#MethodType) + * [.custom(type_)](#MethodType.custom) ⇒ [MethodType](#MethodType) + * [.fromJSON(json)](#MethodType.fromJSON) ⇒ [MethodType](#MethodType) + + + +### methodType.toString() ⇒ string +Returns the [MethodType](#MethodType) as a string. + +**Kind**: instance method of [MethodType](#MethodType) + + +### methodType.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [MethodType](#MethodType) + + +### methodType.clone() ⇒ [MethodType](#MethodType) +Deep clones the object. + +**Kind**: instance method of [MethodType](#MethodType) + + +### MethodType.Ed25519VerificationKey2018() ⇒ [MethodType](#MethodType) +**Kind**: static method of [MethodType](#MethodType) + + +### MethodType.X25519KeyAgreementKey2019() ⇒ [MethodType](#MethodType) +**Kind**: static method of [MethodType](#MethodType) + + +### ~~MethodType.JsonWebKey()~~ +***Deprecated*** + +**Kind**: static method of [MethodType](#MethodType) + + +### MethodType.JsonWebKey2020() ⇒ [MethodType](#MethodType) +A verification method for use with JWT verification as prescribed by the [Jwk](#Jwk) +in the `publicKeyJwk` entry. + +**Kind**: static method of [MethodType](#MethodType) + + +### MethodType.custom(type_) ⇒ [MethodType](#MethodType) +A custom method. + +**Kind**: static method of [MethodType](#MethodType) + +| Param | Type | +| --- | --- | +| type_ | string | + + + +### MethodType.fromJSON(json) ⇒ [MethodType](#MethodType) +Deserializes an instance from a JSON object. + +**Kind**: static method of [MethodType](#MethodType) + +| Param | Type | +| --- | --- | +| json | any | + + + +## PayloadEntry +**Kind**: global class + +* [PayloadEntry](#PayloadEntry) + * [.1](#PayloadEntry+1) ⇒ [PayloadType](#PayloadType) + * [.1](#PayloadEntry+1) + * [.value](#PayloadEntry+value) + * [.value](#PayloadEntry+value) ⇒ any + + + +### payloadEntry.1 ⇒ [PayloadType](#PayloadType) +**Kind**: instance property of [PayloadEntry](#PayloadEntry) + + +### payloadEntry.1 +**Kind**: instance property of [PayloadEntry](#PayloadEntry) + +| Param | Type | +| --- | --- | +| arg0 | [PayloadType](#PayloadType) | + + + +### payloadEntry.value +**Kind**: instance property of [PayloadEntry](#PayloadEntry) + +| Param | Type | +| --- | --- | +| value | any | + + + +### payloadEntry.value ⇒ any +**Kind**: instance property of [PayloadEntry](#PayloadEntry) + + +## Payloads +**Kind**: global class + +* [Payloads](#Payloads) + * [new Payloads(entries)](#new_Payloads_new) + * _instance_ + * [.toJSON()](#Payloads+toJSON) ⇒ any + * [.clone()](#Payloads+clone) ⇒ [Payloads](#Payloads) + * [.getValues()](#Payloads+getValues) ⇒ Array.<any> + * [.getUndisclosedIndexes()](#Payloads+getUndisclosedIndexes) ⇒ Uint32Array + * [.getDisclosedIndexes()](#Payloads+getDisclosedIndexes) ⇒ Uint32Array + * [.getUndisclosedPayloads()](#Payloads+getUndisclosedPayloads) ⇒ Array.<any> + * [.getDisclosedPayloads()](#Payloads+getDisclosedPayloads) ⇒ [Payloads](#Payloads) + * [.setUndisclosed(index)](#Payloads+setUndisclosed) + * [.replacePayloadAtIndex(index, value)](#Payloads+replacePayloadAtIndex) ⇒ any + * _static_ + * [.fromJSON(json)](#Payloads.fromJSON) ⇒ [Payloads](#Payloads) + * [.newFromValues(values)](#Payloads.newFromValues) ⇒ [Payloads](#Payloads) + + + +### new Payloads(entries) + +| Param | Type | +| --- | --- | +| entries | [Array.<PayloadEntry>](#PayloadEntry) | + + + +### payloads.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.clone() ⇒ [Payloads](#Payloads) +Deep clones the object. + +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.getValues() ⇒ Array.<any> +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.getUndisclosedIndexes() ⇒ Uint32Array +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.getDisclosedIndexes() ⇒ Uint32Array +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.getUndisclosedPayloads() ⇒ Array.<any> +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.getDisclosedPayloads() ⇒ [Payloads](#Payloads) +**Kind**: instance method of [Payloads](#Payloads) + + +### payloads.setUndisclosed(index) +**Kind**: instance method of [Payloads](#Payloads) + +| Param | Type | +| --- | --- | +| index | number | + + + +### payloads.replacePayloadAtIndex(index, value) ⇒ any +**Kind**: instance method of [Payloads](#Payloads) + +| Param | Type | +| --- | --- | +| index | number | +| value | any | + + + +### Payloads.fromJSON(json) ⇒ [Payloads](#Payloads) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Payloads](#Payloads) + +| Param | Type | +| --- | --- | +| json | any | + + + +### Payloads.newFromValues(values) ⇒ [Payloads](#Payloads) +**Kind**: static method of [Payloads](#Payloads) + +| Param | Type | +| --- | --- | +| values | Array.<any> | + + + +## Presentation +**Kind**: global class + +* [Presentation](#Presentation) + * [new Presentation(values)](#new_Presentation_new) + * _instance_ + * [.context()](#Presentation+context) ⇒ Array.<(string\|Record.<string, any>)> + * [.id()](#Presentation+id) ⇒ string \| undefined + * [.type()](#Presentation+type) ⇒ Array.<string> + * [.verifiableCredential()](#Presentation+verifiableCredential) ⇒ [Array.<UnknownCredential>](#UnknownCredential) + * [.holder()](#Presentation+holder) ⇒ string + * [.refreshService()](#Presentation+refreshService) ⇒ Array.<RefreshService> + * [.termsOfUse()](#Presentation+termsOfUse) ⇒ Array.<Policy> + * [.proof()](#Presentation+proof) ⇒ [Proof](#Proof) \| undefined + * [.setProof([proof])](#Presentation+setProof) + * [.properties()](#Presentation+properties) ⇒ Map.<string, any> + * [.toJSON()](#Presentation+toJSON) ⇒ any + * [.clone()](#Presentation+clone) ⇒ [Presentation](#Presentation) + * _static_ + * [.BaseContext()](#Presentation.BaseContext) ⇒ string + * [.BaseType()](#Presentation.BaseType) ⇒ string + * [.fromJSON(json)](#Presentation.fromJSON) ⇒ [Presentation](#Presentation) + + + +### new Presentation(values) +Constructs a new presentation. + + +| Param | Type | +| --- | --- | +| values | IPresentation | + + + +### presentation.context() ⇒ Array.<(string\|Record.<string, any>)> +Returns a copy of the JSON-LD context(s) applicable to the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.id() ⇒ string \| undefined +Returns a copy of the unique `URI` identifying the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.type() ⇒ Array.<string> +Returns a copy of the URIs defining the type of the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.verifiableCredential() ⇒ [Array.<UnknownCredential>](#UnknownCredential) +Returns the JWT credentials expressing the claims of the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.holder() ⇒ string +Returns a copy of the URI of the entity that generated the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.refreshService() ⇒ Array.<RefreshService> +Returns a copy of the service(s) used to refresh an expired [Credential](#Credential) in the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.termsOfUse() ⇒ Array.<Policy> +Returns a copy of the terms-of-use specified by the presentation holder + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.proof() ⇒ [Proof](#Proof) \| undefined +Optional cryptographic proof, unrelated to JWT. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.setProof([proof]) +Sets the proof property of the [Presentation](#Presentation). + +Note that this proof is not related to JWT. + +**Kind**: instance method of [Presentation](#Presentation) + +| Param | Type | +| --- | --- | +| [proof] | [Proof](#Proof) \| undefined | + + + +### presentation.properties() ⇒ Map.<string, any> +Returns a copy of the miscellaneous properties on the presentation. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Presentation](#Presentation) + + +### presentation.clone() ⇒ [Presentation](#Presentation) +Deep clones the object. + +**Kind**: instance method of [Presentation](#Presentation) + + +### Presentation.BaseContext() ⇒ string +Returns the base JSON-LD context. + +**Kind**: static method of [Presentation](#Presentation) + + +### Presentation.BaseType() ⇒ string +Returns the base type. + +**Kind**: static method of [Presentation](#Presentation) + + +### Presentation.fromJSON(json) ⇒ [Presentation](#Presentation) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Presentation](#Presentation) + +| Param | Type | +| --- | --- | +| json | any | + + + +## PresentationProtectedHeader +**Kind**: global class + +* [PresentationProtectedHeader](#PresentationProtectedHeader) + * [.alg](#PresentationProtectedHeader+alg) ⇒ [PresentationProofAlgorithm](#PresentationProofAlgorithm) + * [.alg](#PresentationProtectedHeader+alg) + * [.kid](#PresentationProtectedHeader+kid) ⇒ string \| undefined + * [.kid](#PresentationProtectedHeader+kid) + * [.aud](#PresentationProtectedHeader+aud) ⇒ string \| undefined + * [.aud](#PresentationProtectedHeader+aud) + * [.nonce](#PresentationProtectedHeader+nonce) ⇒ string \| undefined + * [.nonce](#PresentationProtectedHeader+nonce) + + + +### presentationProtectedHeader.alg ⇒ [PresentationProofAlgorithm](#PresentationProofAlgorithm) +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + + +### presentationProtectedHeader.alg +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + +| Param | Type | +| --- | --- | +| arg0 | [PresentationProofAlgorithm](#PresentationProofAlgorithm) | + + + +### presentationProtectedHeader.kid ⇒ string \| undefined +ID for the key used for the JWP. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + + +### presentationProtectedHeader.kid +ID for the key used for the JWP. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### presentationProtectedHeader.aud ⇒ string \| undefined +Who have received the JPT. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + + +### presentationProtectedHeader.aud +Who have received the JPT. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +### presentationProtectedHeader.nonce ⇒ string \| undefined +For replay attacks. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + + +### presentationProtectedHeader.nonce +For replay attacks. + +**Kind**: instance property of [PresentationProtectedHeader](#PresentationProtectedHeader) + +| Param | Type | +| --- | --- | +| [arg0] | string \| undefined | + + + +## Proof +Represents a cryptographic proof that can be used to validate verifiable credentials and +presentations. + +This representation does not inherently implement any standard; instead, it +can be utilized to implement standards or user-defined proofs. The presence of the +`type` field is necessary to accommodate different types of cryptographic proofs. + +Note that this proof is not related to JWT and can be used in combination or as an alternative +to it. + +**Kind**: global class + +* [Proof](#Proof) + * [new Proof(type_, properties)](#new_Proof_new) + * _instance_ + * [.type()](#Proof+type) ⇒ string + * [.properties()](#Proof+properties) ⇒ any + * [.toJSON()](#Proof+toJSON) ⇒ any + * [.clone()](#Proof+clone) ⇒ [Proof](#Proof) + * _static_ + * [.fromJSON(json)](#Proof.fromJSON) ⇒ [Proof](#Proof) + + + +### new Proof(type_, properties) + +| Param | Type | +| --- | --- | +| type_ | string | +| properties | any | + + + +### proof.type() ⇒ string +Returns the type of proof. + +**Kind**: instance method of [Proof](#Proof) + + +### proof.properties() ⇒ any +Returns the properties of the proof. + +**Kind**: instance method of [Proof](#Proof) + + +### proof.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Proof](#Proof) + + +### proof.clone() ⇒ [Proof](#Proof) +Deep clones the object. + +**Kind**: instance method of [Proof](#Proof) + + +### Proof.fromJSON(json) ⇒ [Proof](#Proof) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Proof](#Proof) + +| Param | Type | +| --- | --- | +| json | any | + + + +## ProofUpdateCtx +**Kind**: global class + +* [ProofUpdateCtx](#ProofUpdateCtx) + * [.old_start_validity_timeframe](#ProofUpdateCtx+old_start_validity_timeframe) ⇒ Uint8Array + * [.old_start_validity_timeframe](#ProofUpdateCtx+old_start_validity_timeframe) + * [.new_start_validity_timeframe](#ProofUpdateCtx+new_start_validity_timeframe) ⇒ Uint8Array + * [.new_start_validity_timeframe](#ProofUpdateCtx+new_start_validity_timeframe) + * [.old_end_validity_timeframe](#ProofUpdateCtx+old_end_validity_timeframe) ⇒ Uint8Array + * [.old_end_validity_timeframe](#ProofUpdateCtx+old_end_validity_timeframe) + * [.new_end_validity_timeframe](#ProofUpdateCtx+new_end_validity_timeframe) ⇒ Uint8Array + * [.new_end_validity_timeframe](#ProofUpdateCtx+new_end_validity_timeframe) + * [.index_start_validity_timeframe](#ProofUpdateCtx+index_start_validity_timeframe) ⇒ number + * [.index_start_validity_timeframe](#ProofUpdateCtx+index_start_validity_timeframe) + * [.index_end_validity_timeframe](#ProofUpdateCtx+index_end_validity_timeframe) ⇒ number + * [.index_end_validity_timeframe](#ProofUpdateCtx+index_end_validity_timeframe) + * [.number_of_signed_messages](#ProofUpdateCtx+number_of_signed_messages) ⇒ number + * [.number_of_signed_messages](#ProofUpdateCtx+number_of_signed_messages) + + + +### proofUpdateCtx.old\_start\_validity\_timeframe ⇒ Uint8Array +Old `startValidityTimeframe` value + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.old\_start\_validity\_timeframe +Old `startValidityTimeframe` value + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | Uint8Array | + + + +### proofUpdateCtx.new\_start\_validity\_timeframe ⇒ Uint8Array +New `startValidityTimeframe` value to be signed + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.new\_start\_validity\_timeframe +New `startValidityTimeframe` value to be signed + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | Uint8Array | + + + +### proofUpdateCtx.old\_end\_validity\_timeframe ⇒ Uint8Array +Old `endValidityTimeframe` value + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.old\_end\_validity\_timeframe +Old `endValidityTimeframe` value + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | Uint8Array | + + + +### proofUpdateCtx.new\_end\_validity\_timeframe ⇒ Uint8Array +New `endValidityTimeframe` value to be signed + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.new\_end\_validity\_timeframe +New `endValidityTimeframe` value to be signed + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | Uint8Array | + + + +### proofUpdateCtx.index\_start\_validity\_timeframe ⇒ number +Index of `startValidityTimeframe` claim inside the array of Claims + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.index\_start\_validity\_timeframe +Index of `startValidityTimeframe` claim inside the array of Claims + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | number | + + + +### proofUpdateCtx.index\_end\_validity\_timeframe ⇒ number +Index of `endValidityTimeframe` claim inside the array of Claims + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.index\_end\_validity\_timeframe +Index of `endValidityTimeframe` claim inside the array of Claims + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | number | + + + +### proofUpdateCtx.number\_of\_signed\_messages ⇒ number +Number of signed messages, number of payloads in a JWP + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + + +### proofUpdateCtx.number\_of\_signed\_messages +Number of signed messages, number of payloads in a JWP + +**Kind**: instance property of [ProofUpdateCtx](#ProofUpdateCtx) + +| Param | Type | +| --- | --- | +| arg0 | number | + + + +## Resolver +Convenience type for resolving DID documents from different DID methods. + +Also provides methods for resolving DID Documents associated with +verifiable [Credential](#Credential)s and [Presentation](#Presentation)s. + +# Configuration + +The resolver will only be able to resolve DID documents for methods it has been configured for in the constructor. + +**Kind**: global class + +* [Resolver](#Resolver) + * [new Resolver(config)](#new_Resolver_new) + * [.resolve(did)](#Resolver+resolve) ⇒ Promise.<(CoreDocument\|IToCoreDocument)> + * [.resolveMultiple(dids)](#Resolver+resolveMultiple) ⇒ Promise.<Array.<(CoreDocument\|IToCoreDocument)>> + + + +### new Resolver(config) +Constructs a new [Resolver](#Resolver). + +# Errors +If both a `client` is given and the `handlers` map contains the "iota" key the construction process +will throw an error because the handler for the "iota" method then becomes ambiguous. + + +| Param | Type | +| --- | --- | +| config | ResolverConfig | + + + +### resolver.resolve(did) ⇒ Promise.<(CoreDocument\|IToCoreDocument)> +Fetches the DID Document of the given DID. + +### Errors + +Errors if the resolver has not been configured to handle the method +corresponding to the given DID or the resolution process itself fails. + +**Kind**: instance method of [Resolver](#Resolver) + +| Param | Type | +| --- | --- | +| did | string | + + + +### resolver.resolveMultiple(dids) ⇒ Promise.<Array.<(CoreDocument\|IToCoreDocument)>> +Concurrently fetches the DID Documents of the multiple given DIDs. + +# Errors +* If the resolver has not been configured to handle the method of any of the given DIDs. +* If the resolution process of any DID fails. + +## Note +* The order of the documents in the returned array matches that in `dids`. +* If `dids` contains duplicates, these will be resolved only once and the resolved document +is copied into the returned array to match the order of `dids`. + +**Kind**: instance method of [Resolver](#Resolver) + +| Param | Type | +| --- | --- | +| dids | Array.<string> | + + + +## RevocationBitmap +A compressed bitmap for managing credential revocation. + +**Kind**: global class + +* [RevocationBitmap](#RevocationBitmap) + * [new RevocationBitmap()](#new_RevocationBitmap_new) + * _instance_ + * [.isRevoked(index)](#RevocationBitmap+isRevoked) ⇒ boolean + * [.revoke(index)](#RevocationBitmap+revoke) ⇒ boolean + * [.unrevoke(index)](#RevocationBitmap+unrevoke) ⇒ boolean + * [.len()](#RevocationBitmap+len) ⇒ number + * [.toService(serviceId)](#RevocationBitmap+toService) ⇒ [Service](#Service) + * _static_ + * [.type()](#RevocationBitmap.type) ⇒ string + * [.fromEndpoint(service)](#RevocationBitmap.fromEndpoint) ⇒ [RevocationBitmap](#RevocationBitmap) + + + +### new RevocationBitmap() +Creates a new [RevocationBitmap](#RevocationBitmap) instance. + + + +### revocationBitmap.isRevoked(index) ⇒ boolean +Returns `true` if the credential at the given `index` is revoked. + +**Kind**: instance method of [RevocationBitmap](#RevocationBitmap) + +| Param | Type | +| --- | --- | +| index | number | + + + +### revocationBitmap.revoke(index) ⇒ boolean +Mark the given index as revoked. + +Returns true if the index was absent from the set. + +**Kind**: instance method of [RevocationBitmap](#RevocationBitmap) + +| Param | Type | +| --- | --- | +| index | number | + + + +### revocationBitmap.unrevoke(index) ⇒ boolean +Mark the index as not revoked. + +Returns true if the index was present in the set. + +**Kind**: instance method of [RevocationBitmap](#RevocationBitmap) + +| Param | Type | +| --- | --- | +| index | number | + + + +### revocationBitmap.len() ⇒ number +Returns the number of revoked credentials. + +**Kind**: instance method of [RevocationBitmap](#RevocationBitmap) + + +### revocationBitmap.toService(serviceId) ⇒ [Service](#Service) +Return a `Service` with: +- the service's id set to `serviceId`, +- of type `RevocationBitmap2022`, +- and with the bitmap embedded in a data url in the service's endpoint. + +**Kind**: instance method of [RevocationBitmap](#RevocationBitmap) + +| Param | Type | +| --- | --- | +| serviceId | [DIDUrl](#DIDUrl) | + + + +### RevocationBitmap.type() ⇒ string +The name of the service type. + +**Kind**: static method of [RevocationBitmap](#RevocationBitmap) + + +### RevocationBitmap.fromEndpoint(service) ⇒ [RevocationBitmap](#RevocationBitmap) +Try to construct a [RevocationBitmap](#RevocationBitmap) from a service +if it is a valid Revocation Bitmap Service. + +**Kind**: static method of [RevocationBitmap](#RevocationBitmap) + +| Param | Type | +| --- | --- | +| service | [Service](#Service) | + + + +## RevocationTimeframeStatus +Information used to determine the current status of a [Credential](#Credential). + +**Kind**: global class + +* [RevocationTimeframeStatus](#RevocationTimeframeStatus) + * [new RevocationTimeframeStatus(id, index, duration, [start_validity])](#new_RevocationTimeframeStatus_new) + * _instance_ + * [.clone()](#RevocationTimeframeStatus+clone) ⇒ [RevocationTimeframeStatus](#RevocationTimeframeStatus) + * [.toJSON()](#RevocationTimeframeStatus+toJSON) ⇒ any + * [.startValidityTimeframe()](#RevocationTimeframeStatus+startValidityTimeframe) ⇒ [Timestamp](#Timestamp) + * [.endValidityTimeframe()](#RevocationTimeframeStatus+endValidityTimeframe) ⇒ [Timestamp](#Timestamp) + * [.id()](#RevocationTimeframeStatus+id) ⇒ string + * [.index()](#RevocationTimeframeStatus+index) ⇒ number \| undefined + * _static_ + * [.fromJSON(json)](#RevocationTimeframeStatus.fromJSON) ⇒ [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + + +### new RevocationTimeframeStatus(id, index, duration, [start_validity]) +Creates a new `RevocationTimeframeStatus`. + + +| Param | Type | +| --- | --- | +| id | string | +| index | number | +| duration | [Duration](#Duration) | +| [start_validity] | [Timestamp](#Timestamp) \| undefined | + + + +### revocationTimeframeStatus.clone() ⇒ [RevocationTimeframeStatus](#RevocationTimeframeStatus) +Deep clones the object. + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### revocationTimeframeStatus.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### revocationTimeframeStatus.startValidityTimeframe() ⇒ [Timestamp](#Timestamp) +Get startValidityTimeframe value. + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### revocationTimeframeStatus.endValidityTimeframe() ⇒ [Timestamp](#Timestamp) +Get endValidityTimeframe value. + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### revocationTimeframeStatus.id() ⇒ string +Return the URL fo the `RevocationBitmapStatus`. + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### revocationTimeframeStatus.index() ⇒ number \| undefined +Return the index of the credential in the issuer's revocation bitmap + +**Kind**: instance method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + + +### RevocationTimeframeStatus.fromJSON(json) ⇒ [RevocationTimeframeStatus](#RevocationTimeframeStatus) +Deserializes an instance from a JSON object. + +**Kind**: static method of [RevocationTimeframeStatus](#RevocationTimeframeStatus) + +| Param | Type | +| --- | --- | +| json | any | + + + +## SdJwt +Representation of an SD-JWT of the format +`~~~...~~`. + +**Kind**: global class + +* [SdJwt](#SdJwt) + * [new SdJwt(jwt, disclosures, [key_binding_jwt])](#new_SdJwt_new) + * _instance_ + * [.presentation()](#SdJwt+presentation) ⇒ string + * [.toString()](#SdJwt+toString) ⇒ string + * [.jwt()](#SdJwt+jwt) ⇒ string + * [.disclosures()](#SdJwt+disclosures) ⇒ Array.<string> + * [.keyBindingJwt()](#SdJwt+keyBindingJwt) ⇒ string \| undefined + * [.clone()](#SdJwt+clone) ⇒ [SdJwt](#SdJwt) + * _static_ + * [.parse(sd_jwt)](#SdJwt.parse) ⇒ [SdJwt](#SdJwt) + + + +### new SdJwt(jwt, disclosures, [key_binding_jwt]) +Creates a new `SdJwt` from its components. + + +| Param | Type | +| --- | --- | +| jwt | string | +| disclosures | Array.<string> | +| [key_binding_jwt] | string \| undefined | + + + +### sdJwt.presentation() ⇒ string +Serializes the components into the final SD-JWT. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### sdJwt.toString() ⇒ string +Serializes the components into the final SD-JWT. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### sdJwt.jwt() ⇒ string +The JWT part. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### sdJwt.disclosures() ⇒ Array.<string> +The disclosures part. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### sdJwt.keyBindingJwt() ⇒ string \| undefined +The optional key binding JWT. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### sdJwt.clone() ⇒ [SdJwt](#SdJwt) +Deep clones the object. + +**Kind**: instance method of [SdJwt](#SdJwt) + + +### SdJwt.parse(sd_jwt) ⇒ [SdJwt](#SdJwt) +Parses an SD-JWT into its components as [`SdJwt`]. + +## Error +Returns `DeserializationError` if parsing fails. + +**Kind**: static method of [SdJwt](#SdJwt) + +| Param | Type | +| --- | --- | +| sd_jwt | string | + + + +## SdJwtCredentialValidator +A type for decoding and validating [Credential](#Credential). + +**Kind**: global class + +* [SdJwtCredentialValidator](#SdJwtCredentialValidator) + * [new SdJwtCredentialValidator(signatureVerifier)](#new_SdJwtCredentialValidator_new) + * [.validateCredential(sd_jwt, issuer, options, fail_fast)](#SdJwtCredentialValidator+validateCredential) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) + * [.verifySignature(credential, trustedIssuers, options)](#SdJwtCredentialValidator+verifySignature) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) + * [.validateKeyBindingJwt(sdJwt, holder, options)](#SdJwtCredentialValidator+validateKeyBindingJwt) ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) + + + +### new SdJwtCredentialValidator(signatureVerifier) +Creates a new `SdJwtCredentialValidator`. If a `signatureVerifier` is provided it will be used when +verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA` +algorithm will be used. + + +| Param | Type | +| --- | --- | +| signatureVerifier | IJwsVerifier | + + + +### sdJwtCredentialValidator.validateCredential(sd_jwt, issuer, options, fail_fast) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) +Decodes and validates a `Credential` issued as an SD-JWT. A `DecodedJwtCredential` is returned upon success. +The credential is constructed by replacing disclosures following the +[`Selective Disclosure for JWTs (SD-JWT)`](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html) standard. + +The following properties are validated according to `options`: +- the issuer's signature on the JWS, +- the expiration date, +- the issuance date, +- the semantic structure. + +# Warning +* The key binding JWT is not validated. If needed, it must be validated separately using +`SdJwtValidator::validate_key_binding_jwt`. +* The lack of an error returned from this method is in of itself not enough to conclude that the credential can be +trusted. This section contains more information on additional checks that should be carried out before and after +calling this method. + +## The state of the issuer's DID Document +The caller must ensure that `issuer` represents an up-to-date DID Document. + +## Properties that are not validated + There are many properties defined in [The Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) that are **not** validated, such as: +`proof`, `credentialStatus`, `type`, `credentialSchema`, `refreshService` **and more**. +These should be manually checked after validation, according to your requirements. + +# Errors +An error is returned whenever a validated condition is not satisfied. + +**Kind**: instance method of [SdJwtCredentialValidator](#SdJwtCredentialValidator) + +| Param | Type | +| --- | --- | +| sd_jwt | [SdJwt](#SdJwt) | +| issuer | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| options | [JwtCredentialValidationOptions](#JwtCredentialValidationOptions) | +| fail_fast | [FailFast](#FailFast) | + + + +### sdJwtCredentialValidator.verifySignature(credential, trustedIssuers, options) ⇒ [DecodedJwtCredential](#DecodedJwtCredential) +Decode and verify the JWS signature of a `Credential` issued as an SD-JWT using the DID Document of a trusted +issuer and replaces the disclosures. + +A `DecodedJwtCredential` is returned upon success. + +# Warning +The caller must ensure that the DID Documents of the trusted issuers are up-to-date. + +## Proofs + Only the JWS signature is verified. If the `Credential` contains a `proof` property this will not be verified +by this method. + +# Errors +* If the issuer' URL cannot be parsed. +* If Signature verification fails. +* If SD decoding fails. + +**Kind**: instance method of [SdJwtCredentialValidator](#SdJwtCredentialValidator) + +| Param | Type | +| --- | --- | +| credential | [SdJwt](#SdJwt) | +| trustedIssuers | Array.<(CoreDocument\|IToCoreDocument)> | +| options | [JwsVerificationOptions](#JwsVerificationOptions) | + + + +### sdJwtCredentialValidator.validateKeyBindingJwt(sdJwt, holder, options) ⇒ [KeyBindingJwtClaims](#KeyBindingJwtClaims) +Validates a Key Binding JWT (KB-JWT) according to `https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-key-binding-jwt`. +The Validation process includes: + * Signature validation using public key materials defined in the `holder` document. + * `typ` value in KB-JWT header. + * `sd_hash` claim value in the KB-JWT claim. + * Optional `nonce`, `aud` and issuance date validation. + +**Kind**: instance method of [SdJwtCredentialValidator](#SdJwtCredentialValidator) + +| Param | Type | +| --- | --- | +| sdJwt | [SdJwt](#SdJwt) | +| holder | [CoreDocument](#CoreDocument) \| IToCoreDocument | +| options | [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions) | + + + +## SdObjectDecoder +Substitutes digests in an SD-JWT object by their corresponding plaintext values provided by disclosures. + +**Kind**: global class + +* [SdObjectDecoder](#SdObjectDecoder) + * [new SdObjectDecoder()](#new_SdObjectDecoder_new) + * [.decode(object, disclosures)](#SdObjectDecoder+decode) ⇒ Record.<string, any> + + + +### new SdObjectDecoder() +Creates a new `SdObjectDecoder` with `sha-256` hasher. + + + +### sdObjectDecoder.decode(object, disclosures) ⇒ Record.<string, any> +Decodes an SD-JWT `object` containing by Substituting the digests with their corresponding +plaintext values provided by `disclosures`. + +## Notes +* Claims like `exp` or `iat` are not validated in the process of decoding. +* `_sd_alg` property will be removed if present. + +**Kind**: instance method of [SdObjectDecoder](#SdObjectDecoder) + +| Param | Type | +| --- | --- | +| object | Record.<string, any> | +| disclosures | Array.<string> | + + + +## SdObjectEncoder +Transforms a JSON object into an SD-JWT object by substituting selected values +with their corresponding disclosure digests. + +Note: digests are created using the sha-256 algorithm. + +**Kind**: global class + +* [SdObjectEncoder](#SdObjectEncoder) + * [new SdObjectEncoder(object)](#new_SdObjectEncoder_new) + * [.conceal(path, [salt])](#SdObjectEncoder+conceal) ⇒ [Disclosure](#Disclosure) + * [.addSdAlgProperty()](#SdObjectEncoder+addSdAlgProperty) + * [.encodeToString()](#SdObjectEncoder+encodeToString) ⇒ string + * [.toString()](#SdObjectEncoder+toString) ⇒ string + * [.encodeToObject()](#SdObjectEncoder+encodeToObject) ⇒ Record.<string, any> + * [.toJSON()](#SdObjectEncoder+toJSON) ⇒ any + * [.addDecoys(path, number_of_decoys)](#SdObjectEncoder+addDecoys) + + + +### new SdObjectEncoder(object) +Creates a new `SdObjectEncoder` with `sha-256` hash function. + + +| Param | Type | +| --- | --- | +| object | any | + + + +### sdObjectEncoder.conceal(path, [salt]) ⇒ [Disclosure](#Disclosure) +Substitutes a value with the digest of its disclosure. +If no salt is provided, the disclosure will be created with a random salt value. + +`path` indicates the pointer to the value that will be concealed using the syntax of +[JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901). + +For the following object: + + ``` +{ + "id": "did:value", + "claim1": { + "abc": true + }, + "claim2": ["val_1", "val_2"] +} +``` + +Path "/id" conceals `"id": "did:value"` +Path "/claim1/abc" conceals `"abc": true` +Path "/claim2/0" conceals `val_1` +``` + +## Errors +* `InvalidPath` if pointer is invalid. +* `DataTypeMismatch` if existing SD format is invalid. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + +| Param | Type | +| --- | --- | +| path | string | +| [salt] | string \| undefined | + + + +### sdObjectEncoder.addSdAlgProperty() +Adds the `_sd_alg` property to the top level of the object, with +its value set to "sha-256". + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + + +### sdObjectEncoder.encodeToString() ⇒ string +Returns the modified object as a string. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + + +### sdObjectEncoder.toString() ⇒ string +Returns the modified object as a string. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + + +### sdObjectEncoder.encodeToObject() ⇒ Record.<string, any> +Returns the modified object. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + + +### sdObjectEncoder.toJSON() ⇒ any +Returns the modified object. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + + +### sdObjectEncoder.addDecoys(path, number_of_decoys) +Adds a decoy digest to the specified path. +If path is an empty slice, decoys will be added to the top level. + +**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) + +| Param | Type | +| --- | --- | +| path | string | +| number_of_decoys | number | + + + +## SelectiveDisclosurePresentation +Used to construct a JwpPresentedBuilder and handle the selective disclosure of attributes +- @context MUST NOT be blinded +- id MUST be blinded +- type MUST NOT be blinded +- issuer MUST NOT be blinded +- issuanceDate MUST be blinded (if Timeframe Revocation mechanism is used) +- expirationDate MUST be blinded (if Timeframe Revocation mechanism is used) +- credentialSubject (User have to choose which attribute must be blinded) +- credentialSchema MUST NOT be blinded +- credentialStatus MUST NOT be blinded +- refreshService MUST NOT be blinded (probably will be used for Timeslot Revocation mechanism) +- termsOfUse NO reason to use it in ZK VC (will be in any case blinded) +- evidence (User have to choose which attribute must be blinded) + +**Kind**: global class + +* [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) + * [new SelectiveDisclosurePresentation(issued_jwp)](#new_SelectiveDisclosurePresentation_new) + * [.concealInSubject(path)](#SelectiveDisclosurePresentation+concealInSubject) + * [.concealInEvidence(path)](#SelectiveDisclosurePresentation+concealInEvidence) + * [.setPresentationHeader(header)](#SelectiveDisclosurePresentation+setPresentationHeader) + + + +### new SelectiveDisclosurePresentation(issued_jwp) +Initialize a presentation starting from an Issued JWP. +The properties `jti`, `nbf`, `issuanceDate`, `expirationDate` and `termsOfUse` are concealed by default. + + +| Param | Type | +| --- | --- | +| issued_jwp | [JwpIssued](#JwpIssued) | + + + +### selectiveDisclosurePresentation.concealInSubject(path) +Selectively disclose "credentialSubject" attributes. +# Example +``` +{ + "id": 1234, + "name": "Alice", + "mainCourses": ["Object-oriented Programming", "Mathematics"], + "degree": { + "type": "BachelorDegree", + "name": "Bachelor of Science and Arts", + }, + "GPA": "4.0", +} +``` +If you want to undisclose for example the Mathematics course and the name of the degree: +``` +undisclose_subject("mainCourses[1]"); +undisclose_subject("degree.name"); +``` + +**Kind**: instance method of [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) + +| Param | Type | +| --- | --- | +| path | string | + + + +### selectiveDisclosurePresentation.concealInEvidence(path) +Undiscloses "evidence" attributes. + +**Kind**: instance method of [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) + +| Param | Type | +| --- | --- | +| path | string | + + + +### selectiveDisclosurePresentation.setPresentationHeader(header) +Sets presentation protected header. + +**Kind**: instance method of [SelectiveDisclosurePresentation](#SelectiveDisclosurePresentation) + +| Param | Type | +| --- | --- | +| header | [PresentationProtectedHeader](#PresentationProtectedHeader) | + + + +## Service +A DID Document Service used to enable trusted interactions associated with a DID subject. + +**Kind**: global class + +* [Service](#Service) + * [new Service(service)](#new_Service_new) + * _instance_ + * [.id()](#Service+id) ⇒ [DIDUrl](#DIDUrl) + * [.type()](#Service+type) ⇒ Array.<string> + * [.serviceEndpoint()](#Service+serviceEndpoint) ⇒ string \| Array.<string> \| Map.<string, Array.<string>> + * [.properties()](#Service+properties) ⇒ Map.<string, any> + * [.toJSON()](#Service+toJSON) ⇒ any + * [.clone()](#Service+clone) ⇒ [Service](#Service) + * _static_ + * [.fromJSON(json)](#Service.fromJSON) ⇒ [Service](#Service) + + + +### new Service(service) + +| Param | Type | +| --- | --- | +| service | IService | + + + +### service.id() ⇒ [DIDUrl](#DIDUrl) +Returns a copy of the [Service](#Service) id. + +**Kind**: instance method of [Service](#Service) + + +### service.type() ⇒ Array.<string> +Returns a copy of the [Service](#Service) type. + +**Kind**: instance method of [Service](#Service) + + +### service.serviceEndpoint() ⇒ string \| Array.<string> \| Map.<string, Array.<string>> +Returns a copy of the [Service](#Service) endpoint. + +**Kind**: instance method of [Service](#Service) + + +### service.properties() ⇒ Map.<string, any> +Returns a copy of the custom properties on the [Service](#Service). + +**Kind**: instance method of [Service](#Service) + + +### service.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Service](#Service) + + +### service.clone() ⇒ [Service](#Service) +Deep clones the object. + +**Kind**: instance method of [Service](#Service) + + +### Service.fromJSON(json) ⇒ [Service](#Service) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Service](#Service) + +| Param | Type | +| --- | --- | +| json | any | + + + +## StatusList2021 +StatusList2021 data structure as described in [W3C's VC status list 2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/). + +**Kind**: global class + +* [StatusList2021](#StatusList2021) + * [new StatusList2021([size])](#new_StatusList2021_new) + * _instance_ + * [.clone()](#StatusList2021+clone) ⇒ [StatusList2021](#StatusList2021) + * [.len()](#StatusList2021+len) ⇒ number + * [.get(index)](#StatusList2021+get) ⇒ boolean + * [.set(index, value)](#StatusList2021+set) + * [.intoEncodedStr()](#StatusList2021+intoEncodedStr) ⇒ string + * _static_ + * [.fromEncodedStr(s)](#StatusList2021.fromEncodedStr) ⇒ [StatusList2021](#StatusList2021) + + + +### new StatusList2021([size]) +Creates a new [StatusList2021](#StatusList2021) of `size` entries. + + +| Param | Type | +| --- | --- | +| [size] | number \| undefined | + + + +### statusList2021.clone() ⇒ [StatusList2021](#StatusList2021) +Deep clones the object. + +**Kind**: instance method of [StatusList2021](#StatusList2021) + + +### statusList2021.len() ⇒ number +Returns the number of entries in this [StatusList2021](#StatusList2021). + +**Kind**: instance method of [StatusList2021](#StatusList2021) + + +### statusList2021.get(index) ⇒ boolean +Returns whether the entry at `index` is set. + +**Kind**: instance method of [StatusList2021](#StatusList2021) + +| Param | Type | +| --- | --- | +| index | number | + + + +### statusList2021.set(index, value) +Sets the value of the `index`-th entry. + +**Kind**: instance method of [StatusList2021](#StatusList2021) + +| Param | Type | +| --- | --- | +| index | number | +| value | boolean | + + + +### statusList2021.intoEncodedStr() ⇒ string +Encodes this [StatusList2021](#StatusList2021) into its compressed +base64 string representation. + +**Kind**: instance method of [StatusList2021](#StatusList2021) + + +### StatusList2021.fromEncodedStr(s) ⇒ [StatusList2021](#StatusList2021) +Attempts to decode a [StatusList2021](#StatusList2021) from a string. + +**Kind**: static method of [StatusList2021](#StatusList2021) + +| Param | Type | +| --- | --- | +| s | string | + + + +## StatusList2021Credential +A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021credential). + +**Kind**: global class + +* [StatusList2021Credential](#StatusList2021Credential) + * [new StatusList2021Credential(credential)](#new_StatusList2021Credential_new) + * _instance_ + * [.id()](#StatusList2021Credential+id) ⇒ string + * [.setCredentialStatus(credential, index, revoked_or_suspended)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry](#StatusList2021Entry) + * [.purpose()](#StatusList2021Credential+purpose) ⇒ [StatusPurpose](#StatusPurpose) + * [.entry(index)](#StatusList2021Credential+entry) ⇒ [CredentialStatus](#CredentialStatus) + * [.clone()](#StatusList2021Credential+clone) ⇒ [StatusList2021Credential](#StatusList2021Credential) + * [.toJSON()](#StatusList2021Credential+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#StatusList2021Credential.fromJSON) ⇒ [StatusList2021Credential](#StatusList2021Credential) + + + +### new StatusList2021Credential(credential) +Creates a new [StatusList2021Credential](#StatusList2021Credential). + + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | + + + +### statusList2021Credential.id() ⇒ string +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + + +### statusList2021Credential.setCredentialStatus(credential, index, revoked_or_suspended) ⇒ [StatusList2021Entry](#StatusList2021Entry) +Sets the given credential's status using the `index`-th entry of this status list. +Returns the created `credentialStatus`. + +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + +| Param | Type | +| --- | --- | +| credential | [Credential](#Credential) | +| index | number | +| revoked_or_suspended | boolean | + + + +### statusList2021Credential.purpose() ⇒ [StatusPurpose](#StatusPurpose) +Returns the [StatusPurpose](#StatusPurpose) of this [StatusList2021Credential](#StatusList2021Credential). + +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + + +### statusList2021Credential.entry(index) ⇒ [CredentialStatus](#CredentialStatus) +Returns the state of the `index`-th entry, if any. + +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + +| Param | Type | +| --- | --- | +| index | number | + + + +### statusList2021Credential.clone() ⇒ [StatusList2021Credential](#StatusList2021Credential) +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + + +### statusList2021Credential.toJSON() ⇒ any +**Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) + + +### StatusList2021Credential.fromJSON(json) ⇒ [StatusList2021Credential](#StatusList2021Credential) +**Kind**: static method of [StatusList2021Credential](#StatusList2021Credential) + +| Param | Type | +| --- | --- | +| json | any | + + + +## StatusList2021CredentialBuilder +Builder type to construct valid [StatusList2021Credential](#StatusList2021Credential) istances. + +**Kind**: global class + +* [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [new StatusList2021CredentialBuilder([status_list])](#new_StatusList2021CredentialBuilder_new) + * [.purpose(purpose)](#StatusList2021CredentialBuilder+purpose) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.subjectId(id)](#StatusList2021CredentialBuilder+subjectId) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.expirationDate(time)](#StatusList2021CredentialBuilder+expirationDate) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.issuer(issuer)](#StatusList2021CredentialBuilder+issuer) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.context(context)](#StatusList2021CredentialBuilder+context) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.type(t)](#StatusList2021CredentialBuilder+type) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.proof(proof)](#StatusList2021CredentialBuilder+proof) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + * [.build()](#StatusList2021CredentialBuilder+build) ⇒ [StatusList2021Credential](#StatusList2021Credential) + + + +### new StatusList2021CredentialBuilder([status_list]) +Creates a new [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder). + + +| Param | Type | +| --- | --- | +| [status_list] | [StatusList2021](#StatusList2021) \| undefined | + + + +### statusList2021CredentialBuilder.purpose(purpose) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Sets the purpose of the [StatusList2021Credential](#StatusList2021Credential) that is being created. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| purpose | [StatusPurpose](#StatusPurpose) | + + + +### statusList2021CredentialBuilder.subjectId(id) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Sets `credentialSubject.id`. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| id | string | + + + +### statusList2021CredentialBuilder.expirationDate(time) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Sets the expiration date of the credential. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| time | [Timestamp](#Timestamp) | + + + +### statusList2021CredentialBuilder.issuer(issuer) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Sets the issuer of the credential. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| issuer | string | + + + +### statusList2021CredentialBuilder.context(context) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Sets the context of the credential. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| context | string | + + + +### statusList2021CredentialBuilder.type(t) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Adds a credential type. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| t | string | + + + +### statusList2021CredentialBuilder.proof(proof) ⇒ [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) +Adds a credential's proof. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + +| Param | Type | +| --- | --- | +| proof | [Proof](#Proof) | + + + +### statusList2021CredentialBuilder.build() ⇒ [StatusList2021Credential](#StatusList2021Credential) +Attempts to build a valid [StatusList2021Credential](#StatusList2021Credential) with the previously provided data. + +**Kind**: instance method of [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder) + + +## StatusList2021Entry +[StatusList2021Entry](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021entry) implementation. + +**Kind**: global class + +* [StatusList2021Entry](#StatusList2021Entry) + * [new StatusList2021Entry(status_list, purpose, index, [id])](#new_StatusList2021Entry_new) + * _instance_ + * [.id()](#StatusList2021Entry+id) ⇒ string + * [.purpose()](#StatusList2021Entry+purpose) ⇒ [StatusPurpose](#StatusPurpose) + * [.index()](#StatusList2021Entry+index) ⇒ number + * [.statusListCredential()](#StatusList2021Entry+statusListCredential) ⇒ string + * [.toStatus()](#StatusList2021Entry+toStatus) ⇒ Status + * [.clone()](#StatusList2021Entry+clone) ⇒ [StatusList2021Entry](#StatusList2021Entry) + * [.toJSON()](#StatusList2021Entry+toJSON) ⇒ any + * _static_ + * [.fromJSON(json)](#StatusList2021Entry.fromJSON) ⇒ [StatusList2021Entry](#StatusList2021Entry) + + + +### new StatusList2021Entry(status_list, purpose, index, [id]) +Creates a new [StatusList2021Entry](#StatusList2021Entry). + + +| Param | Type | +| --- | --- | +| status_list | string | +| purpose | [StatusPurpose](#StatusPurpose) | +| index | number | +| [id] | string \| undefined | + + + +### statusList2021Entry.id() ⇒ string +Returns this `credentialStatus`'s `id`. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.purpose() ⇒ [StatusPurpose](#StatusPurpose) +Returns the purpose of this entry. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.index() ⇒ number +Returns the index of this entry. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.statusListCredential() ⇒ string +Returns the referenced [StatusList2021Credential](#StatusList2021Credential)'s url. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.toStatus() ⇒ Status +Downcasts [this](this) to [Status](Status) + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.clone() ⇒ [StatusList2021Entry](#StatusList2021Entry) +Deep clones the object. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### statusList2021Entry.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) + + +### StatusList2021Entry.fromJSON(json) ⇒ [StatusList2021Entry](#StatusList2021Entry) +Deserializes an instance from a JSON object. + +**Kind**: static method of [StatusList2021Entry](#StatusList2021Entry) + +| Param | Type | +| --- | --- | +| json | any | + + + +## Storage +A type wrapping a `JwkStorage` and `KeyIdStorage` that should always be used together when +working with storage backed DID documents. + +**Kind**: global class + +* [Storage](#Storage) + * [new Storage(jwkStorage, keyIdStorage)](#new_Storage_new) + * [.keyIdStorage()](#Storage+keyIdStorage) ⇒ KeyIdStorage + * [.keyStorage()](#Storage+keyStorage) ⇒ JwkStorage + + + +### new Storage(jwkStorage, keyIdStorage) +Constructs a new `Storage`. + + +| Param | Type | +| --- | --- | +| jwkStorage | JwkStorage | +| keyIdStorage | KeyIdStorage | + + + +### storage.keyIdStorage() ⇒ KeyIdStorage +Obtain the wrapped `KeyIdStorage`. + +**Kind**: instance method of [Storage](#Storage) + + +### storage.keyStorage() ⇒ JwkStorage +Obtain the wrapped `JwkStorage`. + +**Kind**: instance method of [Storage](#Storage) + + +## Timestamp +**Kind**: global class + +* [Timestamp](#Timestamp) + * [new Timestamp()](#new_Timestamp_new) + * _instance_ + * [.toRFC3339()](#Timestamp+toRFC3339) ⇒ string + * [.checkedAdd(duration)](#Timestamp+checkedAdd) ⇒ [Timestamp](#Timestamp) \| undefined + * [.checkedSub(duration)](#Timestamp+checkedSub) ⇒ [Timestamp](#Timestamp) \| undefined + * [.toJSON()](#Timestamp+toJSON) ⇒ any + * _static_ + * [.parse(input)](#Timestamp.parse) ⇒ [Timestamp](#Timestamp) + * [.nowUTC()](#Timestamp.nowUTC) ⇒ [Timestamp](#Timestamp) + * [.fromJSON(json)](#Timestamp.fromJSON) ⇒ [Timestamp](#Timestamp) + + + +### new Timestamp() +Creates a new [Timestamp](#Timestamp) with the current date and time. + + + +### timestamp.toRFC3339() ⇒ string +Returns the [Timestamp](#Timestamp) as an RFC 3339 `String`. + +**Kind**: instance method of [Timestamp](#Timestamp) + + +### timestamp.checkedAdd(duration) ⇒ [Timestamp](#Timestamp) \| undefined +Computes `self + duration` + +Returns `null` if the operation leads to a timestamp not in the valid range for [RFC 3339](https://tools.ietf.org/html/rfc3339). + +**Kind**: instance method of [Timestamp](#Timestamp) + +| Param | Type | +| --- | --- | +| duration | [Duration](#Duration) | + + + +### timestamp.checkedSub(duration) ⇒ [Timestamp](#Timestamp) \| undefined +Computes `self - duration` + +Returns `null` if the operation leads to a timestamp not in the valid range for [RFC 3339](https://tools.ietf.org/html/rfc3339). + +**Kind**: instance method of [Timestamp](#Timestamp) + +| Param | Type | +| --- | --- | +| duration | [Duration](#Duration) | + + + +### timestamp.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [Timestamp](#Timestamp) + + +### Timestamp.parse(input) ⇒ [Timestamp](#Timestamp) +Parses a [Timestamp](#Timestamp) from the provided input string. + +**Kind**: static method of [Timestamp](#Timestamp) + +| Param | Type | +| --- | --- | +| input | string | + + + +### Timestamp.nowUTC() ⇒ [Timestamp](#Timestamp) +Creates a new [Timestamp](#Timestamp) with the current date and time. + +**Kind**: static method of [Timestamp](#Timestamp) + + +### Timestamp.fromJSON(json) ⇒ [Timestamp](#Timestamp) +Deserializes an instance from a JSON object. + +**Kind**: static method of [Timestamp](#Timestamp) + +| Param | Type | +| --- | --- | +| json | any | + + + +## UnknownCredential +**Kind**: global class + +* [UnknownCredential](#UnknownCredential) + * _instance_ + * [.tryIntoJwt()](#UnknownCredential+tryIntoJwt) ⇒ [Jwt](#Jwt) \| undefined + * [.tryIntoCredential()](#UnknownCredential+tryIntoCredential) ⇒ [Credential](#Credential) \| undefined + * [.tryIntoRaw()](#UnknownCredential+tryIntoRaw) ⇒ Record.<string, any> \| undefined + * [.toJSON()](#UnknownCredential+toJSON) ⇒ any + * [.clone()](#UnknownCredential+clone) ⇒ [UnknownCredential](#UnknownCredential) + * _static_ + * [.fromJSON(json)](#UnknownCredential.fromJSON) ⇒ [UnknownCredential](#UnknownCredential) + + + +### unknownCredential.tryIntoJwt() ⇒ [Jwt](#Jwt) \| undefined +Returns a [Jwt](#Jwt) if the credential is of type string, `undefined` otherwise. + +**Kind**: instance method of [UnknownCredential](#UnknownCredential) + + +### unknownCredential.tryIntoCredential() ⇒ [Credential](#Credential) \| undefined +Returns a [Credential](#Credential) if the credential is of said type, `undefined` otherwise. + +**Kind**: instance method of [UnknownCredential](#UnknownCredential) + + +### unknownCredential.tryIntoRaw() ⇒ Record.<string, any> \| undefined +Returns the contained value as an Object, if it can be converted, `undefined` otherwise. + +**Kind**: instance method of [UnknownCredential](#UnknownCredential) + + +### unknownCredential.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [UnknownCredential](#UnknownCredential) + + +### unknownCredential.clone() ⇒ [UnknownCredential](#UnknownCredential) +Deep clones the object. + +**Kind**: instance method of [UnknownCredential](#UnknownCredential) + + +### UnknownCredential.fromJSON(json) ⇒ [UnknownCredential](#UnknownCredential) +Deserializes an instance from a JSON object. + +**Kind**: static method of [UnknownCredential](#UnknownCredential) + +| Param | Type | +| --- | --- | +| json | any | + + + +## VerificationMethod +A DID Document Verification Method. + +**Kind**: global class + +* [VerificationMethod](#VerificationMethod) + * [new VerificationMethod(id, controller, type_, data)](#new_VerificationMethod_new) + * _instance_ + * [.id()](#VerificationMethod+id) ⇒ [DIDUrl](#DIDUrl) + * [.setId(id)](#VerificationMethod+setId) + * [.controller()](#VerificationMethod+controller) ⇒ [CoreDID](#CoreDID) + * [.setController(did)](#VerificationMethod+setController) + * [.type()](#VerificationMethod+type) ⇒ [MethodType](#MethodType) + * [.setType(type_)](#VerificationMethod+setType) + * [.data()](#VerificationMethod+data) ⇒ [MethodData](#MethodData) + * [.setData(data)](#VerificationMethod+setData) + * [.properties()](#VerificationMethod+properties) ⇒ Map.<string, any> + * [.setPropertyUnchecked(key, value)](#VerificationMethod+setPropertyUnchecked) + * [.toJSON()](#VerificationMethod+toJSON) ⇒ any + * [.clone()](#VerificationMethod+clone) ⇒ [VerificationMethod](#VerificationMethod) + * _static_ + * [.newFromJwk(did, key, [fragment])](#VerificationMethod.newFromJwk) ⇒ [VerificationMethod](#VerificationMethod) + * [.fromJSON(json)](#VerificationMethod.fromJSON) ⇒ [VerificationMethod](#VerificationMethod) + + + +### new VerificationMethod(id, controller, type_, data) +Create a custom [VerificationMethod](#VerificationMethod). + + +| Param | Type | +| --- | --- | +| id | [DIDUrl](#DIDUrl) | +| controller | [CoreDID](#CoreDID) | +| type_ | [MethodType](#MethodType) | +| data | [MethodData](#MethodData) | + + + +### verificationMethod.id() ⇒ [DIDUrl](#DIDUrl) +Returns a copy of the [DIDUrl](#DIDUrl) of the [VerificationMethod](#VerificationMethod)'s `id`. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.setId(id) +Sets the id of the [VerificationMethod](#VerificationMethod). + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| id | [DIDUrl](#DIDUrl) | + + + +### verificationMethod.controller() ⇒ [CoreDID](#CoreDID) +Returns a copy of the `controller` `DID` of the [VerificationMethod](#VerificationMethod). + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.setController(did) +Sets the `controller` `DID` of the [VerificationMethod](#VerificationMethod) object. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| did | [CoreDID](#CoreDID) | + + + +### verificationMethod.type() ⇒ [MethodType](#MethodType) +Returns a copy of the [VerificationMethod](#VerificationMethod) type. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.setType(type_) +Sets the [VerificationMethod](#VerificationMethod) type. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| type_ | [MethodType](#MethodType) | + + + +### verificationMethod.data() ⇒ [MethodData](#MethodData) +Returns a copy of the [VerificationMethod](#VerificationMethod) public key data. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.setData(data) +Sets [VerificationMethod](#VerificationMethod) public key data. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| data | [MethodData](#MethodData) | + + + +### verificationMethod.properties() ⇒ Map.<string, any> +Get custom properties of the Verification Method. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.setPropertyUnchecked(key, value) +Adds a custom property to the Verification Method. +If the value is set to `null`, the custom property will be removed. + +### WARNING +This method can overwrite existing properties like `id` and result +in an invalid Verification Method. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| key | string | +| value | any | + + + +### verificationMethod.toJSON() ⇒ any +Serializes this to a JSON object. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### verificationMethod.clone() ⇒ [VerificationMethod](#VerificationMethod) +Deep clones the object. + +**Kind**: instance method of [VerificationMethod](#VerificationMethod) + + +### VerificationMethod.newFromJwk(did, key, [fragment]) ⇒ [VerificationMethod](#VerificationMethod) +Creates a new [VerificationMethod](#VerificationMethod) from the given `did` and [Jwk](#Jwk). If `fragment` is not given +the `kid` value of the given `key` will be used, if present, otherwise an error is returned. + +### Recommendations +The following recommendations are essentially taken from the `publicKeyJwk` description from the [DID specification](https://www.w3.org/TR/did-core/#dfn-publickeyjwk): +- It is recommended that verification methods that use `Jwks` to represent their public keys use the value of + `kid` as their fragment identifier. This is +done automatically if `None` is passed in as the fragment. +- It is recommended that [Jwk](#Jwk) kid values are set to the public key fingerprint. + +**Kind**: static method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| did | [CoreDID](#CoreDID) \| IToCoreDID | +| key | [Jwk](#Jwk) | +| [fragment] | string \| undefined | + + + +### VerificationMethod.fromJSON(json) ⇒ [VerificationMethod](#VerificationMethod) +Deserializes an instance from a JSON object. + +**Kind**: static method of [VerificationMethod](#VerificationMethod) + +| Param | Type | +| --- | --- | +| json | any | + + + +## StatusCheck +Controls validation behaviour when checking whether or not a credential has been revoked by its +[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status). + +**Kind**: global variable + + +## Strict +Validate the status if supported, reject any unsupported +[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types. + +Only `RevocationBitmap2022` is currently supported. + +This is the default. + +**Kind**: global variable + + +## SkipUnsupported +Validate the status if supported, skip any unsupported +[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types. + +**Kind**: global variable + + +## SkipAll +Skip all status checks. + +**Kind**: global variable + + +## CredentialStatus +**Kind**: global variable + + +## PayloadType +**Kind**: global variable + + +## ProofAlgorithm +**Kind**: global variable + + +## StatusPurpose +Purpose of a [StatusList2021](#StatusList2021). + +**Kind**: global variable + + +## FailFast +Declares when validation should return if an error occurs. + +**Kind**: global variable + + +## AllErrors +Return all errors that occur during validation. + +**Kind**: global variable + + +## FirstError +Return after the first error occurs. + +**Kind**: global variable + + +## StateMetadataEncoding +**Kind**: global variable + + +## SerializationType +**Kind**: global variable + + +## MethodRelationship +**Kind**: global variable + + +## PresentationProofAlgorithm +**Kind**: global variable + + +## SubjectHolderRelationship +Declares how credential subjects must relate to the presentation holder. + +See also the [Subject-Holder Relationship](https://www.w3.org/TR/vc-data-model/#subject-holder-relationships) section of the specification. + +**Kind**: global variable + + +## AlwaysSubject +The holder must always match the subject on all credentials, regardless of their [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property. +This variant is the default. + +**Kind**: global variable + + +## SubjectOnNonTransferable +The holder must match the subject only for credentials where the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property is `true`. + +**Kind**: global variable + + +## Any +The holder is not required to have any kind of relationship to any credential subject. + +**Kind**: global variable + + +## encodeB64(data) ⇒ string +Encode the given bytes in url-safe base64. + +**Kind**: global function + +| Param | Type | +| --- | --- | +| data | Uint8Array | + + + +## decodeB64(data) ⇒ Uint8Array +Decode the given url-safe base64-encoded slice into its raw bytes. + +**Kind**: global function + +| Param | Type | +| --- | --- | +| data | Uint8Array | + + + +## start() +Initializes the console error panic hook for better error messages + +**Kind**: global function + + +## verifyEd25519(alg, signingInput, decodedSignature, publicKey) +Verify a JWS signature secured with the `EdDSA` algorithm and curve `Ed25519`. + +This function is useful when one is composing a `IJwsVerifier` that delegates +`EdDSA` verification with curve `Ed25519` to this function. + +# Warning + +This function does not check whether `alg = EdDSA` in the protected header. Callers are expected to assert this +prior to calling the function. + +**Kind**: global function + +| Param | Type | +| --- | --- | +| alg | JwsAlgorithm | +| signingInput | Uint8Array | +| decodedSignature | Uint8Array | +| publicKey | [Jwk](#Jwk) | + diff --git a/docs/build/identity.rs/1.3/docs/references/specifications/iota-did-method-spec.mdx b/docs/build/identity.rs/1.3/docs/references/specifications/iota-did-method-spec.mdx new file mode 100644 index 00000000000..1535df5b913 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/references/specifications/iota-did-method-spec.mdx @@ -0,0 +1,263 @@ +--- +title: IOTA DID Method Specification v1.0 +sidebar_label: DID Method +description: How IOTA Identity implements the Decentralized Identifiers Standard on the IOTA Tangle. +image: /img/Identity_icon.png +tags: + - DID + - specs + - specifications + - Decentralized Identifiers + - Tangle + - format +--- + +# IOTA DID Method Specification v1.0 + +2023-08-23 + +## Abstract + +The IOTA DID Method Specification describes a method of implementing the [Decentralized Identifiers](https://www.w3.org/TR/did-core/) (DID) standard on [IOTA](https://iota.org), a Distributed Ledger Technology (DLT). It conforms to the [DID specification v1.0](https://www.w3.org/TR/did-core/) and describes how to perform Create, Read, Update and Delete (CRUD) operations for IOTA DID Documents using unspent transaction outputs (_UTXO_) on the IOTA and [Shimmer](https://shimmer.network/) networks, introduced with the [Stardust upgrade](https://blog.shimmer.network/stardust-upgrade-in-a-nutshell/). + +## Data Types & Subschema Notation + +Data types and subschemas used throughout this TIP are defined in [TIP-21](https://github.com/iotaledger/tips/blob/v1.2.0/tips/TIP-0021/tip-0021.md). + +## Introduction + +### UTXO Ledger + +The unspent transaction output ([UTXO](/tips/tips/TIP-0020/)) model defines a ledger state which is comprised of unspent outputs. Outputs are created by a transaction consuming outputs of previous transactions as inputs. The Stardust version of the protocol defines several output types, the relevant ones for the IOTA DID Method are: Basic Outputs for _value transactions_, and Alias Outputs for storage of DID Documents. + +All outputs must hold a minimum amount of tokens to be stored on the ledger. For output types that can hold arbitrary data, for instance the Alias Output, the amount of tokens held by the output must cover the byte cost of the data stored. This prevents the ledger size from growing uncontrollably while guaranteeing that the data is not pruned from the nodes, which is important for resolving DID Documents. This deposit is fully refundable and can be reclaimed when the output is destroyed. + +Data stored in an output and covered by the storage deposit will be stored in _all_ nodes on the network and can be retrieved from any node. This provides strong guarantees for any data stored in the ledger. + +### Alias Output + +The [Alias Output](https://github.com/iotaledger/tips/blob/v1.2.0/tips/TIP-0018/tip-0018.md#alias-output) is a specific implementation of the [UTXO state machine](https://github.com/iotaledger/tips/blob/v1.2.0/tips/TIP-0018/tip-0018.md#chain-constraint-in-utxo). Some of its relevant properties are: + +- **Amount**: the amount of IOTA coins held by the output. +- **Alias ID**: 32 byte array, a unique identifier of the alias, which is the BLAKE2b-256 hash + of the Output ID that created it. +- **State Index**: A counter that must increase by 1 every time the alias is state transitioned. +- **State Metadata**: Dynamically sized array of arbitrary bytes with a length up to `Max Metadata Length`, as defined in [TIP-22](https://github.com/iotaledger/tips/blob/v1.2.0/tips/TIP-0022/tip-0022.md). Can only be changed by the state controller. +- **Unlock Conditions**: + - State Controller Address Unlock Condition + - Governor Address Unlock Condition + +Consuming an Alias Output in a transaction may transition it into the next state. The current state is defined as the consumed Alias Output, while the next state is defined as the **Alias Output with the same explicit `Alias ID` on the output side**. There are two types of transitions: `state transition` and `governance transition`. + +All outputs include an `Unlock Conditions` property. This feature defines how the output can be unlocked and spent. The Alias Output supports two types of unlock conditions that can be set: the state controller and governor. Each of these can be either an Ed25519 Address, Alias Address or an NFT Address. An Alias Output can have at most one of each unlock condition. + +The state controller can unlock a state transition. It is identified by an incremented `State Index` and can change the fields `Amount`, `State Index`, `State Metadata` among other properties. + +The governor, on the other hand, can unlock a governance transition indicated by an unchanged `State Index`. A governance transition can change the addresses of the state controller and governor. It also allows destroying the Alias Output. + +### Ledger and DID + +Storing DID Documents in the ledger state means they inherently benefit from the guarantees the ledger provides. + +1. Conflicts among nodes are resolved and dealt with by the ledger. +2. Replay attacks are mitigated since transactions need to be confirmed by the ledger. +3. Through the `State Index` a linear history for updates of a DID Document is provided. + +## DID Method Name + +The `method-name` to identify this DID method is: `iota`. + +A DID that uses this method MUST begin with the following prefix: `did:iota`. Following the generic DID specification, this string MUST be lowercase. + +## DID Format + +The DIDs that follow this method have the following ABNF syntax. It uses the syntax in [RFC5234](https://www.rfc-editor.org/rfc/rfc5234) and the corresponding definition for `digit`. + +``` +iota-did = "did:iota:" iota-specific-idstring +iota-specific-idstring = [ iota-network ":" ] iota-tag +iota-network = 1*6network-char +iota-tag = "0x" 64lowercase-hex +lowercase-hex = digit / "a" / "b" / "c" / "d" / "e" / "f" +network-char = %x61-7A / digit ; corresponds to the character range from "a" to "z" and "0" to "9". +``` + +It starts with the string "did:iota:", followed by an optional network name (1 to 6 lowercase alpha characters) and a colon, then the tag. +The tag starts with "0x" followed by a hex-encoded `Alias ID` with lower case a-f. + +### IOTA-Network + +The iota-network is an identifier of the network where the DID is stored. This network must be an IOTA Ledger, but can either be a public or private network, permissionless or permissioned. + +The following values are reserved and cannot reference other networks: + +1. `iota` references the main network which refers to the ledger known to host the IOTA cryptocurrency. +2. `atoi` references the development network of IOTA. +3. `smr` references the shimmer network. +4. `rms` references the development network of Shimmer. + +When no IOTA network is specified, it is assumed that the DID is located on the `iota` network. This means that the following DIDs will resolve to the same DID Document: + +``` +did:iota:iota:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe +did:iota:0xe4edef97da1257e83cbeb49159cfdd2da6ac971ac447f233f8439cf29376ebfe +``` + +### IOTA-Tag + +An IOTA-tag is a hex-encoded `Alias ID`. The `Alias ID` itself is a unique identifier of the alias, which is the BLAKE2b-256 hash of the Output ID that created it. +This tag identifies the Alias Output where the DID Document is stored, and it will not be known before the generation of the DID since it will be assigned when the Alias Output is created. + +### Anatomy of the State Metadata + +In the `State Metadata` of the Alias Output must be a byte packed payload with header fields as follows: + +| Name | Type | Description | +| ------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Document Type | ByteArray[3] | Set to value **DID** to denote a DID Document. | +| Version | uint8 | Set value **1** to denote the version number of this method | +| Encoding | uint8 | Set to value to **0** to denote JSON encoding without compression. | +| Payload | (uint16)ByteArray | A DID Document and its metadata, where every occurrence of the DID in the document is replaced by `did:0:0`. It must be encoded according to `Encoding`. | + +The types are defined in [TIP-21](/tips/tips/TIP-0021/#data-types). + +#### Payload + +The payload must contain the following fields: + +- `meta`: contains metadata about the DID Document. For example, `created` to indicate the time of + creation, and `updated` to indicate the time of the last update to the document. It may also include other properties. +- `doc`: contains the DID Document. In the example below, the document only contains one verification method. The `id` and `controller` is specified by `did:0:0` which references the DID of the document itself, since the DID is unknown at the time of publishing. It also deduplicates the DID of the document to reduce the size of the state metadata, in turn reducing the required storage deposit. + +Example State Metadata Document: + +```json +{ + "doc": { + "id": "did:0:0", + "verificationMethod": [ + { + "id": "did:0:0#jkGOGVO3Te7ADpvlplr47eP9ucLt41zm", + "controller": "did:0:0", + "type": "JsonWebKey", + "publicKeyJwk": { + "kty": "OKP", + "alg": "EdDSA", + "kid": "jkGOGVO3Te7ADpvlplr47eP9ucLt41zm", + "crv": "Ed25519", + "x": "D5w8vG6tKEnpBAia5J4vNgLID8k0BspHz-cVMBCC3RQ" + } + } + ], + "authentication": ["did:0:0#jkGOGVO3Te7ADpvlplr47eP9ucLt41zm"] + }, + "meta": { + "created": "2023-08-28T14:49:37Z", + "updated": "2023-08-28T14:50:27Z" + } +} +``` + +## Controllers + +A state controller can directly update the DID Document and the amount of tokens held by the Alias Output, but it cannot destroy the output. A governor, on the other hand, can indirectly update the DID Document by updating the state controller. The governor can also destroy the output by performing a governance transition without producing an Alias Output with the same `Alias ID`. + +As of now, only one state controller and one governor can be set for an Alias Output. Support for multiple controllers may be possible depending on future updates of the protocol. + +## CRUD Operations + +Create, Read, Update and Delete (CRUD) operations that change the DID Documents are done through state or governance transitions of the Alias Output. + +**These operations require fund transfer to cover byte cost. Transactions must be carefully done in order to avoid fund loss.** For example, the amount of funds in the inputs should equal these in the outputs. Additionally, private keys of controllers must be stored securely. + +### Create + +In order to create a simple self controlled DID two things are required: + +1. An Ed25519 Address for which the private key is available, or control over an Alias or NFT Output. +2. A Basic, Alias or NFT Output with enough coins to cover the byte cost. + +Creation steps: + +1. Create the content of the DID Document like verification methods, services, etc. +2. Create the payload and the headers as described in the [Anatomy of the State Metadata](#anatomy-of-the-state-metadata). +3. Create a new Alias Output with the payload and the headers stored in its `State Metadata`. +4. Set the state controller and the governor unlock conditions to the addresses that should control state and governance transitions, respectively. +5. Set enough tokens in the output to cover the byte cost. +6. Publish a new transaction with an existing output that contains at least the storage deposit from step 6 as input, and the newly created Alias Output as output. + +Once the transaction is confirmed, the DID is published and can be formatted by using the `Alias ID` as the tag in [DID Format](#did-format). + +### Read + +The following steps can be used to read the latest DID Document associated with a DID. + +1. Obtain the `Alias ID` from the DID by extracting the `iota-tag` from the DID, see [DID Format](#did-format). +2. Obtain the network of the DID by extracting the `iota-network` from the DID, see [DID Format](#did-format). +3. Query the Alias Output corresponding to the `Alias ID` using a node running the [inx indexer](https://github.com/iotaledger/inx-indexer). Nodes usually include this indexer by default. +4. Assert that the extracted network matches the one returned from the node. Return an error otherwise. +5. Assert that the `Alias ID` of the returned output matches the `Alias ID` extracted from the DID. Return an error otherwise. +6. Retrieve the value of the `State Metadata` field from the returned output. +7. Validate the contents match the structure described in [Anatomy of the State Metadata](#anatomy-of-the-state-metadata). Return an error otherwise. +8. Decode the DID Document from the `State Metadata`. +9. Replace the placeholder `did:0:0` with the DID given as input. + +### Update + +Updating a DID Document can be achieved by the state controller performing a state transition of the Alias Output with the updated content: + +1. Create a copy of the Alias Output with the `Alias ID` set explicitly. +2. Pack the updated DID Document, as described in the [Anatomy of the State Metadata](#anatomy-of-the-state-metadata), into the `State Metadata` of the output. +3. Increment the `State Index`. +4. Set the `amount` of coins sufficient to cover the byte cost. +5. Publish a new transaction that includes the current Alias Output as input (along with any required Basic Outputs to consume to cover the `amount`, if increased) and the updated one as output. If the state controller unlock of the Alias Output references other Alias or NFT Outputs, those outputs must be unlocked in the same transaction, recursively. + +### Delete + +#### Deactivate + +Temporarily deactivating a DID can be done by deleting the contents of the `State Meadata` in the Alias Output, setting it to an empty byte array, and publishing an [update](#update). + +Another option is to [update](#update) the DID Document and set the `deactivated` property in its `metadata` to true. In both cases, the deactivated DID Document will be marked as `deactivated` when resolved. + +#### Destroy + +In order to permanently destroy a DID, a new transaction can be published by the governor that consumes the Alias Output without having a corresponding Alias Output on the output side with the same explicit `Alias ID`. This results in destroying the Alias Output and the DID. + +Note that this operation irreversibly and irrecoverably deletes the DID. This is because the `Alias ID` from which an IOTA DID is derived (see [IOTA-Tag](#iota-tag)) is generated from the hash of the input transaction that created it, which cannot generally be replicated. + +## IOTA Identity standards + +The `did:iota` method is implemented in the [IOTA Identity framework](https://github.com/iotaledger/identity.rs). This framework supports a number of operations that are standardized, some are standardized across the SSI community, and some are the invention of the IOTA Foundation. + +### Revocation + +Revocation of verifiable credentials and signatures can be achieved using the [Revocation Bitmap 2022](./revocation-bitmap-2022.mdx) where issuers store a bitmap of indices in the DID Document. These indices correspond to verifiable credentials they have issued. If the binary value of the index in the bitmap is 1 (one), the verifiable credential is revoked, if it is 0 (zero) it is not revoked. + +### Standardized Services + +The IOTA Identity framework also standardized certain `services` that are embedded in the DID Document. It is RECOMMENDED to implement these when implementing the `did:iota` method. + +Currently standardized `services`: + +- [Revocation Bitmap Service](./revocation-bitmap-2022.mdx#revocation-bitmap-service) + +## Security Considerations + +The `did:iota` method is implemented on the [IOTA](https://iota.org), a public permissionless and feeless Distributed Ledger Technology (DLT), making it resistant against almost all censorship attack vectors. Up until the `Coordicide` update for the IOTA network, a dependency on the coordinator exists for resolving ordering conflicts. This has a minor censorship possibility, that, in the worst case, can prevent transactions from getting confirmed. + +### Private Key Management + +All private keys or seeds used for the `did:iota` method should be equally well protected by the users. Private keys of the state controller and the governor are especially important as they control how keys are added or removed, providing full control over the identity. The IOTA Identity framework utilizes the [Stronghold project](https://github.com/iotaledger/stronghold.rs), a secure software implementation isolating digital secrets from exposure to hacks or leaks. Developers may choose to add other ways to manage the private keys in a different manner. + +## Privacy Considerations + +### Personal Identifiable Information + +The public IOTA and Shimmer networks are immutable. This means that once something is included, it can never be completely removed. For example, destroying an Alias Output will remove it from the ledger state, but it can still be stored in permanodes or by any party that records historical ledger states. + +That directly conflicts with certain privacy laws such as GDPR, which have a 'right-to-be-forgotten' for Personal Identifiable Information (PII). As such, users should NEVER upload any PII, including inside DID Documents. While verifiable credentials can be made public, this should only be utilized by Identity for Organisations and Identity for Things. + +### Correlation Risks + +As with any DID method, identities can be linked if they are used too often and their usage somehow becomes public. See [DID Correlation Risks](https://www.w3.org/TR/did-core/#did-correlation-risks). Additionally, a DID can be correlated with funds if the Alias Output used to store the DID Document or any of its controllers is used for holding, transferring or controlling coins or NFTs. diff --git a/docs/build/identity.rs/1.3/docs/references/specifications/overview.mdx b/docs/build/identity.rs/1.3/docs/references/specifications/overview.mdx new file mode 100644 index 00000000000..1ad9053c490 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/references/specifications/overview.mdx @@ -0,0 +1,15 @@ +--- +title: Specifications Overview +sidebar_label: Overview +description: Provide overview of the specifications +image: /img/Identity_icon.png +tags: + - specifications +--- + +While IOTA Identity implements many existing standards, it also adds some additional features we would like to standardize ourselves. This section covers these features and how they work in great detail. These are not light reads and can be skipped. + +The current specifications are: + +- [IOTA DID](iota-did-method-spec.mdx): The specification for the IOTA DID Method implemented on the _Tangle_. +- [Revocation Bitmap 2022](revocation-bitmap-2022.mdx): The specification for an on-Tangle credential revocation mechanism. diff --git a/docs/build/identity.rs/1.3/docs/references/specifications/revocation-bitmap-2022.mdx b/docs/build/identity.rs/1.3/docs/references/specifications/revocation-bitmap-2022.mdx new file mode 100644 index 00000000000..5c7b89aaa8d --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/references/specifications/revocation-bitmap-2022.mdx @@ -0,0 +1,201 @@ +--- +title: Revocation Bitmap +sidebar_label: Revocation Bitmap +description: The specification for the embedded revocation bitmap. +image: /img/Identity_icon.png +tags: + - DID + - specs + - specifications + - revocation + - bitmap +--- + +# Revocation Bitmap 2022 + +## Abstract + +This specification describes a mechanism for publishing the revocation status of [verifiable credentials](../../explanations/verifiable-credentials.mdx) embedded in an issuer's DID document. + +## Introduction + +Revocation gives an issuer the capability to invalidate a credential they issued before its natural expiration date. To achieve this, issuers can embed an identifier in the `credentialStatus` field of a credential. Verifiers can then lookup that identifier in a separate list, to check whether the credential is still valid. This document specifies a mechanism of embedding such a list, in form of a bitmap, in the DID document of the issuer, where each bitmap index corresponds to a credential they have issued. This mechanism is space-efficient and enables a verifier to check a credential's status in a privacy-preserving manner and without requiring additional lookups or external resources. + +## Revocation Bitmap Concept + +The revocation status of a verifiable credential is expressed as a binary value. The issuer keeps a bitmap of indices corresponding to verifiable credentials they have issued. If the binary value of the index in the bitmap is 1 (one), the verifiable credential is revoked, if it is 0 (zero) it is not revoked. + +## Data Model + +### Revocation Bitmap Status + +For an issuer to enable verifiers to check the status of a verifiable credential, the [`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) property MUST be specified with the following properties: + +| Property | Description | +| :---------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | The constraints on the `id` property are listed in the [Verifiable Credentials Data Model specification](https://www.w3.org/TR/vc-data-model/). The `id` MUST be a [DID URL](https://www.w3.org/TR/did-core/#did-url-syntax) that is the URL to a [Revocation Bitmap Service](#revocation-bitmap-service) in the DID Document of the issuer. It SHOULD include an `index` query set to the same value as `revocationBitmapIndex`, to uniquely identify the `credentialStatus`. If the `index` query is present, implementations SHOULD reject statuses where the `index` query's value does not match `revocationBitmapIndex`. | +| `type` | The `type` property MUST be `"RevocationBitmap2022"`. | +| `revocationBitmapIndex` | The `revocationBitmapIndex` property MUST be an unsigned, 32-bit integer expressed as a string. This is the index of the credential in the issuer's revocation bitmap. Each index SHOULD be unique among all credentials linking to the same [Revocation Bitmap Service](#revocation-bitmap-service). | + +#### Example + +An example of a verifiable credential with a `credentialStatus` of type `RevocationBitmap2022`. + +```json +{ + "@context": "https://www.w3.org/2018/credentials/v1", + "id": "https://example.edu/credentials/3732", + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": { + "id": "did:iota:B8DucnzULJ9E8cmaReYoePU2b7UKE9WKxyEVov8tQA7H", + "GPA": "4.0", + "degree": "Bachelor of Science and Arts", + "name": "Alice" + }, + "issuer": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "issuanceDate": "2022-06-13T08:04:36Z", + "credentialStatus": { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw?index=5#revocation", + "type": "RevocationBitmap2022", + "revocationBitmapIndex": "5" + }, + "proof": { + "type": "JcsEd25519Signature2020", + "verificationMethod": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#key-1", + "signatureValue": "2eHdbDumMrer4pNVkaiYMqsVqVp2adq7bRcgTJZiw17Zeghk2ZT49YHwLwCCg35YKganBhxP6YSbzYoBK1AuCUv" + } +} +``` + +### Revocation Bitmap Service + +To allow verifiers to check the status of a [Revocation Bitmap Status](#revocation-bitmap-status), the DID document of the credential issuer MUST contain a [service](https://www.w3.org/TR/did-core/#services) with the following properties: + +| Property | Description | +| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | The constraints on the `id` property are listed in the [DID Core service specification](https://www.w3.org/TR/did-core/#services). The `id` property MUST be a DID URL uniquely identifying the revocation bitmap. | +| `type` | The `type` property MUST be `"RevocationBitmap2022"`. | +| `serviceEndpoint` | The `serviceEndpoint` MUST be generated according to the [service endpoint generation algorithm](#service-endpoint-generation-algorithm). | + +#### Example + +An example of an issuer's DID document where credential `"5"` in the `#revocation` service is revoked: + +```json +{ + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "verificationMethod": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#key-1", + "controller": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "z3hgM9fNkhwgT5mECbj1HdKoFNZgpffwQYEV8WBVHphXq" + } + ], + "capabilityInvocation": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#sign-0", + "controller": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "z83F6zbD3KqaxvQhqo25LvSXzoDdpZmp3EpPVonSVACwZ" + } + ], + "service": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#revocation", + "type": "RevocationBitmap2022", + "serviceEndpoint": "data:application/octet-stream;base64,ZUp5ek1tQmdZR1NBQUFFZ1ptVUFBQWZPQUlF" + } + ] +} +``` + +## Algorithms + +The following algorithms define how to generate, expand and validate revocation bitmaps. + +### Service Endpoint Generation Algorithm + +The following process MUST be followed when producing a `RevocationBitmap2022` to embed in a service endpoint: + +1. Let **bitmap** be a [_roaring bitmap_](https://roaringbitmap.org/) where each bit is initialized to 0. +2. For each revoked credential with an **index** not exceeding an unsigned, 32-bit integer, set the corresponding bit in **bitmap** at **index** to 1. +3. Generate the **bitmap serialization** according to the [roaring bitmap serialization format](https://github.com/RoaringBitmap/RoaringFormatSpec/) using the **bitmap** as input. +4. Generate a **compressed bitmap** by using the ZLIB compression algorithm [[RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950)] on the **bitmap serialization** and base64-encoding [[RFC4648](https://datatracker.ietf.org/doc/html/rfc4648)] the result. +5. Create the **service endpoint** by embedding the **compressed bitmap** in a data URL [[RFC2397](https://datatracker.ietf.org/doc/html/rfc2397)]. On the data url, the `` MUST be `application/octet-stream` and the `base64` attribute MUST be set. +6. Return the **service endpoint**. + +### Service Endpoint Expansion Algorithm + +The following process MUST be followed when expanding the endpoint from a service of type `RevocationBitmap2022`: + +1. Let **service endpoint** be a data url generated using the [service endpoint generation algorithm](#service-endpoint-generation-algorithm). +2. The `` of the **service endpoint** MUST be `application/octet-stream` and the `base64` attribute MUST be set, return an error otherwise. Let **compressed bitmap** be the `` part of the data url. +3. Generate an **uncompressed bitmap** by base64-decoding [[RFC4648](https://datatracker.ietf.org/doc/html/rfc4648)] the **compressed bitmap** and then decompressing the result using ZLIB [[RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950)]. +4. Generate the **bitmap** by deserializing the **uncompressed bitmap** according to the [roaring bitmap serialization format](https://github.com/RoaringBitmap/RoaringFormatSpec/). +5. Return the **bitmap**. + +### Validation Algorithm + +The following steps MUST be followed when checking whether a verifiable credential is revoked: + +1. Let **credential** be a verifiable credential containing a `credentialStatus` whose `type` is `RevocationBitmap2022`. +2. Let **revocation bitmap URL** be the `id` field of the **credential**'s `credentialStatus`. +3. Resolve the **revocation bitmap URL** to a **revocation bitmap service** in the issuer's DID document, and verify that the service `type` is `RevocationBitmap2022`. Return an error otherwise. +4. Expand the endpoint of the **revocation bitmap service** into a **revocation bitmap** according to the [service endpoint expansion algorithm](#service-endpoint-expansion-algorithm). +5. Let **revocation index** be the integer value of the `revocationBitmapIndex` property contained in the `credentialStatus` of the **credential**. +6. Let **revoked** be the value of the bit at index **revocation index** in the **revocation bitmap**. +7. Return `true` if **revoked** is 1, `false` otherwise. + +## Test Vectors + +This section provides test vectors to validate implementations against. + +### Test Vector 1 + +The following data URL decodes to a bitmap of length 0 where no index is revoked: + +`"data:application/octet-stream;base64,ZUp5ek1tQUFBd0FES0FCcg=="` + +### Test Vector 2 + +The following data URL decodes to a bitmap of length 3 where indices `5`, `398`, and `67000` are revoked: + +`"data:application/octet-stream;base64,ZUp5ek1tQmdZR0lBQVVZZ1pHQ1FBR0laSUdabDZHUGN3UW9BRXVvQjlB"`. + +### Test Vector 3 + +The following data URL decodes to a bitmap of length 16384 where all indices are revoked: + +`"data:application/octet-stream;base64,ZUp6dHhERVJBQ0FNQkxESEFWS1lXZkN2Q3E0MmFESmtyMlNrM0ROckFLQ2RBQUFBQUFBQTMzbGhHZm9q"` + +## Rationale + +This section describes the rationale behind some of the design decisions of this specification. + +### Compression and maximum size + +Considering that messages published to the Tangle cannot exceed [32 KiB](https://github.com/iotaledger/tips/blob/v1.2.0/tips/TIP-0006/tip-0006.md#message-validation) in size, and that larger messages have increased requirements, the use of compression was assessed. +The precise size of a serialized bitmap varies based on the number and distribution of revoked indices. When indices are revoked uniformly randomly, roughly 100,000 - 200,000 can be achieved in a DID Document with compression, and significantly more if consecutive indices are revoked. + +ZLIB [[RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950)] was chosen for having a free and open source software licence and being one of the most widely used compression schemes, which enhances the accessibility of this specification. Some other assessed algorithms produced only marginally better compression ratios but had far fewer existing implementations across different programming languages. + +### Compressed Bitstring vs. Roaring Bitmap + +Because of its space efficiency, a roaring bitmap is preferred for representing a bitmap in-memory. To avoid the dependency on roaring bitmap, we considered using a compressed bitstring as the serialization format. However, serialization of such a bitstring was 2-3x slower compared to roaring's serialization format, which becomes an issue on resource-constrained devices (e.g. smartphones) or in web browsers. + +### Comparison to `RevocationList2020` and `StatusList2021` + +The [RevocationList2020 specification](https://w3c-ccg.github.io/vc-status-rl-2020/) and [StatusList2021 specification](https://w3c-ccg.github.io/vc-status-list-2021/) both describe a similar revocation mechanism using a verifiable credential that contains a bitmap, similar to the `RevocationBitmap2022` approach. The credential is hosted outside of the DID document and the verifier thus needs to fetch it from an external resource, likely one controlled by the issuer. This has privacy implications as the issuer can track where a fetch request for the credential came from and potentially infer who the credential was verified by and for what purpose. The issuer can also potentially infer which credential was checked. Because `RevocationBitmap2022` is embedded in the issuer's DID document, which can be obtained without the their knowledge, this approach does not suffer from these privacy shortcomings. See also the [privacy considerations](#privacy-considerations). + +A downside of embedding the revocation list in the DID document is that storage in a distributed ledger (DLT) is usually more expensive than other storage hosting solutions. The DLT might also impose message size limitations, capping the total number of revocations that can be done (see also [compression](#compression)). + +Another difference is that `RevocationList2020` specifies a minimum initial size of 131,072 for its bitstring, to mitigate the potential for correlating individuals when few credentials have been issued. `RevocationBitmap2022` uses a roaring bitmap instead of a bitstring, so the maximum size is not fixed (apart from the upper bound of an unsigned 32-bit integer). This means the bitmap cannot be used to correlate small populations without more information not present in the bitmap itself. However, both schemes still reveal publicly how many credentials have been revoked, which could be used to infer other information if more knowledge about how an issuer assigns credential revocation indexes is known. + +`StatusList2021` allows for explicitly stating the purpose of the list, currently either _revocation_ or _suspension_. This specification does not mandate that revoked credentials cannot be unrevoked, which means a `RevocationBitmap2022` can effectively also be used as a suspension list. + +### Privacy Considerations + +Because the revocation bitmap is embedded in the DID document, and thus available without contacting the issuer directly, the issuer cannot correlate how a holder uses their credential. + +An observer finding a service of type `RevocationBitmap2022` in a DID document can infer that this DID belongs to an issuer. However, DIDs of issuers tend to be publicly known, in contrast to DIDs of other entities, so this is unlikely to present an issue. External observers can monitor the frequency of revocations and potentially the total number of issued credentials, depending on how the issuer assigns credential indices (e.g. starting from 0 and incrementing the index for each issued credential). diff --git a/docs/build/identity.rs/1.3/docs/references/specifications/revocation-timeframe-2024.mdx b/docs/build/identity.rs/1.3/docs/references/specifications/revocation-timeframe-2024.mdx new file mode 100644 index 00000000000..9acb71f1e00 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/references/specifications/revocation-timeframe-2024.mdx @@ -0,0 +1,150 @@ +--- +title: Revocation Timeframe 2024 +sidebar_label: Revocation Timeframe 2024 +description: The specification for an embeddable time-based revocation method - `RevocationTimeframe2024`. +image: /img/Identity_icon.png +tags: + - DID + - specs + - specifications + - revocation + - bitmap +--- + +# Revocation Timeframe 2024 + +## Abstract + +This specification describes a new revocation mechanism - `RevocationTimeframe2024` - that extends [`RevocationBitmap2022`](../revocation-bitmap-2022) +to address its linkability security concerns, at least when used in combination with selectively disclosable (SD-able) VCs. + +## Introduction + +`RevocationBitmap2022` allows for a simple and straightforward way for an issuer to invalidate an issued VC before its expiration. While this method prevents the analysis of usage by the issuer through hosting the revocation information on-chain +it comes with a high risk of linkability by colluding verifiers as they can store the bitmap index and use it to identify users. Additionally, verifiers can monitor the revocation information and at a later point, outside of any interaction, check the revocation status. +To address this privacy concern, `RevocationTimeframe2024` was designed as an extension that builds on top of `RevocationBitmap2022`, therefore sharing +most of its logic. + +## Concepts +`RevocationTimeframe2024` should be used together with selectively disclosable credentials - either [SD-JWT](../../../how-tos/verifiable-credentials/selective-disclosure) +or [ZK-SD](../../../how-tos/verifiable-credentials/zero-knowledge-selective-disclosure) - in order to conceal to the verifier +the credential's index in the issuer's revocation bitmap to avoid linkability. + +### Validity Timeframe + +If the revocation index is concealed from the verifier how can it assert the validity of the presented credential? +To solve this issue `RevocationTimeframe2024` introduces the concept of a _validity timeframe_, i.e. a limited time span +in which the credential is guaranteed to be non-revoked. By having a validity timeframe embedded in the credential's status +the verifier can prove the credential's validity by verifying the credential's signature. + +The downside of this mechanism is that the credential holder using `RevocationTimeframe2024` has to contact the credential's issuer +to update the signature - i.e. re-issue the credential - at the end of the credentials validity timeframe. Furthermore, +given how a credentials validity timeframe proves the validity of the credential itself, the updates made by the issuer to the credential's status - +i.e., revoking or un-revoking it - won't be reflected on the credential until a new validity timeframe starts. For this reason, +issuers should choose a validity timeframe length with respect to how frequently they expect to change the credential's status; +frequent updates deem shorter validity timeframes. + +:::note +A credential holder does not need to have its credential re-issued at the end of every validity timeframe, but only when +they need to present the credential to a verifier and its validity timeframe has expired. +::: + +## Data Model + +### Revocation Timeframe Status + +For an issuer to enable verifiers to check the status of a verifiable credential, the [`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) property MUST be specified with the following properties: + +| Property | Description | +| :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | The constraints on the `id` property are listed in the [Verifiable Credentials Data Model specification](https://www.w3.org/TR/vc-data-model/). The `id` MUST be a [DID URL](https://www.w3.org/TR/did-core/#did-url-syntax) that is the URL to a [Revocation Bitmap Service](#revocation-bitmap-service) in the DID Document of the issuer. | +| `type` | The `type` property MUST be `"RevocationTimeframe2024"`. | +| `revocationBitmapIndex` | The `revocationBitmapIndex` property MUST be an unsigned, 32-bit integer expressed as a string. This is the index of the credential in the issuers revocation bitmap. Each index SHOULD be unique among all credentials linking to the same [Revocation Bitmap Service](#revocation-bitmap-service). To ensure user unlinkability, this value MUST NOT be disclosed to the verifier (this is done by default). | +| `startValidityTimeframe`| The `startValidityTimeframe` property MUST be a [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339)-compliant timestamp. | +| `endValidityTimeframe`| The `endValidityTimeframe` property MUST be a [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339)-compliant timestamp. | + +#### Example + +An example of a verifiable credential with a `credentialStatus` of type `RevocationTimeframe2024`. + +```json +{ + "@context": "https://www.w3.org/2018/credentials/v1", + "id": "https://example.edu/credentials/3732", + "type": ["VerifiableCredential", "UniversityDegreeCredential"], + "credentialSubject": { + "id": "did:iota:B8DucnzULJ9E8cmaReYoePU2b7UKE9WKxyEVov8tQA7H", + "GPA": "4.0", + "degree": "Bachelor of Science and Arts", + "name": "Alice" + }, + "issuer": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "issuanceDate": "2022-06-13T08:04:36Z", + "credentialStatus": { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#my-revocation-service", + "type": "RevocationTimeframe2024", + "revocationBitmapIndex": "5" + "startValidityTimeframe": "2024-05-03T08:00:00Z", + "endValidityTimeframe": "2024-05-03T08:05:00Z", + }, +} +``` + +### Revocation Timeframe Service + +To allow verifiers to check the status of a [Revocation Timeframe Status](#revocation-bitmap-status), the DID document of the credential issuer MUST contain a [service](https://www.w3.org/TR/did-core/#services) with the following properties: + +| Property | Description | +| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | The constraints on the `id` property are listed in the [DID Core service specification](https://www.w3.org/TR/did-core/#services). The `id` property MUST be a DID URL uniquely identifying the revocation bitmap. | +| `type` | The `type` property MUST be `"RevocationTimeframe2024"`. | +| `serviceEndpoint` | The `serviceEndpoint` MUST be generated according to the [service endpoint generation algorithm](#service-endpoint-generation-algorithm). | + +#### Example + +An example of an issuers DID document where credential `"5"` in the `#revocation` service is revoked: + +```json +{ + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "verificationMethod": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#key-1", + "controller": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "z3hgM9fNkhwgT5mECbj1HdKoFNZgpffwQYEV8WBVHphXq" + } + ], + "capabilityInvocation": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#sign-0", + "controller": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "z83F6zbD3KqaxvQhqo25LvSXzoDdpZmp3EpPVonSVACwZ" + } + ], + "service": [ + { + "id": "did:iota:EvaQhPXXsJsGgxSXGhZGMCvTt63KuAFtaGThx6a5nSpw#revocation", + "type": "RevocationTimeframe2024", + "serviceEndpoint": "data:application/octet-stream;base64,ZUp5ek1tQmdZR1NBQUFFZ1ptVUFBQWZPQUlF" + } + ] +} +``` + +## Algorithms + +For generation and expansion of the service endpoint see [`RevocationBitmap2022`](../revocation-bitmap-2022#algorithms). + +### Validation Algorithm + +The following steps MUST be followed when checking whether a verifiable credential is revoked: + +1. Let **credential** be a verifiable credential containing a `credentialStatus` whose `type` is `RevocationTimeframe2024`. +2. Let **now** be the string serialization of the RFC3339 timestamp representing the current UTC time. +3. Let **start validity timeframe** and **end validity timeframe** be the RFC3339 timestamps of the `startValidityTimeframe` and `endValidityTimeframe` (respectively) properties contained in the `credentialStatus` of the **credential**. +4. Return `true` if `startValidityTimeframe <= now < endValidityTimeframe`, `false` otherwise. + +## Test Vectors +See [`RevocationBitmap2022`](../revocation-bitmap-2022#test-vectors). \ No newline at end of file diff --git a/docs/build/identity.rs/1.3/docs/welcome.mdx b/docs/build/identity.rs/1.3/docs/welcome.mdx new file mode 100644 index 00000000000..29910d80cb0 --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/welcome.mdx @@ -0,0 +1,91 @@ +--- +description: The most important concepts that developers will need to know to utilize IOTA Identity to its full potential. +image: /img/Identity_icon.png +tags: + - Identity + - guide + - TOC + - overview + - reference +--- +# IOTA Identity Framework + +![IOTA Identity](/img/banner/banner_identity.svg) + +The IOTA Identity framework implements the most common standards and patterns for Decentralized Identity in both a DLT agnostic and `iota` method-specific manner. +It is designed to work for Identity for [People](#identity-for-people), [Organizations](#identity-for-organizations), +[Things, and Objects](#identity-for-things) acting as a unifying layer of trust between everyone and everything. + +## Introduction to Decentralized Identity + +Decentralized or Self-Sovereign Identity (SSI) gives individuals full control over their online identity, +offering a remedy for database breaches, lack of digital trust, and stringent privacy laws like GDPR. +Digital identity bridges the gap between online pseudonyms and real-world personas, enabling true verifiable identities. This gives individuals the power to choose which data to share and with whom. + + + +### Identity for People + +:::info Privacy + +IOTA Identity builds a new internet, without usernames, passwords, endless repeated forums, or uncontrolled data harvesting. + +::: + +Information about anyone's life is spread across many locations. Most people have numerous unorganized important documents at home, hundreds of online accounts, and many more online footprints. Through statistical predictive analysis, computer programs can harvest unverified online information sources and create a reasonably accurate profile about our lives. These profiles are accurate enough for targeted advertising and personalized content but lack the proof and trust for them to be used in business. This results in an antiquated customer experience where we have to submit our age and address for every purchase we make and every account we create. It also inhibits our ability to do many online tasks like requesting and extending licenses or taking out a mortgage. + +Self-Sovereign Identity is about returning autonomy and privacy to the individual, while also improving our online experience. Some movements focus on data privacy, preventing companies from using our information altogether, but with the IOTA Identity framework you control which part of the information you want to reveal. The user can create a single online profile containing all our personal information. They can decide who they share what information with, and a verifier checks if the information is correct, making the data trustworthy. This moves their online profile from a statistical estimation by corporate entities to an accurate and verifiable profile under their own control. + +IOTA Identity allows a new internet without usernames, passwords, endlessly repeated forms or data harvesting. Users have ultimate control and can choose to supply service providers with their personal data, who in return provide personalized experiences. Data will still flow, and perhaps even more than before, but it will always be in the individual's interest instead of a corporation's. People will gain additional benefits in sharing their data, either in monetary value or improved customer experience. This system is impossible in non-neutral environments such as permissioned or fee-based ledgers. + +Governmental mechanisms for building _digital identities_ are currently being established throughout Europe and Asia, with demand increasing around the globe. However, they are managed by single entities and restricted to the governments that created them. By decentralizing a framework for these standards to adapt to, we have a system for intergovernmental verification of individuals and devices. A person’s digital identification will be transferable across borders like a passport. However, it will no longer require the trust of the issuing government due to the digital trust established by the open and auditable system. + +### Identity for Organizations + +:::info GDPR + +IOTA Identity allows organizations to comply with GDPR in a cost-efficient and privacy-enabling manner + +::: + +Corporations are associated with greed and abuse of power. This reputation stems from the role some have chosen to take within society. Corporations are trusted with our data, but often do not act responsibly; vulnerability, fix, patch, repeat. In software and systems, we have seen this cycle repeat. Headlines on data leaks are now an ever-present feature in the news. + +IOTA Identity presents an opportunity for companies to embrace a new role in the ecosystem. Traditional approaches do not provide cost-efficient solutions to new legislation like GDPR. IOTA Identity enables organizations to change their processes to comply with the new regulations in a cost-efficient and privacy-enabling manner. Features of “Data Protection and Privacy by Design” shift responsibility over Personal Identifiable Information (PII) from organization to customer, and organizations no longer need to store that data. The relationship between customer and organization is also tightened as communication via a third-party Identity provider like Google or Facebook is no longer needed. + +Due to Know-Your-Customer (KYC) and Anti-Money Laundering (AML) obligations, companies can be certain who their customers are. These services also provide unique insight into their customers’ data. These insights can be combined and translated into verifiable credentials, providing a new “Trust Anchor” service with the potential for new business models. KYC and AML credentials would return the autonomy of personal data to the customer. Once companies accept other companies' KYC and AML credentials, the enrollment time for new customers is significantly reduced, as are the costs. With the personal data secured by the customer, companies can afford to store less data in their databases, reducing risk and responsibility and fulfilling the goals of legislation such as GDPR. + +Organizations that have their own decentralized identities can also combat fraud and increase control over their online brand. Companies can sign invoices and agreements using their decentralized identities. While interacting with the customers, they will also be able to reliably identify themselves. + +### Identity for Things + +:::info TRUST + +IOTA Identity adds the missing key ingredient for the "Economy of Things": Trust. + +::: + +With Identity of Things (IDoT), devices are provided with a unique global identity that are able to prove many attributes, including their capabilities, specifications, and authenticity. People, organizations, and other devices will only pay for devices that can prove their ability to fulfill the required task. This basis of trust prevents fraudulent activity. Additionally, using the IOTA ledger, the task's progress can be immutably logged. Combining the IOTA protocol and the IOTA Identity framework, we can automate the entire interaction between all parties without requiring predefined trust. The [Industry Marketplace](https://industry.iota.org/) provides a perfect example of how this framework and level of autonomy work. + +There is a growth in applications that generate Digital Twins for physical devices or objects, such as the Asset Administration Shell (AAS) developed for our Industry Marketplace. Digital twins are online profiles representing a device or object. They provide a virtual state that mirrors reality by emulating the device or object’s physical state through data input sources like sensors. A digital twin is often used to monitor states and execute actions based on the information. Digital twins are only rarely shared outside the associated application and organization due to the complexities in sharing and matching profiles. However, empowered with a digital identity, digital twin sharing would become possible. Once data is verifiable and trusted, digital twins can form the basis for the digital representation of physical devices and objects. This allows other identities to interact with them automatically and provide services such as predictive maintenance. + +Security is a major barrier to advancing technologies that use IoT. Whether it is the smart devices in our homes or at a larger scale, the critical infrastructure of organizations and cities, security must be at the core. It is central to any globally unifying identity solution. By integrating advanced research in cryptography and digital ledgers and combining it with a scalable access and management system, security will become a core functionality of the systems we build. By using scalable device DIDs, integrating verification and reputation schemes, and allowing for transparent tamper-proof accountability, we begin to understand how we can future-proof the security of our systems, allowing us to start trusting the process and not the patch. + +### One Framework. Any Identity + +The IOTA Identity framework serves as a ubiquitous layer of trust for the internet. Whether it's people, organizations, or things, the framework enables the creation of digital identities, fosters trust-building through verifiable credentials, and ensures seamless interaction among different entities. + +### Why IOTA? + +IOTA stands apart as a scalable, feeless Distributed Ledger Technology (DLT), suitable for a universal identity solution. Some features of IOTA include: + +* **Cost-effectiveness**: Usually, minting decentralized identities costs fees. IOTA Identity has redeemable and predictable deposits but no fees. +* **High availability**: Identities are always available on all network nodes - for holders, issuers, and verifiers. +* **Security**: Write access to identities is secured through multi-level control structures with key rotation capabilities, allowing for backup access and recoverability. +* **Integrity**: Updates go through the same mechanisms that secure the IOTA network, guaranteeing consistent state and history of all identities. diff --git a/docs/build/identity.rs/1.3/docs/workflow.mdx b/docs/build/identity.rs/1.3/docs/workflow.mdx new file mode 100644 index 00000000000..70449a8673c --- /dev/null +++ b/docs/build/identity.rs/1.3/docs/workflow.mdx @@ -0,0 +1,179 @@ +--- +title: Identity.rs workflow +sidebar_label: Workflow +description: Learn about the software development process of the IOTA Identity repository. +image: /img/Identity_icon.png +tags: + - Workflow + - Contribute + - GitHub + - explanation +--- + +# Identity Workflow + +In this article you will learn about the software development process for the IOTA Identity repository as well as key terms, functions, and the overall operability of the workflow components. + +## Issues + +Issues are opened when a certain task or problem is noted but cannot immediately be fixed. Issues may contain bug reports, requests, or larger topics. Please use the correct GitHub issue template for your issue type. Only IOTA Foundation members should use the task templates flagged for maintainers. You should make sure to [label](#issue-labels) the issue correctly. As a contributor, you may also add issues to a certain [project](https://github.com/iotaledger/identity.rs/projects/). + +## Git + +### Pull Requests + +New branches should be pushed to the GitHub repository as soon as possible, making them public to all contributors. In addition, a pull request (PR) should be opened in draft status, describing the goals and any requirements of the changes. To generate good [changelogs](#changelog), a PR title must be written in a way that is suitable as a changelog entry while the PR must be [labeled](#pr-labels) correctly. + +Any code written should frequently be committed and pushed back to the GitHub branch. This acts as both a back-up mechanism and provides transparency towards other contributors and the community. You should also pull from the origin branch of the PR regularly to prevent merge conflicts. + +Other contributors are encouraged to provide feedback on a PR during its development. A PR should be flagged as 'ready for review' once the PR has implemented all changes and no further commits are planned by the main contributors. The repository requires a review to be provided by at least one (other) developer in the team that works in the same language or has knowledge of the work before it can be merged. For larger PRs, the review of two maintainers is recommended. + +Once a PR is approved, the preferred method is "squash-and-merge" for non-epic branches to keep the destination branch clean and allow for many small commits while work is in-progress. Epic branches must instead be merged with the merge commits of included PRs intact, so the [changelog generator](#changelog) can detect included changes. Once merged in, the source branch may be deleted. + +### Branches + +IOTA Identity always has two permanent branches: `main` and `dev`. Both branches are protected and disallow direct commits; the only changes allowed are from pull requests approved and merged by maintainers. + +#### [Main](https://github.com/iotaledger/identity.rs/tree/main) (main) + +The `main` branch contains a stable version of the code that is released towards package managers such as `crates.io` and `npm`. This branch only accepts PRs that merge from `release` or `hotfix` branches. + +#### [Dev](https://github.com/iotaledger/identity.rs) (dev) + +The `dev` branch contains a frequently updated version of the code that is released towards package managers under a development flag. These releases may contain breaking changes without a strong notice towards developers using them. While the `dev` branch may get frequent updates, it may not contain unfinished features. Any large, multi-PR feature should be committed to a long-lived `epic` branch created specifically for that feature. + +### Work Branches + +These are branches that developers work on directly. Their names should be prefixed appropriately with one of the following categories. For example, a PR fixing a null pointer bug in the Wasm bindings might be created from a branch called `fix/client-non-null`. + +#### Feature (feat/, doc/, chore/, fix/) + +Singular PR contributions should create either a `feat`, `doc`, `chore`, or `fix` branch, depending on the type of changes. These may be branched from either the `dev` branch or an `epic` branch. If the number of lines of code are going to be relatively small and the work completed in a single PR, the branch should be created from `dev` and merged back into `dev` once completed. Otherwise, the branches should be created from their associated `epic` branch and be merged back into the same `epic` branch. + +- `feat` branches should contain changes to the code that expand or modify functionality. They should also include updates to the documentation and examples related to the feature, though `doc` branches may be used to catch up on documenting a feature. +- `doc` branches contain changes to code documentation or the wiki. These PRs should be kept relatively small to avoid burdening a reviewer with too many documentation updates at once. For example, during a documentation catch-up, we will have a branch or PR per documentation page. +- `chore` branches are short-lived branches that contain no significant features or functionality changes, but rather smaller fixes such as typos, code fixes, minor refactors, and CI changes. +- `fix` branches correct bugs such as compilation errors or where existing features do not behave as expected, generally without introducing any new functionality or breaking changes. + +We recommend integrating `dev` or `epic` regularly, depending on where the branch started, to reduce the possibility and potential size of merge conflicts. + +#### Epic (epic/) + +Long-lived `epic` branches should be created as soon as a feature is expected to require more than one PR. The `epic` branch should be branched from `dev` and should only accept merges that are related to the feature being developed. A PR should be opened as soon as the branch is created to publicly notify contributors about the development, the goals and requirements of the feature, and the existence of the branch. It is recommended you integrate `dev` often to reduce the possibility and potential size of merge conflicts. Epic branches must not be squash-merged, otherwise the [changelog generator](#changelog) will not detect its constituent PRs. + +### Semantic Versioning + +Semantic Versioning (SemVer) describes a methodology for versioning of software to convey meaning and guarantees through the version string. A typical version string looks like `2.3.1`, where `2` is called the major version, `3` the minor version and `1` the patch or bugfix version. + +The central idea is that every part of the version string conveys meaning. A major change introduces behavior that is incompatible with previous versions of the software, while a minor change adds backwards-compatible functionality and a patch simply fixes a problem. So just by looking at the version string, an implementer will understand the effort needed to integrate a new version. + +For more detailed information and an overview of advanced features, see [Semantic Versioning 2.0.0](https://semver.org/). Though this is not to be confused with [Sentimental Versioning](http://sentimentalversioning.org/). + +### Changelog + +A changelog is a file describing a software project for humans to grasp the type and content of changes from version to version. Changelogs are closely related to the versioning of software, since individual changes are grouped into versions that are, in our case, referenced by a [SemVer string](#semantic-versioning). We generally follow the recommendations from [keepachangelog](https://keepachangelog.com/en/1.0.0/). The changelog in this project is generated from the titles and [labels](#pr-labels) of [pull requests](#pull-requests). + +#### PR labels + +Labels are used to categorize changes in [pull requests](#pull-requests). Adding a label will include the labeled [PR](#pull-requests) title in the related section of the generated [changelog](#changelog). + +Changelogs are generated for the core Rust library and each binding separately. To attach a PR to a specific changelog, use the following labels: + +##### `Rust` + +This includes the PR in the core Rust library changelog. + +##### `Wasm` + +This includes the PR in the WASM bindings changelog. + +It is also necessary to add an appropriate label for the type of change in the PR. The following labels determine in which section a PR title will appear: + +##### Changed + +Maps to the major version of [Semantic Versioning](#semantic-versioning). +labels: `Breaking change` + +##### Added + +Maps to the minor version of [Semantic Versioning](#semantic-versioning). +labels: `Added` + +##### Patch + +Maps to the patch version of [Semantic Versioning](#semantic-versioning). +labels: `Patch` + +##### Deprecated + +Marks features that will be removed in the feature. No special version consideration should apply here, since the feature did not change yet. +labels: `Deprecated` + +##### Removed + +Marks features as being removed. Typically the features should have been deprecated in the previous version. This maps to the major version of [Semantic Versioning](#semantic-versioning). +labels: `Removed` + +##### Excluded tags + +Marks changes that should not be part of the changelog. This should only be used for documentation and rare exceptions. +labels: `Documentation`, `No changelog` + +Please note that a PR can only be listed in one section of a changelog. So attaching the labels `Rust` `Added` `Patch` to a PR, for example, is invalid because `Added` and `Patch` conflict. + +##### Release summary + +To attach a release summary to a version in the changelog, an issue with the label `release-summary` must be created. Create a GitHub milestone matching the version you want to describe and attach it to the issue. The issue can be closed immediately. The text of the issue will be included in the changelog as the release summary. + +### Issue Labels + +The following labels are used to categorize issues but do not have any effect on changelogs: `Request`, `Enhancement`, `Bug`, `Chore`, `Dependencies`, `Help wanted`, `Duplicate`, `Wontfix`. + +## Release + +With the release process, we can deliver versions of our software to the community. We use sensible automation where it helps to remove tedium. However, some steps that require active decision-making remain manual. + +The final list of changes from the [changelog](#changelog) informs the version of the release. If at least one change mapping to a major version is included, the major version needs to be incremented. In that case, the minor and patch versions are set to `0`. If there are no changes related to a major version, but changes related to a minor version are present, the minor version needs to be incremented while the patch version is set to `0`. Otherwise, only the patch version is incremented. Determining the version of the release is the responsibility of the person performing the release. + +The determined version of the release is used to create the [hotfix](#hotfix) or [release](#release) branch. For example, a major release from the previous version `v2.3.1` will create the `release/v3.0.0` branch. + +Notice the `v` in front of the version. We [tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) all release in git in the form of `vMAJOR.MINOR.PATCH`. For bindings, we prefix the tag with the binding name, so a tag for Wasm would look like `wasm-v1.2.3`. Bindings and the core Rust library are versioned and released independently. + +Additionally, we may release `dev` versions separately for both bindings and the core Rust library. These releases are meant as a preview of upcoming versions. For example, if the current version is `1.2.3` with the tag `v1.2.3`, we may release `v1.3.0-dev.1` which is then superseded by the actual `1.3.0` release. + +You should follow these steps to create a release: + +1. Ensure all the changes you want to release are on the `dev` branch. +2. Select the appropriate GitHub Actions workflow, e.g. `Rust Create Release PR`. + 2.1. Decide if you want to create a `dev` or `main` release. + 2.2. Determine the next version string. + 2.3. Run the workflow. The workflow will create a PR from `dev` targeting `dev` with release related changes. +3. Review the PR. + 3.1. The PR will update the changelog, check that it has all expected entries in the appropriate sections and the determined version matches the changelog according to [SemVer](#semantic-versioning). + 3.2. The PR will update project version strings, ensure these are correct and match the expected version. + 3.3. Refer to [Troubleshooting](#troubleshooting) if anything is incorrect. +4. Merge the PR. + 4.1. On merging to `dev`, an automatic workflow is triggered that builds and publishes artifacts to the appropriate package manager (`crates.io` for Rust, `npm` for the WASM bindings), and creates a GitHub Release (only for `main` version releases of the core Rust library). +5. For `main` version releases, merge the `dev` branch into the `main` branch. + +### Troubleshooting + +#### The changelog entries have the wrong description in the release PR + +Update the titles of the relevant PRs, then re-run the workflow with the same parameters. The release PR will be updated with the new changelog. + +#### The changelog in the release PR is missing entries, has unrelated entries, or entries in the wrong section + +Fix the [labels](#pr-labels) on the relevant PRs, then re-run the workflow with the same parameters. The release PR will be updated with the new changelog. + +#### The release description in the release PR is missing or wrong + +Fix the issue description, milestone, and label according to the [release summaries guide](#release-summary) and re-run the workflow with the same parameters. The release PR will be updated with the new changelog. + +#### Features or code are missing from the release + +Merge the code into the `dev` branch, then re-run the workflow with the same parameters. The release PR will be updated with the changes. + +#### I want to abort the release for any reason + +Close the PR. You can reopen it later. // TODO: can I just re-run the workflow? Maybe that needs an "I want to resume an aborted release" section? diff --git a/docs/build/identity.rs/1.3/sidebars.js b/docs/build/identity.rs/1.3/sidebars.js new file mode 100644 index 00000000000..552c26a33ce --- /dev/null +++ b/docs/build/identity.rs/1.3/sidebars.js @@ -0,0 +1,116 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + // tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + + docs: [ + { + type: 'doc', + id: 'welcome', + label: 'Welcome', + }, + { + type: 'category', + label: 'Getting Started', + collapsed: false, + items: ['getting-started/rust', 'getting-started/wasm'], + }, + { + type: 'category', + label: 'Explanations', + items: [ + 'explanations/decentralized-identifiers', + 'explanations/verifiable-credentials', + 'explanations/verifiable-presentations', + 'explanations/about-alias-outputs', + ], + }, + { + type: 'category', + label: 'How To', + items: [ + { + type: 'category', + label: 'Decentralized Identifiers (DID)', + items: [ + 'how-tos/decentralized-identifiers/create', + 'how-tos/decentralized-identifiers/update', + 'how-tos/decentralized-identifiers/resolve', + 'how-tos/decentralized-identifiers/delete', + ], + }, + { + type: 'category', + label: 'Verifiable Credentials', + items: [ + 'how-tos/verifiable-credentials/create', + 'how-tos/verifiable-credentials/revocation', + 'how-tos/verifiable-credentials/selective-disclosure', + 'how-tos/verifiable-credentials/zero-knowledge-selective-disclosure', + ], + }, + { + type: 'category', + label: 'Verifiable Presentations', + items: ['how-tos/verifiable-presentations/create-and-validate'], + }, + { + type: 'category', + label: 'Domain Linkage', + items: ['how-tos/domain-linkage/create-and-verify'], + }, + 'how-tos/key-storage', + ], + }, + { + type: 'category', + label: 'References', + collapsed: true, + items: [ + { + type: 'category', + label: 'API', + items: [ + { + type: 'doc', + id: 'references/api/wasm', + label: 'Wasm', + }, + { + type: 'link', + label: 'Rust', + href: 'https://docs.rs/identity_iota/latest/identity_iota/index.html', + }, + ], + }, + { + type: 'category', + label: 'Specifications', + items: [ + 'references/specifications/overview', + 'references/specifications/iota-did-method-spec', + 'references/specifications/revocation-bitmap-2022', + 'references/specifications/revocation-timeframe-2024', + ], + }, + ], + }, + 'glossary', + 'contribute', + 'workflow', + 'contact', + 'faq', + ], +}; diff --git a/docs/build/iota-sandbox/docs/welcome.md b/docs/build/iota-sandbox/docs/welcome.md index ca37c427f08..4b4270a749a 100644 --- a/docs/build/iota-sandbox/docs/welcome.md +++ b/docs/build/iota-sandbox/docs/welcome.md @@ -21,10 +21,9 @@ It is not for creating production-ready networks. ::: -:::tip Public Testnet +:::tip Testnet -If possible, -you should use the [public testnet](https://wiki.iota.org/build/networks-endpoints/#public-testnet) +If possible, you should use one of the testnets(/build/networks-endpoints) where you can experiment with confidence and community support. ::: diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_network_warning.md b/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_network_warning.md deleted file mode 100644 index e7a18ce4286..00000000000 --- a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_network_warning.md +++ /dev/null @@ -1,6 +0,0 @@ -:::caution Only Available on Shimmer - -At the moment, Smart Contracts are only available on [Shimmer](/build/networks-endpoints/#shimmer) and -its [Public Testnet](/build/networks-endpoints/#public-testnet) network. - -::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/quick-start.mdx b/docs/build/isc/v1.0.0-rc.6/docs/getting-started/quick-start.mdx deleted file mode 100644 index ea23ffe1c75..00000000000 --- a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/quick-start.mdx +++ /dev/null @@ -1,92 +0,0 @@ ---- -description: This guide will help you quickly get started with the [Public Testnet](/build/networks-endpoints/#public-testnet) -image: /img/logo/WASP_logo_dark.png -tags: - - quickstart - - developer - - using - - EVM - - Ethereum - - Solidity - - metamask - - JSON - - RPC ---- - -import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; -import NetworkInfo from '@theme/NetworkInfo'; -import { Networks } from '@theme/constant'; -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import Link from '@docusaurus/Link'; - -# EVM Testnets Quickstart Guide - -This guide will help you quickly get started with our [EVM Testnets](/build/networks-endpoints), where you can deploy and interact with EVM-compatible smart contracts. - -## Prerequisites - -- [MetaMask](https://metamask.io/) browser extension installed - -## Setup MetaMask - -Click this button: - - - -:::tip - -Please read [the MetaMask section in the tools guide](tools.mdx#metamask) for a detailed guide. - -::: - -## Get Testnet Tokens - -:::tip Fund your testnet account - -If you want to fund your EVM testnet account, please refer to our [How To Get Funds guide](../how-tos/send-funds-from-L1-to-L2.mdx). - -::: - -1. Go to the [IOTA EVM](https://evm-toolkit.evm.testnet.iotaledger.net) or [ShimmerEVM](https://evm-toolkit.evm.testnet.shimmer.network/) Testnet Toolkit. -2. Connect your MetaMask wallet by clicking "Connect Wallet" or paste an EVM address. -3. Select the account you want to receive testnet tokens. -4. Click "Send funds" to get testnet tokens. - -## Get Simulated Bridged Tokens - -:::info ShimmerEVM Testnet - -The simulated bridged tokens are currently only available on the ShimmerEVM Testnet. - -::: - -1. Go to the [ERC20 Simulated Token Faucet](https://evm-faucet.testnet.shimmer.network/). -2. Connect your MetaMask wallet by clicking "Connect Wallet". -3. Select the account you want to receive simulated bridged tokens. -4. Choose the desired token (fETH, fBTC, fUSDT, etc.) from the dropdown list. -5. Click "Submit" to get the selected simulated bridged tokens. - -## Deploy and Interact with Smart Contracts - -You can now use your testnet tokens and simulated bridged tokens to deploy and interact with smart contracts on the testnets. Utilize popular development tools and frameworks, such as [Hardhat](https://hardhat.org/), or [Remix](https://remix.ethereum.org/), to build, test, and deploy your smart contracts. - -## Explore the Public Testnet - -Visit the corresponding Testnet Block Explorer to monitor the chain, track transactions, and explore deployed smart contracts. - - - -Explorer - - -Explorer - - - -## Additional Resources - -- [GitHub issues page for Wasp](https://github.com/iotaledger/wasp/issues) -- [Firefly](https://firefly.iota.org) - -With this quickstart guide, you should now be able to set up and start exploring the [Testnet](/build/networks-endpoints). As you begin to deploy and interact with smart contracts, remember to provide feedback on any issues or improvements you discover to help make our EVM even better. Happy developing! diff --git a/docs/build/isc/v1.1/docs/_admonitions/_ERC721.md b/docs/build/isc/v1.1/docs/_admonitions/_ERC721.md new file mode 100644 index 00000000000..76191eec6be --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_ERC721.md @@ -0,0 +1,5 @@ +:::info ERC721 + +As your L1 NFT is always registered as [ERC721](https://eips.ethereum.org/EIPS/eip-721), you might want to get the metadata like `tokenURI` from there. Using `getIRC27NFTData` is normally only needed if you need special [IRC27](https://wiki.iota.org/tips/tips/TIP-0027/) metadata. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM-required-prior-knowledge.md b/docs/build/isc/v1.1/docs/_admonitions/_EVM-required-prior-knowledge.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM-required-prior-knowledge.md rename to docs/build/isc/v1.1/docs/_admonitions/_EVM-required-prior-knowledge.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM_compatibility.md b/docs/build/isc/v1.1/docs/_admonitions/_EVM_compatibility.md similarity index 98% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM_compatibility.md rename to docs/build/isc/v1.1/docs/_admonitions/_EVM_compatibility.md index 1f20154e1ea..23cc9bfdb24 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_EVM_compatibility.md +++ b/docs/build/isc/v1.1/docs/_admonitions/_EVM_compatibility.md @@ -2,6 +2,6 @@ The ISC EVM layer is also designed to be as compatible as possible with existing Ethereum [tools](../getting-started/tools.mdx) and functionalities. However, please make sure you have checked out the current -[properties and limitations](../getting-started/compatibility.md). +[properties and limitations](../getting-started/compatibility.mdx). ::: \ No newline at end of file diff --git a/docs/build/isc/v1.1/docs/_admonitions/_IRC27.md b/docs/build/isc/v1.1/docs/_admonitions/_IRC27.md new file mode 100644 index 00000000000..1831e8fe100 --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_IRC27.md @@ -0,0 +1,5 @@ +:::info IRC27NFTMetadata URI + +The uri property contains a JSON object which follows the `ERC721` standard. This JSON is also returned by the [`tokenURI`](../reference/magic-contract/ERC721NFTs.md#tokenuri) function from the `ERC721NFTs` contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_about-accounts.md b/docs/build/isc/v1.1/docs/_admonitions/_about-accounts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_about-accounts.md rename to docs/build/isc/v1.1/docs/_admonitions/_about-accounts.md diff --git a/docs/build/isc/v1.1/docs/_admonitions/_create-native-token.md b/docs/build/isc/v1.1/docs/_admonitions/_create-native-token.md new file mode 100644 index 00000000000..223ed9aef7d --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_create-native-token.md @@ -0,0 +1,5 @@ +:::tip Create a Native Token + +Create your first native token by following our how to [Create a Native Token Guide](../how-tos/core-contracts/token/create-native-token.md/). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_deploy_a_smart_contract.md b/docs/build/isc/v1.1/docs/_admonitions/_deploy_a_smart_contract.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_deploy_a_smart_contract.md rename to docs/build/isc/v1.1/docs/_admonitions/_deploy_a_smart_contract.md diff --git a/docs/build/isc/v1.1/docs/_admonitions/_mint-nft.md b/docs/build/isc/v1.1/docs/_admonitions/_mint-nft.md new file mode 100644 index 00000000000..1ed17749708 --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_mint-nft.md @@ -0,0 +1,5 @@ +:::tip Mint an NFT + +Mint your first NFT following our how to [mint an NFT guide](../how-tos/core-contracts/nft/mint-nft.md#about-nfts). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_ownership.md b/docs/build/isc/v1.1/docs/_admonitions/_ownership.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_ownership.md rename to docs/build/isc/v1.1/docs/_admonitions/_ownership.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_payable.md b/docs/build/isc/v1.1/docs/_admonitions/_payable.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_payable.md rename to docs/build/isc/v1.1/docs/_admonitions/_payable.md diff --git a/docs/build/isc/v1.1/docs/_admonitions/_query_gas_fees.md b/docs/build/isc/v1.1/docs/_admonitions/_query_gas_fees.md new file mode 100644 index 00000000000..cd1fc1dd456 --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_query_gas_fees.md @@ -0,0 +1,5 @@ +:::tip Current Gas Fee + +You can get the minimum gas fee by querying the `eth_gasPrice` using the [JSON-RPC API](../reference/json-rpc-spec.md/#json-rpc-methods-according-to-ethereum-client-api). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_remix-IDE.md b/docs/build/isc/v1.1/docs/_admonitions/_remix-IDE.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_admonitions/_remix-IDE.md rename to docs/build/isc/v1.1/docs/_admonitions/_remix-IDE.md diff --git a/docs/build/isc/v1.1/docs/_admonitions/_token-demo-setup.md b/docs/build/isc/v1.1/docs/_admonitions/_token-demo-setup.md new file mode 100644 index 00000000000..9192df2e16e --- /dev/null +++ b/docs/build/isc/v1.1/docs/_admonitions/_token-demo-setup.md @@ -0,0 +1,6 @@ +:::info Setup Demo Repo + +Visit the Demo Repo GitHub page for instructions on how to properly setup, +[IOTA Cross Chain Token Demo](https://github.com/iotaledger/isc-cross-chain/tree/master?tab=readme-ov-file#iota-cross-chain-token-demo) + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/_hardhat_config.md b/docs/build/isc/v1.1/docs/_partials/_hardhat_config.md similarity index 50% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/_hardhat_config.md rename to docs/build/isc/v1.1/docs/_partials/_hardhat_config.md index d6257484a0b..d40752cc44b 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/_partials/_hardhat_config.md +++ b/docs/build/isc/v1.1/docs/_partials/_hardhat_config.md @@ -3,15 +3,30 @@ import { Networks } from '@theme/constant'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; - + + + + +{` +networks: { + 'iotaevm-testnet': { + url: '${Networks['iota_testnet'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['iota_testnet'].evm.core.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + {` networks: { 'shimmerevm-testnet': { - url: '${Networks['shimmer_testnet'].evm.rpcUrls[0]}', - chainId: ${parseInt(Networks['shimmer_testnet'].evm.chainId)}, + url: '${Networks['shimmer_testnet'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer_testnet'].evm.core.chainId)}, accounts: [YOUR PRIVATE KEY], }, } @@ -19,14 +34,14 @@ networks: { - + {` networks: { - 'iotaevm-testnet': { - url: '${Networks['iota_testnet'].evm.rpcUrls[0]}', - chainId: ${parseInt(Networks['iota_testnet'].evm.chainId)}, + 'iotaevm': { + url: '${Networks['iota'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['iota'].evm.core.chainId)}, accounts: [YOUR PRIVATE KEY], }, } @@ -40,8 +55,8 @@ networks: { {` networks: { 'shimmerevm': { - url: '${Networks['shimmer'].evm.rpcUrls[0]}', - chainId: ${parseInt(Networks['shimmer'].evm.chainId)}, + url: '${Networks['shimmer'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer'].evm.core.chainId)}, accounts: [YOUR PRIVATE KEY], }, } diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/_on_off_ledger_request.md b/docs/build/isc/v1.1/docs/_partials/_on_off_ledger_request.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/_on_off_ledger_request.md rename to docs/build/isc/v1.1/docs/_partials/_on_off_ledger_request.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_check_storage_deposit.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_check_storage_deposit.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_check_storage_deposit.md rename to docs/build/isc/v1.1/docs/_partials/how-tos/token/_check_storage_deposit.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_example_code_intro.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_example_code_intro.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/_partials/how-tos/token/_example_code_intro.md rename to docs/build/isc/v1.1/docs/_partials/how-tos/token/_example_code_intro.md diff --git a/docs/build/isc/v1.1/docs/_partials/how-tos/token/_get-nft-metadata.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_get-nft-metadata.md new file mode 100644 index 00000000000..a13f2634c7d --- /dev/null +++ b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_get-nft-metadata.md @@ -0,0 +1,5 @@ +:::tip Mint an NFT + +Mint your first NFT following our how to [mint an NFT guide](../../../how-tos/core-contracts/nft/mint-nft.md#about-nfts). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md new file mode 100644 index 00000000000..1a70e93ffaa --- /dev/null +++ b/docs/build/isc/v1.1/docs/_partials/how-tos/token/_obsolete_token_creation.md @@ -0,0 +1,5 @@ +:::caution + +This method is now obsolete, use the new [`createNativeTokenFoundry`](../../../how-tos/core-contracts/token/create-native-token.md) method instead. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/consensus.md b/docs/build/isc/v1.1/docs/explanations/consensus.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/consensus.md rename to docs/build/isc/v1.1/docs/explanations/consensus.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/context.mdx b/docs/build/isc/v1.1/docs/explanations/context.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/context.mdx rename to docs/build/isc/v1.1/docs/explanations/context.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/core-contracts.md b/docs/build/isc/v1.1/docs/explanations/core-contracts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/core-contracts.md rename to docs/build/isc/v1.1/docs/explanations/core-contracts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/how-accounts-work.md b/docs/build/isc/v1.1/docs/explanations/how-accounts-work.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/how-accounts-work.md rename to docs/build/isc/v1.1/docs/explanations/how-accounts-work.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/invocation.md b/docs/build/isc/v1.1/docs/explanations/invocation.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/invocation.md rename to docs/build/isc/v1.1/docs/explanations/invocation.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/sandbox.md b/docs/build/isc/v1.1/docs/explanations/sandbox.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/sandbox.md rename to docs/build/isc/v1.1/docs/explanations/sandbox.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contract-anatomy.md b/docs/build/isc/v1.1/docs/explanations/smart-contract-anatomy.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contract-anatomy.md rename to docs/build/isc/v1.1/docs/explanations/smart-contract-anatomy.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contracts.md b/docs/build/isc/v1.1/docs/explanations/smart-contracts.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/smart-contracts.md rename to docs/build/isc/v1.1/docs/explanations/smart-contracts.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/state_manager.md b/docs/build/isc/v1.1/docs/explanations/state_manager.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/state_manager.md rename to docs/build/isc/v1.1/docs/explanations/state_manager.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/states.md b/docs/build/isc/v1.1/docs/explanations/states.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/states.md rename to docs/build/isc/v1.1/docs/explanations/states.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/explanations/validators.md b/docs/build/isc/v1.1/docs/explanations/validators.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/explanations/validators.md rename to docs/build/isc/v1.1/docs/explanations/validators.md diff --git a/docs/build/isc/v1.1/docs/getting-started/compatibility.mdx b/docs/build/isc/v1.1/docs/getting-started/compatibility.mdx new file mode 100644 index 00000000000..193f58e5dee --- /dev/null +++ b/docs/build/isc/v1.1/docs/getting-started/compatibility.mdx @@ -0,0 +1,54 @@ +--- +description: Compatibility between the ISC EVM layer and existing Ethereum smart contracts and tooling. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - EVM + - Ethereum + - Solidity + - limitations + - compatibility + - fees + - reference +--- +import QueryGasFees from '../_admonitions/_query_gas_fees.md'; + +# EVM Compatibility in IOTA Smart Contracts + +The [`evm`](../reference/core-contracts/evm.md) [core contract](../reference/core-contracts/overview.md) +provides EVM support in IOTA Smart Contracts. It stores the EVM state (account balances, state, code, +etc.) and provides a way to execute EVM code to manipulate the state. + +The EVM core contract runs on top of the ISC layer, which provides the rest of the machinery needed to run smart +contracts, such as signed requests, blocks, state, proofs, etc. + +However, the ISC EVM layer is also designed to be as compatible as possible with existing Ethereum tools +like [MetaMask](https://metamask.io/), which assume that the EVM code runs on an Ethereum blockchain composed of +Ethereum blocks containing Ethereum transactions. Since ISC works in a fundamentally different way, +providing 100% compatibility is not possible. We do our best to emulate the behavior of an Ethereum node, so the +Ethereum tools think they are interfacing with an actual Ethereum node, but some differences in behavior are inevitable. + +## Properties and Limitations + +Here are some of the most important properties and limitations of EVM support in IOTA Smart Contracts: + +### No Enforced Block Time + +There is no guaranteed _block time_. A new EVM "_block_" will be created only when an ISC block is created, and ISC does +not enforce an average _block time_. This means that block times are variable; a new block will be created as soon as needed. + +### The Magic Contract + +A [dedicated Ethereum contract](../how-tos/core-contracts/introduction.md) exists to manage Layer 1 tokens and ISC +functionalities, introducing commands like `isc.send(...)` for token transfers. + +### Gas Fees + +As in [Ethereum](https://ethereum.org/en/developers/docs/gas), gas fees depend on the current network usage. As in an +auction, if there is a high demand, users will compete and try to outbid each other's transactions. This means gas prices +increase in periods of high usage and decrease when the usage goes down. However, unlike Ethereum, the chain owner can set +the minimum gas fee. + + + + diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/languages-and-vms.md b/docs/build/isc/v1.1/docs/getting-started/languages-and-vms.md similarity index 97% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/languages-and-vms.md rename to docs/build/isc/v1.1/docs/getting-started/languages-and-vms.md index 64bacc1c8b4..1719a69053f 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/languages-and-vms.md +++ b/docs/build/isc/v1.1/docs/getting-started/languages-and-vms.md @@ -1,10 +1,7 @@ import EVMCompatibility from '../_admonitions/_EVM_compatibility.md' -import NetworkWarning from '../_admonitions/_network_warning.md' # Supported Virtual Machines & Languages - - The current release of IOTA Smart Contracts has support for [EVM/Solidity](#evmsolidity-based-smart-contracts) smart contracts, as well as experimental [Wasm](#wasm-vm-for-isc) smart contracts, providing compatibility with existing smart contracts and tooling from other EVM based chains like Ethereum. This allows us to offer the existing diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/networks-and-chains.mdx b/docs/build/isc/v1.1/docs/getting-started/networks-and-chains.mdx similarity index 79% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/networks-and-chains.mdx rename to docs/build/isc/v1.1/docs/getting-started/networks-and-chains.mdx index cd1d3902ea0..ca5d667d66b 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/networks-and-chains.mdx +++ b/docs/build/isc/v1.1/docs/getting-started/networks-and-chains.mdx @@ -4,7 +4,7 @@ tags: - mainnet - shimmer - devnet - - public testnet + - EVM Testnet - reference - Endpoints --- @@ -35,13 +35,17 @@ The other values (network name and currency symbol) can be whatever value you li ::: -## ShimmerEVM +## IOTA EVM -[ShimmerEVM](https://explorer.evm.shimmer.network/) is the L2 EVM running on top of the Shimmer network. +[IOTA EVM](https://explorer.evm.iota.org) is the L2 EVM running on top of the IOTA network. - + - + + +### Additional Info + + ## ShimmerEVM Testnet @@ -65,8 +69,24 @@ The other values (network name and currency symbol) can be whatever value you li ::: +### Additional Info + + + +## ShimmerEVM + +[ShimmerEVM](https://explorer.evm.shimmer.network/) is the L2 EVM running on top of the Shimmer network. + + + + + +### Additional Info + + + ## Core Contracts -[ShimmerEVM](#shimmerEVM) and the testnet networks have 7 +[IOTA EVM](#IOTAEVM), [ShimmerEVM](#shimmerEVM) and the testnet networks have 7 [core contracts](../reference/core-contracts/overview.md) deployed, as well as the [Magic Contract](../reference/magic-contract/introduction.md). diff --git a/docs/build/isc/v1.1/docs/getting-started/quick-start.mdx b/docs/build/isc/v1.1/docs/getting-started/quick-start.mdx new file mode 100644 index 00000000000..01601ba1d50 --- /dev/null +++ b/docs/build/isc/v1.1/docs/getting-started/quick-start.mdx @@ -0,0 +1,83 @@ +--- +description: This guide will help you quickly get started with the EVM +image: /img/logo/WASP_logo_dark.png +tags: + - quickstart + - developer + - using + - EVM + - Ethereum + - Solidity + - metamask + - JSON + - RPC +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import Link from '@docusaurus/Link'; + +# EVM Quickstart Guide + +This guide will help you quickly get started with our EVM, where you can deploy and interact with EVM-compatible smart contracts. + +## Prerequisites + +- [MetaMask](https://metamask.io/) browser extension installed + +## Setup MetaMask + +Click this button: + + + +:::tip + +Please read [the MetaMask section in the tools guide](tools.mdx#metamask) for a detailed guide. + +::: + +## Deploy and Interact with Smart Contracts + +:::tip Fund your testnet account + +If you are using one of the testnets you can just use the the toolkit to get testnet tokens. + +1. Go to the [IOTA EVM](https://evm-toolkit.evm.testnet.iotaledger.net) or [ShimmerEVM](https://evm-toolkit.evm.testnet.shimmer.network/) Testnet Toolkit. +2. Connect your MetaMask wallet by clicking "Connect Wallet" or paste an EVM address. +3. Select the account you want to receive testnet tokens. +4. Click "Send funds" to get testnet tokens. + +::: + +You can now deploy and interact with smart contracts. Utilize popular development tools and frameworks, such as [Hardhat](https://hardhat.org/), or [Remix](https://remix.ethereum.org/), to build, test, and deploy your smart contracts. + + + +## Explore the Network + +Visit the corresponding Block Explorer to monitor the chain, track transactions, and explore deployed smart contracts. + + + +Explorer + + +Explorer + + +Explorer + + +Explorer + + + +## Additional Resources + +- [GitHub issues page for Wasp](https://github.com/iotaledger/wasp/issues) +- [Firefly](https://firefly.iota.org) + +With this quickstart guide, you should now be able to set up and start exploring the EVM. As you begin to deploy and interact with smart contracts, remember to provide feedback on any issues or improvements you discover to help make our EVM even better. Happy developing! diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/tools.mdx b/docs/build/isc/v1.1/docs/getting-started/tools.mdx similarity index 62% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/tools.mdx rename to docs/build/isc/v1.1/docs/getting-started/tools.mdx index 13709a276d4..4e09788a54e 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/tools.mdx +++ b/docs/build/isc/v1.1/docs/getting-started/tools.mdx @@ -24,6 +24,7 @@ import { Networks } from '@theme/constant'; import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; import { ChainId } from '@theme/ChainId'; import NetworkInfo from '@theme/NetworkInfo'; +import OraclesContractData from '../../../../_partials/_oracles_contract_data.mdx'; # Compatible Tools @@ -34,7 +35,8 @@ directly with an IOTA Smart Contracts chain running EVM as long as you take a co 1. Please make sure you use the correct JSON-RPC endpoint URL in your tooling for your chain. If you're running your own chain, you can find the JSON-RPC endpoint URL in the Wasp dashboard (`[URL]/wasp/dashboard` when using `node-docker-setup`). -2. Please ensure you use the correct `Chain ID` configured while starting the JSON-RPC service. If you did not explicitly define this while starting the service, the default Chain ID will be +2. Please ensure you use the correct `Chain ID` configured while starting the JSON-RPC service. If you did not explicitly define this while starting the service, the default Chain ID will be +for IOTA EVM, for ShimmerEVM or for the EVM Testnet. 3. Fees are handled on the IOTA Smart Contracts chain level, not the EVM level. The chain will reject any requests with a different gas price than specified by the chain. @@ -46,6 +48,66 @@ chain ID after deployment.** ::: +## Network RPCs + + + + + + + + + + + + + + + + + + + + +## IOTA EVM Tools + +The following tools are **only available on IOTA EVM**. + +### Blast API + +The [Blast API](/build/blastAPI) is a decentralized platform that provides reliable and scalable node infrastructure +for accessing blockchain data. You can find the Blast API URLs in the [Network RPCs](#network-rpcs) + +### EVM Toolkit + +You can use the [IOTA EVM Toolkit](https://evm-toolkit.evm.iotaledger.net) to withdraw assets from IOTA EVM to IOTA L1. +It also includes a wrapper IOTA <-> wIOTA. + +### Multicall3 + +If you need to aggregate results from multiple contract reads into a single JSON-RPC request or execute multiple +state-changing calls in a single transaction, you can use the [Multicall3 contract](https://explorer.evm.iota.org/address/0xcA11bde05977b3631167028862bE2a173976CA11?tab=contract). + +## IOTA EVM and ShimmerEVM Tools + +The following tools are available on both IOTA EVM end ShimmerEVM. + +### MultiSig Wallets + +If you require and additional level of security, you can use the [Safe{} Wallet](https://safe.iotaledger.net/) as a +Multisig solution on IOTA EVM. + +### Oracles + +If your project requires [Oracles](/build/oracles/) to provide data from the outside world, you find both Pyth and Supra have integrated IOTA EVM. + + + +### Subgraphs + +[Subgraphs](/build/subgraphs/) provide a streamlined way for developers to access blockchain data relevant to their applications, +significantly enhancing developer efficiency and user experience. IOTA EVM subgraphs available via [Goldsky](https://goldsky.com). + ## MetaMask [MetaMask](https://metamask.io/) is a popular EVM wallet which runs in a browser extension that allows you to @@ -55,16 +117,20 @@ To use your EVM chain with MetaMask, simply open up MetaMask and click on the ne the bottom of this list, you will see the option `Add network`. On the new page you will see a list of popular network with the option `Add a network manually`. For example this would be the configs to add our different [EVM chains](/build/networks-endpoints): - - + + + + + + - + - + @@ -113,9 +179,9 @@ often offered through block explorer APIs. ## Ethers.js/Web3.js -If you input the correct configuration parameters for the JSON-RPC endpoint to talk -to, [Ethers.js](https://docs.ethers.io/) and [Web3.js](https://web3js.readthedocs.io/) are also compatible with EVM -chains on IOTA Smart Contracts. Alternatively, you can let both interact through MetaMask instead so that it uses the +If you input the correct configuration parameters for the JSON-RPC endpoint to talk to, +[Ethers.js](https://docs.ethers.io/) and [Web3.js](https://web3js.readthedocs.io/) are also compatible with EVM chains on IOTA Smart Contracts. +Alternatively, you can let both interact through MetaMask instead so that it uses the network configured in MetaMask. For more information on this, read their documentation. ## Other Tooling diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC20.md b/docs/build/isc/v1.1/docs/how-tos/ERC20.md similarity index 91% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC20.md rename to docs/build/isc/v1.1/docs/how-tos/ERC20.md index 9bbd6929beb..adf0a6ccfa1 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC20.md +++ b/docs/build/isc/v1.1/docs/how-tos/ERC20.md @@ -74,8 +74,9 @@ Once you have deployed your contract, you can add your new custom token to your 1. Open Metamask, and click on the transaction that created the contract. From there, you can simply click on `View on block explorer` to visit the transaction details. Alternatively, you can copy the transaction ID and - visit the [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) - or [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) and use the search bar to find transaction. + visit the [IOTA EVM Explorer](https://explorer.evm.iota.org), + [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) + or [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) and use the search bar to find transaction. !['View on block explorer](/img/evm/how-tos/ERC20/metamask-get-transaction-or-go-to-block-explorer.png) diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC721.md b/docs/build/isc/v1.1/docs/how-tos/ERC721.md similarity index 84% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC721.md rename to docs/build/isc/v1.1/docs/how-tos/ERC721.md index 0b66f129e59..767661dbff2 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/ERC721.md +++ b/docs/build/isc/v1.1/docs/how-tos/ERC721.md @@ -42,7 +42,7 @@ your smart contracts. ## Create the Smart Contract -The following is an example NFT Smart Contract called "ShimmerEVMSampleNFT". +The following is an example NFT Smart Contract called "IotaEVMSampleNFT". ```solidity // SPDX-License-Identifier: MIT @@ -51,11 +51,11 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts@5.0.1/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts@5.0.1/access/Ownable.sol"; -contract ShimmerEVMSampleNFT is ERC721, Ownable { +contract IotaEVMSampleNFT is ERC721, Ownable { uint256 private _nextTokenId; constructor(address initialOwner) - ERC721("ShimmerEVMSampleNFT", "SSNFT") + ERC721("IotaEVMSampleNFT", "SSNFT") Ownable(initialOwner) {} @@ -73,9 +73,9 @@ contract ShimmerEVMSampleNFT is ERC721, Ownable { As you can see above, the contract uses standard methods for the most part. You should pay attention to the following: - `pragma solidity ^0.8.20;`: This line means the contract uses solidity compiler version `0.8.20` or above. -- `contract ShimmerEVMSampleNFT is ERC721, ERC721URIStorage, Ownable`: This line defines the contract's name, and what +- `contract IotaEVMSampleNFT is ERC721, ERC721URIStorage, Ownable`: This line defines the contract's name, and what other contracts it implements. -- `ERC721("ShimmerEVMSampleNFT", "SNFT") {}`: This line defines the token name and symbol. You can name it +- `ERC721("IotaEVMSampleNFT", "SNFT") {}`: This line defines the token name and symbol. You can name it whatever you want. We recommend using the same name for the token and the contract. - `return "https://example.com/nft/";`: You should define the base URI of your NFTs. That means the URL you provide here will be used for all your tokens. Since this contract uses auto-incremental token IDs, your token URI will look @@ -101,7 +101,7 @@ directly. :::note Set the Initial Owner -Before you can deploy this contract, you will need to set the `Initial Owner` address; this can be your own ShimmerEVM address. +Before you can deploy this contract, you will need to set the `Initial Owner` address; this can be your own IOTA EVM address. !["Set the initial owner" img.png](/img/evm/how-tos/ERC721/set-initial-owner.png) @@ -115,13 +115,15 @@ So far, you have [created](#create-the-smart-contract) and deployed the contract To do, you should: 1. Open the contract (listed under `Deployed Contracts`). -2. Insert your target ShimmerEVM in beside the `safeMint` button and then click the button. +2. Insert your target IOTA EVM in beside the `safeMint` button and then click the button. ![Safe mint](/img/evm/how-tos/ERC721/safe-mint.png) + 3. Confirm the transaction on Metamask. ![Confirm in metamask](/img/evm/how-tos/ERC721/confirm-in-metamask.png) -If you visit your address in the [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) or [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) +If you visit your address in the visit the [IOTA EVM Explorer](https://explorer.evm.iota.org), +[ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) or [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) you should see your NFTs listed under `Tokens`. diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/allow.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/allow.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/allow.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/allow.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/get-allowance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/get-allowance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/get-allowance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/get-allowance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/take-allowance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/take-allowance.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/allowance/take-allowance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/allowance/take-allowance.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/get-balance.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/get-balance.md similarity index 98% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/get-balance.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/get-balance.md index aa25f559ac0..8ab06fafb02 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/get-balance.md +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/get-balance.md @@ -67,7 +67,7 @@ contract GetBalance { emit GotNativeTokenBalance(nativeTokens); uint256 nfts = ISC.accounts.getL2NFTAmount(agentID); - emit GotNativeTokenBalance(nfts); + emit GotNFTIDs(nfts); } } ``` diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx similarity index 88% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx index 4fb8baa24da..a479d9bb2c1 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx @@ -18,7 +18,7 @@ import AboutAccounts from '../../../_admonitions/_about-accounts.md'; :::info -ShimmerEVM has 18 decimal places, while Shimmer has 6. This means that any decimals beyond the 6th will be ignored by Shimmer, even though you can see them on ShimmerEVM. Please keep this in mind while sending your tokens to L1. +IOTA EVM and ShimmerEVM have 18 decimal places, while IOTA and Shimmer have 6. This means that any decimals beyond the 6th will be ignored by IOTA and Shimmer, even though you can see them on IOTA EVM and ShimmerEVM. Please keep this in mind while sending your tokens to L1. ::: diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/call-view.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/call-view.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/call-view.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/call-view.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/get-randomness-on-l2.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/get-randomness-on-l2.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/get-randomness-on-l2.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/get-randomness-on-l2.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/introduction.md diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx new file mode 100644 index 00000000000..3795884916c --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx @@ -0,0 +1,55 @@ +--- +description: How to get NFT metadata from a L1 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- +import GetNftMetadata from '../../../_partials/how-tos/token/_get-nft-metadata.md'; +import ERC721Admonition from '../../../_admonitions/_ERC721.md'; +import IRC27Admonition from '../../../_admonitions/_IRC27.md'; + +# Get IRC27 NFT Metadata + + + +This guide explains how to use the [`getIRC27NFTData`](../../../reference/magic-contract/ISCSandbox.md#getirc27nftdata) function within a smart contract to fetch information about a specific IRC27 NFT on the IOTA Network. + + + +## Understanding the `getIRC27NFTData` Function + +The [`getIRC27NFTData`](../../../reference/magic-contract/ISCSandbox.md#getirc27nftdata) function retrieves metadata for an IRC27 NFT based on its identifier. IRC27 is a series of standards to support interoperable and universal NFT systems throughout the IOTA ecosystem. + +## How To Use `getIRC27NFTData` + +Create a function called `fetchIRC27NFTData` in your contract that calls `getIRC27NFTData` and processes its return value. `getIRC27NFTData` returns a struct of type [`IRC27NFTMetadata`](../../../reference/magic-contract/ISCTypes.md#irc27nftmetadata) which contains properties like the NFT name, uri and more. + + + +```solidity +function fetchIRC27NFTData(uint256 tokenId) public view returns (IRC27NFT memory irc27NftData) { + irc27NftData = ISC.sandbox.getIRC27NFTData(ISCTypes.asNFTID(tokenId)); + return irc27NftData; +} +``` + +## Full Example Contract + +Combining all the above steps, here’s a complete example: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; +import "@iota/iscmagic/ISCTypes.sol"; + +contract IRCNFTMetadata { + function fetchIRC27NFTData(uint256 tokenId) public view returns (IRC27NFT memory irc27NftData) { + irc27NftData = ISC.sandbox.getIRC27NFTData(ISCTypes.asNFTID(tokenId)); + return irc27NftData; + } +} +``` \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/mint-nft.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/mint-nft.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/mint-nft.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/mint-nft.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/use-as-erc721.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/use-as-erc721.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/nft/use-as-erc721.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/nft/use-as-erc721.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md similarity index 94% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md index f9636742db8..17ba120d40c 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/create-foundry.md +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-foundry.md @@ -7,8 +7,12 @@ tags: - how-to --- import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; # Create a Foundry + + + ## About Foundries The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md new file mode 100644 index 00000000000..06baa4615d1 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/create-native-token.md @@ -0,0 +1,91 @@ +--- +description: How to Create a Native Token Foundary. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint + - register +--- + +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Create a Native Token + +This guide will show you how you can efficiently mint new tokens and register them for use as ERC20 tokens with the [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) function in one seamless operation. It will create a foundry on L1 and register it as an ERC20 on L2. This method ensures that only the foundry owner can mint tokens, maintaining security and control over the token creation process. + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry lets you specify your native token's maximum supply **once** and change the circulating supply. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the [`NativeTokenScheme`](../../../reference/magic-contract/ISCTypes.md#nativetokenscheme) by specifying the `maximumSupply`. + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply +}); +``` + +### 3. Mint and Register Native Token + +Minting native tokens and registering them as ERC20 tokens using [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) method + +```solidity +uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance +); +``` + +## Full Example Code + +```solidity +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract MyToken { + event MintedToken(uint32 foundrySN); + + constructor( + string memory _tokenName, + string memory _tokenSymbol, + uint8 _tokenDecimals, + uint256 _maximumSupply, + uint64 _storageDeposit + ) payable { + require(msg.value == _storageDeposit * (10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply + }); + + uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance + ); + emit MintedToken(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/erc20-native-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/erc20-native-token.md new file mode 100644 index 00000000000..dfbe3d280e5 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/erc20-native-token.md @@ -0,0 +1,55 @@ +--- +description: How to use the custom functionality of ERC20NativeToken +image: /img/logo/WASP_logo_dark.png +tags: + - native token + - erc20 + - EVM + - how-to +--- + +# Custom ERC20 Functions + +Once you [registered your native token as ERC20](./erc20-native-token.md) you can use it like any other ERC20 token, with functions like +`transfer`, `balanceOf`, etc. But, as the ERC20 token maps the native token on L2, there are some additional ISC features +you can take advantage of. + +## Example Code + +### Get Your `nativeTokenID` + +You can use the `erc20NativeTokensAddress` function and the Foundry serial number to get the contract address: + +```solidity +ERC20NativeTokens token = ERC20NativeTokens( + ISC.sandbox.erc20NativeTokensAddress(_foundrySN) +); +``` + +* `nativeTokenID` will give you the native token ID of the ERC20 token: + +```solidity +NativeTokenID memory id =token.nativeTokenID(); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract MyNativeToken { + + function nativeTokenID(uint32 _foundrySN) public view returns (bytes memory) { + ERC20NativeTokens token = ERC20NativeTokens( + ISC.sandbox.erc20NativeTokensAddress(_foundrySN) + ); + NativeTokenID memory id = token.nativeTokenID(); + return id.data; + } +} + +``` diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/introduction.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/core-contracts/token/introduction.md diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md new file mode 100644 index 00000000000..551452802db --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/mint-token.md @@ -0,0 +1,53 @@ +--- +description: How to mint native token on an L1 foundry. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Mint Native Tokens + +To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract where you also [created the native token](./create-native-token.md). + +## Example Code + + + +### 2. Mint the Native Token + +Mint the native token specifying the foundry serial number, the amount to mint and the allowance. + +```solidity +ISC.accounts.mintNativeTokens(_foundrySN, _amount, allowance); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract NativeTokenMinter { + event MintedNativeTokens(uint32 foundrySN, uint amount); + + function mintNativeTokens(uint32 _foundrySN, uint _amount, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit * (10 ** 12), "Please send exact funds to pay for storage deposit"); + + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + ISC.accounts.mintNativeTokens(_foundrySN, _amount, allowance); + + emit MintedNativeTokens(_foundrySN, _amount); + } +} + +``` diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md new file mode 100644 index 00000000000..6e3af8a789f --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/register-token.md @@ -0,0 +1,74 @@ +--- +description: How to register a native token as ERC20 +image: /img/logo/WASP_logo_dark.png +tags: + - ERC20 + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; + +# Register Tokens + + + +To properly use your native tokens, you should register them as ERC20 using the `registerERC20NativeToken` function from the ISC magic contract. + +## Example Code + + + + +### 2. Register the Native Tokens + +Register the native tokens specifying: +* the foundry serial number +* a name +* a symbol +* it's decimals +* the allowance. +```solidity +ISC.sandbox.registerERC20NativeToken(_foundrySN, _name, _symbol, _decimals, allowance); +``` + +### 3. Get the Contract's Address + +Get the ERC20 contract address with `erc20NativeTokensAddress`: + +```solidity +address erc20address = ISC.sandbox.erc20NativeTokensAddress(_foundrySN); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract ERC20NativeTokenRegistry { + + event ERC20Address(address erc20address); + + function registerERC20NativeToken( + uint32 _foundrySN, + string calldata _name, + string calldata _symbol, + uint8 _decimals, + uint64 _storageDeposit + ) public payable { + require(msg.value == _storageDeposit * (10 ** 12), "Please send exact funds to pay for storage deposit"); + + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + ISC.sandbox.registerERC20NativeToken(_foundrySN, _name, _symbol, _decimals, allowance); + + address erc20address = ISC.sandbox.erc20NativeTokensAddress(_foundrySN); + emit ERC20Address(erc20address); + } +} +``` diff --git a/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/send-token-across-chains.mdx b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/send-token-across-chains.mdx new file mode 100644 index 00000000000..9af496752e6 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/core-contracts/token/send-token-across-chains.mdx @@ -0,0 +1,118 @@ +--- +description: How to Send Native Tokens Across Chains. +image: /img/logo/WASP_logo_dark.png +tags: + - EVM + - how-to + - native tokens + - cross-chain +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import DemoTokenSetup from '../../../_admonitions/_token-demo-setup.md'; +import CreateNativeToken from '../../../_admonitions/_create-native-token.md'; + +# Send Native Token Across Chains + +## Introduction + +Cross-chain token transfers are crucial in the evolving decentralized finance (DeFi) landscape. In this guide, you'll learn how to send L1 native Tokens from L1 to an L2 EVM account on a destination chain using the `sendCrossChain` function of the [`NativeTokenController.sol`](https://github.com/iotaledger/isc-cross-chain/blob/master/contracts/NativeTokenController.sol) contract. + + + +## Understanding the `sendCrossChain` Function + +First, let’s take a look at the `sendCrossChain` function in the `NativeTokenController.sol` file: + +```solidity +function sendCrossChain( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit +) external { + // Function implementation +} +``` +This function facilitates the transfer of native tokens from a Layer 1 (L1) address to a specified Layer 2 (L2) EVM account. It requires the L1 address of the destination chain (`chainAddress`), the recipient address on the destination chain (`_destination`), the destination chain's ID (`_chainID`), the amount of native tokens to be sent (`_amount`), and the amount of base tokens to cover the storage deposit (`_storageDeposit`). +The `sendCrossChain` wrapper function invokes the `ISC.sandbox.send` function, which manages the actual cross-chain message transmission. + +## Setting Up the Development Environment + + + +## Using the `sendCrossChain` Function + +To send native tokens across chains, you need to provide the following transaction details to the `sendCrossChain` function: + +* `ChainAddress` - The L1 address of the destination chain. +* `Destination` - The address on the destination chain that will receive the tokens. +* `chainID` - The ID of the destination chain. +* `amount` - The amount of native tokens to sent. +* `storageDeposit` - The base tokens to cover storage deposit. + +## Example Code + + +### 2. Send Token to Another Chain + +Let's define a function named `sendCrossChainMessage` in our contract, which will interact with the `sendCrossChain` function in the `NativeTokenController` contract. + +```solidity +function sendCrossChainMessage( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit +) external { + // Ensure the sender has enough tokens (assuming a balanceOf function exists) + uint256 senderBalance = IERC20(tokenAddress).balanceOf(msg.sender); + require(senderBalance >= amount, "Insufficient token balance"); + + // Call the sendCrossChain function from NativeTokenController + nativeTokenController.sendCrossChain(destinationChain, destinationAddress, amount, chainID, storageDeposit); +} +``` + +## Full Example Code + +```solidity + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./NativeTokenController.sol"; // Adjust the path as necessary +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract CrossChainMessenger { + + NativeTokenController public nativeTokenController; + + constructor(address _nativeTokenControllerAddress) { + nativeTokenController = NativeTokenController(_nativeTokenControllerAddress); +} + +function sendCrossChainMessage( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit, + tokenAddress +) external { + // Ensure the sender has enough tokens (assuming a balanceOf function exists) + uint256 senderBalance = IERC20(tokenAddress).balanceOf(msg.sender); + require(senderBalance >= amount, "Insufficient token balance"); + + // Call the sendCrossChain function from NativeTokenController + nativeTokenController.sendCrossChain(destinationChain, destinationAddress, amount, chainID, storageDeposit); + } +} +``` +## Conclusion + +By following this guide, you have learned how to set up your development environment and use the `sendCrossChain` function in the [`NativeTokenController.sol`](https://github.com/iotaledger/isc-cross-chain/blob/master/contracts/NativeTokenController.sol) contract to send native tokens across chains. You can now interact with the `sendCrossChain` function within your own smart contracts to facilitate cross-chain token transfers. + +By leveraging cross-chain capabilities, you can create more interoperable and versatile decentralized applications, paving the way for a more connected blockchain ecosystem. \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/create-a-basic-contract.md b/docs/build/isc/v1.1/docs/how-tos/create-a-basic-contract.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/create-a-basic-contract.md rename to docs/build/isc/v1.1/docs/how-tos/create-a-basic-contract.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/deploy-a-smart-contract.mdx b/docs/build/isc/v1.1/docs/how-tos/deploy-a-smart-contract.mdx similarity index 81% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/deploy-a-smart-contract.mdx rename to docs/build/isc/v1.1/docs/how-tos/deploy-a-smart-contract.mdx index 9fbf20161e0..0a1860715ec 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/deploy-a-smart-contract.mdx +++ b/docs/build/isc/v1.1/docs/how-tos/deploy-a-smart-contract.mdx @@ -2,11 +2,12 @@ tags: - Smart Contract Deployment - Shimmer EVM +- IOTA EVM - Remix IDE - Hardhat -- Shimmer EVM Testnet +- EVM Testnet image: /img/logo/WASP_logo_dark.png -description: 'Learn how to deploy smart contracts to Shimmer EVM and Shimmer EVM Testnet using popular tools like Remix and Hardhat.' +description: 'Learn how to deploy smart contracts to IOTA EVM, Shimmer EVM and EVM Testnet using popular tools like Remix and Hardhat.' --- import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; import HardhatConfig from '../_partials/_hardhat_config.md'; @@ -27,7 +28,7 @@ the [How to Create a Basic Solidity Contract Guide](create-a-basic-contract.md). ::: - + Deploying a Solidity smart contract using Remix is a straightforward process that doesn't require any installation or @@ -109,10 +110,10 @@ project. Here's a step-by-step guide: ``` 5. Create a Hardhat Project by running the following command: ```bash - npx hardhat + npx hardhat init ``` - Select "Create a basic sample project" when prompted and answer the setup questions (you can just press enter to + Select `Create a JavaScript project` (or whatever applies to your project) when prompted and answer the setup questions (you can press enter to accept defaults). ### 2. Add Your Contract @@ -130,9 +131,7 @@ project. Here's a step-by-step guide: const Counter = await ethers.getContractFactory("Counter"); const counter = await Counter.deploy(); - await counter.deployed(); - - console.log("Counter deployed to:", counter.address); + console.log("Counter deployed to:", await counter.getAddress()); } main() @@ -149,6 +148,19 @@ project. Here's a step-by-step guide: +:::info Export the Metamask Private Key + +1. Click on the Metamask logo in the upper right corner. +2. Select the account you want to export. +3. On the account page, click the menu (three dots) in the upper right corner, then click the "Account Details" button. +4. Click on "Export Private Key". +5. Enter your wallet password to access your private key and click `Confirm` to continue. +6. Your private key will now be displayed. Click to copy it and save it in a safe place. + +You can find more information in the [official Metamask Documentation](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). + +::: + :::caution Currently, there is no validation service available for EVM/Solidity smart contracts on IOTA Smart Contracts, which is @@ -165,7 +177,7 @@ often offered through block explorer APIs. 3. If you have no compilation errors, you can deploy your contract by running the following command: ```bash - npx hardhat run scripts/deploy.js --network shimmerevm-testnet + npx hardhat run scripts/deploy.js --network evm-testnet ``` **Expected output**: @@ -176,7 +188,7 @@ often offered through block explorer APIs. ***** `0x123456789ABCDEFGHIJK123456789ABCDEFGHIJK` is the contract unlock address. 4. You can verify your contract by visiting - the [ShimmerEVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/), + the [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/), and searching for the address from the previous step. If you access the `Contract` tab, you should be able to see your code and interact with your contract. diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/introduction.md b/docs/build/isc/v1.1/docs/how-tos/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/introduction.md rename to docs/build/isc/v1.1/docs/how-tos/introduction.md diff --git a/docs/build/isc/v1.1/docs/how-tos/send-ERC20-across-chains.md b/docs/build/isc/v1.1/docs/how-tos/send-ERC20-across-chains.md new file mode 100644 index 00000000000..af8cc67fa54 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/send-ERC20-across-chains.md @@ -0,0 +1,297 @@ +# Send ERC20 Tokens Across Chains + +## Introduction + +[LayerZero OFT V2](https://docs.layerzero.network/v2) enables cross-chain transfers of existing ERC20 tokens, such as wSMR and wIOTA (wrapped versions of the native gas tokens SMR and IOTA on ShimmerEVM and IOTA EVM respectively). For testing purposes, Sepolia is chosen as the source chain, while the BNB Testnet is chosen as the destination chain. + +:::info Community Libs + +You can clone the Utilities for LayerZero OFT V2 from [IOTA Community GitHub Repository](https://github.com/iota-community/layerzero-oft-v2-utils). + +::: + +### Why Would a User Need to Send ERC20 Tokens Across Chains? + +Sending ERC20 tokens across chains allows users to leverage different blockchain networks' strengths and unique features, optimize costs, and manage risks more effectively. This flexibility is crucial as the blockchain ecosystem continues to grow and diversify. + +#### Send Existing ERC20 Tokens Across Chains + +You need both the [OFT Adapter](https://docs.layerzero.network/v2/developers/evm/oft/adapter) and OFT contracts to enable existing ERC20 tokens for cross-chain sending, + +#### Create New Cross-chain Fungible Tokens + +If you are about to launch a new ERC20 token, you can use the [OFT standard](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) to enable cross-chain sending without the OFT Adapter. + +## How To Use IOTA's Utilities for LayerZero OFT V2 + +The [Utilities for LayerZero OFT V2](https://github.com/iota-community/layerzero-oft-v2-utils) facilitate cross-chain sending of ERC20 tokens between a source chain (e.g., Sepolia or ShimmerEVM Testnet) and a destination chain (e.g., BNB Testnet or IOTA EVM Testnet). + +:::tip Further Information + +You can learn more about the available options in the [Layer Zero Documentation](https://docs.layerzero.network/v2/developers/evm/gas-settings/options#option-types.). + +::: + +### Send Tokens From One Source Chain to Another Destination Chain (and Vice Versa) + +To send existing ERC20 tokens, you will need both the OFT Adapter contract on the source chain and the OFT contract on the destination chain. You should then use the following procedure: + +#### 1. Approve the tokens + +The sender must approve their ERC20 tokens for the OFT Adapter contract. + +```typescript +const approveTx = await erc20TokenContract.approve(oftAdapterContractAddress, amountInWei); +``` + +#### 2. Estimate the fee + +The sender calls the function `quoteSend()` of the OFT Adapter contract to estimate the cross-chain fee to be paid in native tokens on the source chain. + +```typescript + const sendParam = [ + lzEndpointIdOnDestChain, + receiverAddressInBytes32, + amountInWei, + amountInWei, + options, // additional options + "0x", // composed message for the send() operation + "0x", // OFT command to be executed, unused in default OFT implementations + ]; + + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L127C60-L127C73 + // false is set for _payInLzToken Flag indicating whether the caller is paying in the LZ token + const [nativeFee] = await myOFTAdapterContract.quoteSend(sendParam as any, false); +``` + +#### 3. Send the tokens + +The sender calls the function `send()` of the OFT Adapter contract to transfer tokens from the source chain to the destination chain. + +```typescript + const sendTx = await myOFTAdapterContract.send( + sendParam as any, + [nativeFee, 0] as any, // set 0 for lzTokenFee + sender.address, // refund address + { + value: nativeFee, + }, + ); + const sendTxReceipt = await sendTx.wait(); + console.log("sendOFT - send tx on source chain:", sendTxReceipt?.hash); +``` + +#### 4. (Optional) Wait for Finalization + +The sender can wait for transaction finalization on the destination chain using the library [@layerzerolabs/scan-client](https://www.npmjs.com/package/@layerzerolabs/scan-client#example-usage). +```typescript + const deliveredMsg = await waitForMessageReceived( + Number(lzEndpointIdOnDestChain), + sendTxReceipt?.hash as string, + ); + console.log("sendOFT - received tx on destination chain:", deliveredMsg?.dstTxHash); +``` + +### Send the OFT-wrapped Tokens Back + +To send back the OFT-wrapped tokens on the destination chain to the source chain, the procedure is similar, except that the approval step is not needed: + +#### 1. Estimate the fee + +The sender calls the function `quoteSend()` of the OFT contract to estimate the cross-chain fee to be paid in native tokens on the sender chain. + +```typescript + // Set the send param + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L10 + const sendParam = [ + lzEndpointIdOnSrcChain, // Sepolia + receiverAddressInBytes32, + amountInWei, + amountInWei, + options, // additional options + "0x", // composed message for the send() operation + "0x", // OFT command to be executed, unused in default OFT implementations + ]; + + // Step 1: call the func quoteSend() to estimate cross-chain fee to be paid in native on the source chain + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L127C60-L127C73 + // false is set for _payInLzToken Flag indicating whether the caller is paying in the LZ token + const [nativeFee] = await myOFTContract.quoteSend(sendParam as any, false); + console.log("sendOFTBack - estimated nativeFee:", ethers.formatEther(nativeFee)); + ``` + +#### 2. Send the tokens + +The sender calls the function `send()` of the OFT contract to transfer tokens from the destination chain back to the source chain. + +```typescript +const sendTx = await myOFTContract.send( + sendParam as any, + [nativeFee, 0] as any, // set 0 for lzTokenFee + sender.address, // refund address + { + value: nativeFee, + }, + ); + const sendTxReceipt = await sendTx.wait(); + console.log("sendOFTBack - send tx on source chain:", sendTxReceipt?.hash); + ``` + +#### 3. (Optional) Wait for Finalization + +The sender can wait for transaction finalization on the destination chain using the library `@layerzerolabs/scan-client`. +```typescript + const deliveredMsg = await waitForMessageReceived( + Number(lzEndpointIdOnDestChain), + sendTxReceipt?.hash as string, + ); + console.log("sendOFTBack - received tx on destination chain:", deliveredMsg?.dstTxHash); + ``` + +## Sample Solidity Code for OFT Adapter and OFT Contracts in the `contracts-standard` Folder + +The [contracts-standard](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-standard) contains scripts to: + +- [Deploy the OFT Adapter and OFT contracts](#deploy-the-oft-adapter-contract-on-the-source-chain). +- [Set your trusted peers](#optional-set-the-trusted-peers). +- Set enforced options. +- [Send tokens from the source chain to the destination chain](#send-the-origin-tokens-from-the-source-chain-to-the-destination-chain), +and [vice versa](#send-oft-wrapped-tokens-back-from-the-destination-chain-to-the-origin-chain). + +### Install the Library + +After you have cloned the [IOTA Community Utilities for LayerZero OFT V2 repository](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main), you should run the following command to install: + +``` +yarn +``` + +### Compile the Contracts + +If you want to use the standard implementation for ERC20, copy the [`contracts-standard`](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-standard) folder to `contracts`. If you want to use a custom implementation, copy the [`contracts-wiota`](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-wiota) to `contracts`. Then, run the following command to compile the contracts: + +```bash +yarn compile +``` + +### Set Your Configuration + +You should copy the template [`.env.example`](https://github.com/iota-community/layerzero-oft-v2-utils/blob/main/.env.example) file to a file called `.env`, and edit any of the configuration options you see fit. + +```bash +cp .env.example .env +``` + +### Deploy the Contracts + +#### Deploy the OFT Adapter Contract On the Source Chain + +The OFT Adapter facilitates the expansion of an existing token to any supported blockchain as a native token, maintaining a unified global supply and inheriting all features of the OFT Standard. This intermediary contract manages the sending and receiving of pre-deployed tokens. + +For instance, when an ERC20 token is transferred from the source chain (Chain A), it gets locked in the OFT Adapter. Consequently, a corresponding token is minted on the destination chain (Chain B) through the paired OFT Contract. + +```bash +yarn deploy-oft-adapter-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_oft_adapter.ts --network sepolia +Deployed MyOFTAdapter contract address: 0x4daa81978576cB91a2e1919960e90e46c2a6D586 +Done in 6.67s. +``` + +#### Deploy OFT on the Destination Chain + +You can use the following command to deploy OFT on destination chain (e.g. BNB Testnet): + +```bash +yarn deploy-oft-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_oft.ts --network bnbTestnet +Deployed MyOFT contract address: 0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1 +Done in 6.68s. +``` + +### (optional) Set the Trusted Peers + +#### On OFTAdapter + +You can set the trusted peer in the source chain's OFT Adapter (e.g., Sepolia) using the following command: + +```bash +yarn set-peer-oft-adapter-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/set_peer_oft_adapter.ts --network sepolia +setPeerMyOFTAdapter - oftAdapterContractAddress:0x4daa81978576cB91a2e1919960e90e46c2a6D586, lzEndpointIdOnDestChain:40102, oftContractAddress:0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1 +MyOFTAdapter - setPeer tx: 0xc17e7a54d96325768b6427ce893d9b6b7ed04bd920089b63a3f96c005073e9c2 +Done in 14.10s. +``` + +#### On OFT + +You can add a trusted peer in the destination chain (e.g. BNB Testnet) using the following command: + +```bash +yarn set-peer-oft-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/set_peer_oft.ts --network bnbTestnet +setPeerMyOFT - oftContractAddress:0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1, lzEndpointIdOnSrcChain:40161, oftAdapterContractAddress:0x4daa81978576cB91a2e1919960e90e46c2a6D586 +MyOFT - setPeer tx: 0xb0012378ee14c9df5c9f86980dd9c96fc8aedb3c19d92c1d91a4259f3981ac35 +Done in 4.66s. +``` + +### Send the Origin Tokens from the Source Chain to the Destination Chain + + +You can use the following command to send tokens from the source chain to the destination chain: + +```bash +yarn send-oft-from-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/send_oft.ts --network sepolia +sendOFT - oftAdapterContractAddress:0x5D7Cbc05fc6df2832c40023f1Eb2755628C51D81, oftContractAddress:0x075e512E25b45a3EaF8b432220F0Ca8D4e3c6a58, lzEndpointIdOnSrcChain:40161, lzEndpointIdOnDestChain:40102, gasDropInWeiOnDestChain:1000000000000000, executorLzReceiveOptionMaxGas:200000, receivingAccountAddress:0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, sender: 0x57a4bd139fb673d364a6f12df9177a3f686625f3, amount:2 +sendOFT - approve tx: 0x8fa692edb47b1ad9d21f60b0fa30993e5cd3abd78c3c56fb4f38db5f9b8ac369 +sendOFT - estimated nativeFee: 0.000734209489447653 +sendOFT - send tx on source chain: 0xeb3e44310a09ae2ab2f0d6d6d3fdfd7c490f8ac536bb20a5e16999b23232ef67 +Wait for cross-chain tx finalization by LayerZero ... +sendOFT - received tx on destination chain: 0xc2e5a4be8ae67718e817ff585a32765e393835880068f408fd7724667a25a46c +``` + +### Send Oft-Wrapped Tokens Back From the Destination Chain to the Origin Chain + +You can use the following command to send the OFT-wrapped tokens back to the origin chain: + + +```bash +yarn send-oft-back-from-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/send_oft_back.ts --network bnbTestnet +sendOFTBack - oftAdapterContractAddress:0x5D7Cbc05fc6df2832c40023f1Eb2755628C51D81, oftContractAddress:0x075e512E25b45a3EaF8b432220F0Ca8D4e3c6a58, lzEndpointIdOnSrcChain:40161, lzEndpointIdOnDestChain:40102, gasDropInWeiOnDestChain:1000000000000000, executorLzReceiveOptionMaxGas:200000, receivingAccountAddress:0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, sender: 0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, amount:2 +sendOFTBack - estimated nativeFee: 0.054815809525020364 +sendOFTBack - send tx on source chain: 0x41bcf78b310dc1bbf9b4005f7412d995011c7815ad5af9cc26b37370e75bbfeb +Wait for cross-chain tx finalization by LayerZero ... +sendOFTBack - received tx on destination chain: 0xc1031694e92512a0189885ad6419e33196a65b8ae56baa9d555be8686d6d42fe +``` + diff --git a/docs/build/isc/v1.1/docs/how-tos/send-NFTs-across-chains.md b/docs/build/isc/v1.1/docs/how-tos/send-NFTs-across-chains.md new file mode 100644 index 00000000000..f76c757dfa9 --- /dev/null +++ b/docs/build/isc/v1.1/docs/how-tos/send-NFTs-across-chains.md @@ -0,0 +1,359 @@ +# Send NFTs Across Chains + +## Introduction + +[LayerZero ONFT V1FV](https://docs.layerzero.network/V1) enables cross-chain transfers of existing ERC721 tokens. For +testing purposes, the ShimmerEVM Testnet is chosen as the source chain, while the BNB Testnet is chosen as the destination +chain. + +:::info Community Libs + +You can clone the Utilities for LayerZero ONFT V1 +from [IOTA Community GitHub Repository](https://github.com/iota-community/layerzero-onft-v1-utils). + +::: + +## Why Would a User Need to Send ERC721 Tokens Across Chains? + +By facilitating the movement of ERC721 tokens across chains, users gain flexibility and can optimize their NFT usage +according to their specific needs, preferences, and circumstances. + +### Enable the Existing ERC721 Tokens for Cross-Chain Sending + +To enable the existing ERC721 tokens for cross-chain sending, you will need the `ProxyONFT` contract on the source +chain, +and the ONFT contract on the destination chain) are needed. + +The origin NFT token will be locked in the `ProxyONFT` contract so that the ONFT-wrapped tokens will be minted on the +destination chain. If the NFT token already exists on the destination chain (i.e., when the ONFT-wrapped token on +the destination chain is sent back to the source chain), no new token minting will happen. Instead, the NFT tokens will be +transferred from the ONFT contract to the user's wallet address. Relevant code + +### Enable Cross-Chain Sending for Unloached ERC721 NFTs + +If you are launching a new ERC721 token, you can use the ONFT standard to enable cross-chain sending without the need of +`ProxyONFT`. As with existing tokens, the NFT will be locked on the source chain and minted or transferred on the destination chain. + +:::info Contract Documentation + +- [ProxyONFT721](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/721#proxyonft721sol) +- [ProxyONFT1155](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/1155#proxyonft1155sol) +- [ONFT721](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/721#onft721sol) +- [ONFT1155](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/1155#onft1155sol) + +::: + +## Scripts + +### Deploy the ProxyONFT and ONFT Contracts + +#### For ERC721 + +- MyProxyONFT721.sol: + - CTOR: + - [`minGasToTransferAndStore`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/ONFT721Core.sol#L169): + The minimum gas needed to transfer and store your NFT is typically 100k for ERC721. This value would vary + depending on your contract complexity; it's recommended to test. If this value is set too low, the destination + tx will fail, and a manual retry is needed. + - `lzEndpoint`: LayerZero Endpoint on the source chain. + - `proxyToken`: deployed contract address of the NFT tokens on the source chain. + +- MyONFT721.sol: + - CTOR: + - `name`: name of the ONFT-wrapped tokens on the destination chain + - `symbol`: symbol of the ONFT-wrapped tokens on the destination chain + - [`minGasToTransferAndStore`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/ONFT721Core.sol#L169): + The minimum gas needed to transfer and store your NFT typically 100k for ERC721. This value would vary + depending on your contract complexity; it's recommended to test. If this value is set too low, the destination + tx will fail, and a manual retry is needed. + - `lzEndpoint`: - lzEndpoint: LayerZero Endpoint on the destination chain + +### Set the Trusted Remote + +For **existing ERC721 tokens**, the `ProxyONFT` and `ONFT` contract instances must be paired. + +For the **upcoming ERC721 tokens** that want to leverage the `ONFT` standard, the `ONFT` contract instance on the source chain +needs to be paired with another `ONFT` contract instance on the destination chain. + +You can set this using the [`setTrustedRemote`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L138) method. + +### Set the `minGasLimit` + +Both the `ProxyONFT` and the `ONFT` contract instanceS need to be set for minimum gas on destination([`minGasLimit`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L85C37-L85C48)). + +You can set his using the [`setMinDstGas`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L159) method. + +:::info + +It is required that `minDstGas` <= `providedGasLimit`, which is to be set via `adapterParams` upon cross-chain sending on +the source chain. + +::: + +### Set the Batch Size Limit + +Both the `ProxyONFT` and the `ONFT` contract instances need to set a limit for the batch size on the source +chain to limit the number of tokens to be sent to another chain when using the +[`sendBatchFrom`](https://github.com/LayerZero-Labs/solidity-examples/blob/c04e7d211b1b610f84761df943e6a38b0a53d304/contracts/token/onft721/ONFT721Core.sol#L67) +method. + +You can set this using the [`setDstChainIdToBatchLimit`](https://github.com/LayerZero-Labs/solidity-examples/blob/c04e7d211b1b610f84761df943e6a38b0a53d304/contracts/token/onft721/ONFT721Core.sol#L194) method; the default value is 1. + +## How To Send Tokens From a Source Chain to a Destination Chain (and Vice-Versa) + +### Required Contracts + +#### From the Source Chain to the Destination Chain + +For the existing ERC721 tokens, you will need the `ProxyONFT` contract on the source chain and the `ONFT` contract on +the destination chain. The procedure is as follows: + +1. The sender approves his ERC721 tokens for the `ProxyONFT` contract. +2. The sender calls the function [`estimateSendFee()`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/interfaces/IONFT721Core.sol#L70) of the ProxyONFT contract to estimate cross-chain fee to be paid in + native on the source chain. +3. The sender calls the function [`sendFrom()`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/interfaces/IONFT721Core.sol#L36) of the ProxyONFT contract to transfer tokens on source chain to destination + chain. +4. (Optional) Wait for the transaction finalization on the destination chain by using the + [@layerzerolabs/scan-client](https://www.npmjs.com/package/@layerzerolabs/scan-client#example-usage) library. + +#### From the Destination Chain Back to the Source Chain + +To send back the ONFT-wrapped tokens on the destination chain to the source chain, the procedure is similar as the +approve step is also required, but the operations will happen on the `ONFT` contract. + +#### References and Tools + +##### `AdapterParams` + +- You can use the [LayerZero Repository](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/libs/LzLib.sol#L44) as a reference to set gas drop on the destination in `adapterParams`. + - The provided gas drop must be `<=` the config one. Otherwise, you will get [`dstNativeAmt` too large](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/mocks/LZEndpointMock.sol#L413) error. +- You can use the [LayerZero Repository](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/libs/LzLib.sol#L34) as a refernce to set default `adapterParams` without needing a gas drop. + +##### LayerZero + +- [LayerZero Endpoint V1 (Testnet)](https://docs.layerzero.network/v1/developers/evm/technical-reference/testnet/testnet-addresses) +- [layerZero Endpoint V1 (Mainnet)](https://docs.layerzero.network/v1/developers/evm/technical-reference/mainnet/mainnet-addresses) +- [LayerZero explorer](https://Testnet.layerzeroscan.com/) + +### Install and compile the Library + +After you have cloned +the [IOTA Community Utilities for LayerZero ONFT V1 repository](https://github.com/iota-community/layerzero-onft-v1-utils), +you should run the following command to install: + +```bash +yarn +``` +then compile the contracts: + +```bash +yarn compile +``` + +### Set Your Configuration + +You should copy the +template [`.env.example`](https://github.com/iota-community/layerzero-oft-V1-utils/blob/main/.env.example) file to a +file called `.env`, and edit any of the configuration options you see fit. + +```bash +cp .env.example .env +``` + +### Deploy the Contracts + +#### Deploy a mock ERC721 + +```bash +yarn deploy-ERC721-mock-smr-Testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_ERC721.ts --network shimmerEvmTestnet +Deployed ERC721Mock contract address:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +Done in 4.49s. +``` + +#### Deploy `ProxyONFT721` on the source chain + +You can use the following command to deploy ProxyONFT721 on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn deploy-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_proxy_onft721.ts --network shimmerEvmTestnet +Deployed MyProxyONFT721 contract address:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2 +Done in 4.50s. +``` + +#### Deploy `ProxyONFT721` on the destination chain + +You can use the following command to deploy ProxyONFT721 on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-min-dest-gas-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_min_destination_gas.ts --network bnbTestnet +setMinDstGas - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xce044ded17daa77a8aefc3d39b99c5381216eb4057ddce6253affde6cda2091c +setMinDstGas (packetType 1) tx: 0x3a26ae40ac058099bfd8b85910009a5e5e8b03f16a5f032b572827d48be8f2b0 +Done in 9.34s. +``` + +### Set the Minimum Destination Gas + +#### On the source chain + +You can use the following command to set the minimum destination gas on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-min-dest-gas-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_min_destination_gas.ts --network shimmerEvmTestnet +setMinDstGas - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xcab06e9989448153a4bbc1bb166fc2d33467f3311d1851bf2ff719d982daa613 +setMinDstGas (packetType 1) tx: 0xe78fd3f0bf668fafbc423decd2cf14a27d74543af3ac9daf031f0b278c22ea78 +Done in 6.07s. +``` + +#### On the destination chain + +You can use the following command to set the minimum destination gas on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-min-dest-gas-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_min_destination_gas.ts --network bnbTestnet +setMinDstGas - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xce044ded17daa77a8aefc3d39b99c5381216eb4057ddce6253affde6cda2091c +setMinDstGas (packetType 1) tx: 0x3a26ae40ac058099bfd8b85910009a5e5e8b03f16a5f032b572827d48be8f2b0 +Done in 9.34s. +``` + +### Set the batch size limit + +#### On the source chain + +You can use the following command to set batch size limits on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-batch-size-limit-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_batch_size_limit.ts --network shimmerEvmTestnet +setBatchSizeLimit - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102, batchSizeLimit:1 +setBatchSizeLimit tx: 0x70c23b3d3d5e94ef82e50944f7eba93fa1fe8db3a5487ac371015e7a14482e75 +Done in 4.28s. +``` + +#### On the destination chain + +You can use the following command to set batch size limits on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-batch-size-limit-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_batch_size_limit.ts --network bnbTestnet +setBatchSizeLimit - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, batchSizeLimit:1 +setBatchSizeLimit tx: 0x8cb44c2195ac93da552c646677e6585c95ab172df19463637541933ec70dc9b8 +Done in 4.26s. +``` + +### Set the Trusted Remote + +#### On the source chain + +You can use the following command to set a trusted remote on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-remote-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_trusted_remote.ts --network shimmerEvmTestnet +setTrustedRemote - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102 +setTrustedRemote tx: 0xce52c0f25090ef7c1668ef04ff2f6098551c9f56b3ce881d17181bf106457016 +Done in 4.24s. +``` + +##### On the destination chain + +You can use the following command to set a trusted remote on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-remote-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_trusted_remote.ts --network bnbTestnet +setTrustedRemote - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230 +setTrustedRemote tx: 0x311a0568b5afce7d601df2613f8ff80428d8a4d2f2c91012e0e4a8cbc0aedf59 +Done in 4.88s. +``` + +### Send Origin Tokens From the Source Chain To the Destination Chain + +```bash +yarn send-onft-from-smr-Testnet +``` + +Expected log output: + +```bash +npx hardhat run scripts/send_onft.ts --network shimmerEvmTestnet +sendONFT - proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnSrcChain:10230, lzEndpointIdOnDestChain:10102, gasDropInWeiOnDestChain:0, providedGasLimit:200000, receivingAccountAddress:0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, sender: 0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, nftTokenId:2, nftTokenAddress:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +sendONFT - approve tx: 0xa871bc79e45bf20f33c626044d6e208460c5745ab1f13d476dcbe04e1da7e592 +sendONFT - estimated nativeFee: 158.319172348046094655 +sendONFT - send tx on source chain: 0x72779c7549053194e42bcc78f78cf65e876867f0516dc91f28986c854e652596 +Wait for cross-chain tx finalization by LayerZero ... +sendONFT - received tx on destination chain: 0x2700a9d35c139eb84ba07b75490e6627a30e00bde130e3cb7c1cbb81c0326138 +Done in 53.50s. +``` + +### Send ONFT-Wrapped Tokens Back From the Destination Chain Back To the Origin Chain + +```bash +yarn send-onft-back-from-bnb-Testnet +``` + +Expected log output: + +```bash +npx hardhat run scripts/send_onft_back.ts --network bnbTestnet +sendONFTBack - proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnSrcChain:10230, lzEndpointIdOnDestChain:10102, gasDropInWeiOnDestChain:0, providedGasLimit:200000, receivingAccountAddress:0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, sender: 0x60917645A28258a75836aF63633850c5F3561C1b, nftTokenId:2, nftTokenAddress:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +sendONFTBack - approve tx: 0xe5bfff108528efdc67e72896845f0ad3e0186b4ed64835e7c5f3552eaab69d99 +sendONFTBack - estimated nativeFee: 0.000498452810033053 +sendONFTBack - send tx on source chain: 0xa43bb5547a5a35730fe183b4d554416a4ea34852e510d21f24d173db75db4e79 +Wait for cross-chain tx finalization by LayerZero ... +sendONFTBack - received tx on destination chain: 0xb05fa2de194153819b26d17893278c485abbaf355fa24f26fbc7a4c759994cde +Done in 212.16s. +``` diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/send-funds-from-L1-to-L2.mdx b/docs/build/isc/v1.1/docs/how-tos/send-funds-from-L1-to-L2.mdx similarity index 93% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/send-funds-from-L1-to-L2.mdx rename to docs/build/isc/v1.1/docs/how-tos/send-funds-from-L1-to-L2.mdx index 1a9a469d7ea..0b1b47dec7f 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/send-funds-from-L1-to-L2.mdx +++ b/docs/build/isc/v1.1/docs/how-tos/send-funds-from-L1-to-L2.mdx @@ -36,14 +36,14 @@ If you want to fund your EVM Testnet account using the EVM Toolkit, please refer To send EVM transactions, you need to have an Ethereum address that owns tokens on the ISC chain (L2). These tokens will be used to cover gas fees. - + -You can use your [Firefly Wallet](https://firefly.iota.org/) to easily send L1 SMR to your L2 ShimmerEVM account. +You can use your [Firefly Wallet](https://firefly.iota.org/) to easily send L1 IOTA or SMR to your L2 IOTA EVM or ShimmerEVM account. #### Requirements -* [Shimmer Tokens](/get-started/introduction/shimmer/shimmer-token/) or [IOTA Tokens](/get-started/introduction/iota/iota-token/) +* [IOTA Tokens](/get-started/introduction/iota/iota-token/) or [Shimmer Tokens](/get-started/introduction/shimmer/shimmer-token/) * [Firefly Wallet](https://firefly.iota.org/) * [Metamask](https://metamask.io/) diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/test-smart-contracts.md b/docs/build/isc/v1.1/docs/how-tos/test-smart-contracts.md similarity index 93% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/test-smart-contracts.md rename to docs/build/isc/v1.1/docs/how-tos/test-smart-contracts.md index 7b032b6d9bf..c3f2a8aa344 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/test-smart-contracts.md +++ b/docs/build/isc/v1.1/docs/how-tos/test-smart-contracts.md @@ -5,9 +5,9 @@ keywords: - Unit Tests - Integration Tests - Testing Frameworks -- ShimmerEVM Testnet +- EVM Testnet - Solidity Testing -description: Learn how to test smart contracts before deploying them on public networks to avoid vulnerabilities and ensure functionality aligns with requirements using unit, and integration testing, alongside frameworks and testing with the IOTA Sandbox and the ShimmerEVM Testnet. +description: Learn how to test smart contracts before deploying them on public networks to avoid vulnerabilities and ensure functionality aligns with requirements using unit, and integration testing, alongside frameworks and testing with the IOTA Sandbox and the EVM Testnet. --- # Testing Smart Contracts @@ -91,18 +91,18 @@ expected. #### Tools -You can use the [ShimmerEVM Testnet](/build/networks-endpoints/#testnet-evm) to conduct integration tests without +You can use the [EVM Testnet](/build/networks-endpoints/#shimmerevm-testnet) to conduct integration tests without incurring any fees or the [IOTA Sandbox](/iota-sandbox/getting-started/) if you want to run the tests locally. ## Manual Testing Once you have a complete batch of [automated tests](#automated-testing), manually testing your contract to ensure it behaves as expected in the real world is still good practice. However, to avoid incurring fees or deploying a faulty -contract, you can manually test your contract using a sandboxed local network and the Shimmer EVM Testnet. +contract, you can manually test your contract using a sandboxed local network and the EVM Testnet. Testing using the [IOTA Sandbox](/iota-sandbox/getting-started/) serves well for the first stage of automated and manual integration tests, as you have complete control over the entire local network. Once you are confident about how your -contract behaves locally, you can deploy and test on the [ShimmerEVM Testnet](/build/networks-endpoints/#testnet-evm), -which replicates the ShimmerEVM network but also enables cost and risk-free interactions. +contract behaves locally, you can deploy and test on the [EVM Testnet](/build/networks-endpoints/#shimmerevm-testnet), +which replicates the IOTA EVM and ShimmerEVM networks, but also enables cost and risk-free interactions. diff --git a/docs/build/isc/v1.0.0-rc.6/docs/introduction.md b/docs/build/isc/v1.1/docs/introduction.md similarity index 97% rename from docs/build/isc/v1.0.0-rc.6/docs/introduction.md rename to docs/build/isc/v1.1/docs/introduction.md index c644eb4da1a..b3811792692 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/introduction.md +++ b/docs/build/isc/v1.1/docs/introduction.md @@ -11,13 +11,10 @@ tags: - explanation --- -import NetworkWarning from './_admonitions/_network_warning.md' import OnOffLedgerRequest from './_partials/_on_off_ledger_request.md'; # Introduction - - Smart contracts are deterministic applications that run on a distributed network with multiple [validators](explanations/validators.md) that execute and validate the same code. Their deterministic and distributed nature makes them predictable, stable and trustworthy. diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/.gitignore b/docs/build/isc/v1.1/docs/reference/.gitignore similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/.gitignore rename to docs/build/isc/v1.1/docs/reference/.gitignore diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/accounts.md b/docs/build/isc/v1.1/docs/reference/core-contracts/accounts.md similarity index 89% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/accounts.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/accounts.md index e445e0db13a..18a3f77e787 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/accounts.md +++ b/docs/build/isc/v1.1/docs/reference/core-contracts/accounts.md @@ -93,16 +93,19 @@ the target chain to the sender SC's L2 account on the origin chain. ::: -### `foundryCreateNew(t TokenScheme) s SerialNumber` +### `nativeTokenCreate(t TokenScheme, tn TokenName, ts TokenSymbol, td TokenDecimal) s SerialNumber` -Creates a new foundry with the specified token scheme, and assigns the foundry to the sender. +Creates a new foundry and registers it as a ERC20 and IRC30 token. -You can call this end point from the CLI using `wasp-cli chain create-foundry -h` +You can call this end point from the CLI using `wasp-cli chain create-native-token -h` #### Parameters - `t` ([`iotago::TokenScheme`](https://github.com/iotaledger/iota.go/blob/develop/token_scheme.go)): The token scheme for the new foundry. +- `tn` (`string`): The token name +- `ts` (`string`): The token symbol +- `td` (`uint8`): The token decimals The storage deposit for the new foundry must be provided via allowance (only the minimum required will be used). @@ -110,7 +113,7 @@ The storage deposit for the new foundry must be provided via allowance (only the - `s` (`uint32`): The serial number of the newly created foundry -### `foundryModifySupply(s SerialNumber, d SupplyDeltaAbs, y DestroyTokens)` +### `nativeTokenModifySupply(s SerialNumber, d SupplyDeltaAbs, y DestroyTokens)` Mints or destroys tokens for the given foundry, which must be controlled by the caller. @@ -124,7 +127,7 @@ When minting new tokens, the storage deposit for the new output must be provided When destroying tokens, the tokens to be destroyed must be provided via an allowance. -### `foundryDestroy(s SerialNumber)` +### `nativeTokenDestroy(s SerialNumber)` Destroys a given foundry output on L1, reimbursing the storage deposit to the caller. The foundry must be owned by the caller. @@ -139,6 +142,31 @@ This operation cannot be reverted. - `s` (`uint32`): The serial number of the foundry. + +### `foundryCreateNew(t TokenScheme) s SerialNumber` + +:::warning Deprecated + +This function is deprecated, please use [`nativeTokenCreate`](#nativetokencreatet-tokenscheme-s-serialnumber) instead + +::: + +Creates a new foundry with the specified token scheme, and assigns the foundry to the sender. + +You can call this end point from the CLI using `wasp-cli chain create-foundry -h` + +#### Parameters + +- `t` ([`iotago::TokenScheme`](https://github.com/iotaledger/iota.go/blob/develop/token_scheme.go)): The token scheme + for the new foundry. + +The storage deposit for the new foundry must be provided via allowance (only the minimum required will be used). + +#### Returns + +- `s` (`uint32`): The serial number of the newly created foundry + + ### `mintNFT(I ImmutableData, a AgentID, C CollectionID, w WithdrawOnMint)` Mints an NFT with ImmutableData `I` that will be owned by the AgentID `a`. @@ -221,7 +249,7 @@ Returns a list of all native tokenIDs that are owned by the chain. A map of [`TokenID`](#tokenid) => `0x01` -### `foundryOutput(s FoundrySerialNumber)` +### `nativeToken(s FoundrySerialNumber)` #### Parameters diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blob.md b/docs/build/isc/v1.1/docs/reference/core-contracts/blob.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blob.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/blob.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blocklog.md b/docs/build/isc/v1.1/docs/reference/core-contracts/blocklog.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/blocklog.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/blocklog.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/errors.md b/docs/build/isc/v1.1/docs/reference/core-contracts/errors.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/errors.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/errors.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/evm.md b/docs/build/isc/v1.1/docs/reference/core-contracts/evm.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/evm.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/evm.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/governance.md b/docs/build/isc/v1.1/docs/reference/core-contracts/governance.md similarity index 98% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/governance.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/governance.md index ab8e092379b..9958c2a9ad8 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/governance.md +++ b/docs/build/isc/v1.1/docs/reference/core-contracts/governance.md @@ -325,8 +325,6 @@ A ratio between two values `x` and `y`, expressed as two `int32` numbers `a:b`, `FeePolicy` is encoded as the concatenation of: -- The [`TokenID`](accounts.md#tokenid) of the token used to charge for gas. (`iotago.NativeTokenID`) - - If this value is `nil`, the gas fee token is the base token. - Gas per token ([`Ratio32`](#ratio32)): expressed as an `a:b` (`gas/token`) ratio, meaning how many gas units each token pays for. - Validator fee share. Must be between 0 and 100, meaning the percentage of the gas fees distributed to the validators. (`uint8`) diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/overview.md b/docs/build/isc/v1.1/docs/reference/core-contracts/overview.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/overview.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/overview.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/root.md b/docs/build/isc/v1.1/docs/reference/core-contracts/root.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/root.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/root.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/xfer.md b/docs/build/isc/v1.1/docs/reference/core-contracts/xfer.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/core-contracts/xfer.md rename to docs/build/isc/v1.1/docs/reference/core-contracts/xfer.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/json-rpc-spec.md b/docs/build/isc/v1.1/docs/reference/json-rpc-spec.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/json-rpc-spec.md rename to docs/build/isc/v1.1/docs/reference/json-rpc-spec.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/introduction.md b/docs/build/isc/v1.1/docs/reference/magic-contract/introduction.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/introduction.md rename to docs/build/isc/v1.1/docs/reference/magic-contract/introduction.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/reference/wasm-lib-data-types.mdx b/docs/build/isc/v1.1/docs/reference/wasm-lib-data-types.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/reference/wasm-lib-data-types.mdx rename to docs/build/isc/v1.1/docs/reference/wasm-lib-data-types.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/access.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/access.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/access.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/access.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/call.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/call.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/call.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/call.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/events.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/events.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/events.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/events.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcdesc.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/funcdesc.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcdesc.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/funcdesc.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/funcs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/funcs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/funcs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/init.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/init.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/init.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/init.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/params.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/params.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/params.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/params.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/post.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/post.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/post.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/post.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/results.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/results.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/results.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/results.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/spec.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/spec.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/spec.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/spec.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/state.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/state.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/state.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/state.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/structs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/structs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/structs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/structs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/thunks.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/thunks.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/thunks.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/thunks.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/transfers.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/transfers.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/transfers.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/transfers.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/typedefs.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/typedefs.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/typedefs.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/typedefs.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/usage.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/usage.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/usage.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/usage.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/views.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/views.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/views.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/views.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/yaml.mdx b/docs/build/isc/v1.1/docs/schema/how-tos/yaml.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/how-tos/yaml.mdx rename to docs/build/isc/v1.1/docs/schema/how-tos/yaml.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/introduction.mdx b/docs/build/isc/v1.1/docs/schema/introduction.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/introduction.mdx rename to docs/build/isc/v1.1/docs/schema/introduction.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/schema/proxies.mdx b/docs/build/isc/v1.1/docs/schema/proxies.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/schema/proxies.mdx rename to docs/build/isc/v1.1/docs/schema/proxies.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/getting-started.md b/docs/build/isc/v1.1/docs/solo/getting-started.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/getting-started.md rename to docs/build/isc/v1.1/docs/solo/getting-started.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/deploying-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/deploying-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/deploying-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/deploying-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/error-handling.md b/docs/build/isc/v1.1/docs/solo/how-tos/error-handling.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/error-handling.md rename to docs/build/isc/v1.1/docs/solo/how-tos/error-handling.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/examples.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/examples.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/examples.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/examples.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/first-example.md b/docs/build/isc/v1.1/docs/solo/how-tos/first-example.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/first-example.md rename to docs/build/isc/v1.1/docs/solo/how-tos/first-example.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/invoking-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/invoking-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/invoking-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/invoking-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/test.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/test.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/test.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/test.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l1-ledger.md b/docs/build/isc/v1.1/docs/solo/how-tos/the-l1-ledger.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l1-ledger.md rename to docs/build/isc/v1.1/docs/solo/how-tos/the-l1-ledger.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l2-ledger.md b/docs/build/isc/v1.1/docs/solo/how-tos/the-l2-ledger.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/the-l2-ledger.md rename to docs/build/isc/v1.1/docs/solo/how-tos/the-l2-ledger.md diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/timelock.mdx b/docs/build/isc/v1.1/docs/solo/how-tos/timelock.mdx similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/timelock.mdx rename to docs/build/isc/v1.1/docs/solo/how-tos/timelock.mdx diff --git a/docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/view-sc.md b/docs/build/isc/v1.1/docs/solo/how-tos/view-sc.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/solo/how-tos/view-sc.md rename to docs/build/isc/v1.1/docs/solo/how-tos/view-sc.md diff --git a/docs/build/isc/v1.0.0-rc.6/sidebars.js b/docs/build/isc/v1.1/sidebars.js similarity index 93% rename from docs/build/isc/v1.0.0-rc.6/sidebars.js rename to docs/build/isc/v1.1/sidebars.js index 79e46174358..675779b89b5 100644 --- a/docs/build/isc/v1.0.0-rc.6/sidebars.js +++ b/docs/build/isc/v1.1/sidebars.js @@ -84,11 +84,21 @@ module.exports = { label: 'Create Custom Tokens - ERC20', id: 'how-tos/ERC20', }, + { + type: 'doc', + label: 'Send ERC20 Tokens Across Chains', + id: 'how-tos/send-ERC20-across-chains', + }, { type: 'doc', label: 'Create NFTs - ERC721', id: 'how-tos/ERC721', }, + { + type: 'doc', + label: 'Send NFTs Across Chains', + id: 'how-tos/send-NFTs-across-chains', + }, { type: 'doc', label: 'Test Smart Contracts', @@ -151,14 +161,24 @@ module.exports = { }, { type: 'doc', - label: 'Create a Foundry', - id: 'how-tos/core-contracts/token/create-foundry', + label: 'Create a Native Token', + id: 'how-tos/core-contracts/token/create-native-token', }, { type: 'doc', - label: 'Mint a Native Token', + label: 'Mint Native Tokens', id: 'how-tos/core-contracts/token/mint-token', }, + { + type: 'doc', + label: 'Custom ERC20 Functions', + id: 'how-tos/core-contracts/token/erc20-native-token', + }, + { + type: 'doc', + label: 'Create a Foundry', + id: 'how-tos/core-contracts/token/create-foundry', + }, { type: 'doc', label: 'Register Token as ERC20', @@ -166,8 +186,8 @@ module.exports = { }, { type: 'doc', - label: 'Custom ERC20 Functions', - id: 'how-tos/core-contracts/token/erc20-native-token', + label: 'Send Token Across Chains', + id: 'how-tos/core-contracts/token/send-token-across-chains', }, ], }, @@ -190,6 +210,11 @@ module.exports = { label: 'Use as ERC721', id: 'how-tos/core-contracts/nft/use-as-erc721', }, + { + type: 'doc', + label: 'Get NFT Metadata', + id: 'how-tos/core-contracts/nft/get-nft-metadata', + }, ], }, { diff --git a/docs/build/isc/v1.3/docs/_admonitions/_ERC721.md b/docs/build/isc/v1.3/docs/_admonitions/_ERC721.md new file mode 100644 index 00000000000..76191eec6be --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_ERC721.md @@ -0,0 +1,5 @@ +:::info ERC721 + +As your L1 NFT is always registered as [ERC721](https://eips.ethereum.org/EIPS/eip-721), you might want to get the metadata like `tokenURI` from there. Using `getIRC27NFTData` is normally only needed if you need special [IRC27](https://wiki.iota.org/tips/tips/TIP-0027/) metadata. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_EVM-required-prior-knowledge.md b/docs/build/isc/v1.3/docs/_admonitions/_EVM-required-prior-knowledge.md new file mode 100644 index 00000000000..c1e17089a98 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_EVM-required-prior-knowledge.md @@ -0,0 +1,14 @@ +:::note Required Prior Knowledge + +This guide assumes you are familiar with the concept +of [tokens](https://en.wikipedia.org/wiki/Cryptocurrency#Crypto_token) +in [blockchain](https://en.wikipedia.org/wiki/Blockchain), +[Ethereum Request for Comments (ERCs)](https://eips.ethereum.org/erc)(also known as Ethereum Improvement Proposals ( +EIP)) +, [NFTs](/learn/protocols/stardust/core-concepts/multi-asset-ledger#non-fungible-tokens-nfts), [Smart Contracts](/learn/smart-contracts/introduction) +and have already tinkered with [Solidity](https://docs.soliditylang.org/en/v0.8.16/). + +You should also have basic knowledge on how to [create](../how-tos/create-a-basic-contract.md) and [deploy](../how-tos/deploy-a-smart-contract.mdx) +a smart contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_EVM_compatibility.md b/docs/build/isc/v1.3/docs/_admonitions/_EVM_compatibility.md new file mode 100644 index 00000000000..23cc9bfdb24 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_EVM_compatibility.md @@ -0,0 +1,7 @@ +:::info EVM Compatibility + +The ISC EVM layer is also designed to be as compatible as possible with existing Ethereum +[tools](../getting-started/tools.mdx) and functionalities. However, please make sure you have checked out the current +[properties and limitations](../getting-started/compatibility.mdx). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_IRC27.md b/docs/build/isc/v1.3/docs/_admonitions/_IRC27.md new file mode 100644 index 00000000000..1831e8fe100 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_IRC27.md @@ -0,0 +1,5 @@ +:::info IRC27NFTMetadata URI + +The uri property contains a JSON object which follows the `ERC721` standard. This JSON is also returned by the [`tokenURI`](../reference/magic-contract/ERC721NFTs.md#tokenuri) function from the `ERC721NFTs` contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_about-accounts.md b/docs/build/isc/v1.3/docs/_admonitions/_about-accounts.md new file mode 100644 index 00000000000..4095981384d --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_about-accounts.md @@ -0,0 +1,5 @@ +:::info Accounts in ISC + +Learn more about the [different types of accounts](../explanations/how-accounts-work.md). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_create-native-token.md b/docs/build/isc/v1.3/docs/_admonitions/_create-native-token.md new file mode 100644 index 00000000000..223ed9aef7d --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_create-native-token.md @@ -0,0 +1,5 @@ +:::tip Create a Native Token + +Create your first native token by following our how to [Create a Native Token Guide](../how-tos/core-contracts/token/create-native-token.md/). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_deploy_a_smart_contract.md b/docs/build/isc/v1.3/docs/_admonitions/_deploy_a_smart_contract.md new file mode 100644 index 00000000000..de4579b6d81 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_deploy_a_smart_contract.md @@ -0,0 +1,5 @@ +:::tip Deploy a Smart Contract + +Deploy a Solidity Smart Contract following our [how to Deploy a Smart Contract guide](/isc/how-tos/deploy-a-smart-contract#remix). + +::: diff --git a/docs/build/isc/v1.3/docs/_admonitions/_ownership.md b/docs/build/isc/v1.3/docs/_admonitions/_ownership.md new file mode 100644 index 00000000000..fa86ee2f72f --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_ownership.md @@ -0,0 +1,7 @@ +:::info Ownership + +You might want to look into making the function ownable with, for example, +[OpenZeppelin](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) +so only owners of the contract can call certain functionalities of your contract. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_payable.md b/docs/build/isc/v1.3/docs/_admonitions/_payable.md new file mode 100644 index 00000000000..2975d1d26d4 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_payable.md @@ -0,0 +1,10 @@ +:::info Payable + +Instead of making the function payable, you could let the contract pay for the storage deposit. +If so, you will need to change the `require` statement to check if the contract's balance has enough funds: + +```solidity +require(address(this).balance > _storageDeposit); +``` + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_query_gas_fees.md b/docs/build/isc/v1.3/docs/_admonitions/_query_gas_fees.md new file mode 100644 index 00000000000..cd1fc1dd456 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_query_gas_fees.md @@ -0,0 +1,5 @@ +:::tip Current Gas Fee + +You can get the minimum gas fee by querying the `eth_gasPrice` using the [JSON-RPC API](../reference/json-rpc-spec.md/#json-rpc-methods-according-to-ethereum-client-api). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_remix-IDE.md b/docs/build/isc/v1.3/docs/_admonitions/_remix-IDE.md new file mode 100644 index 00000000000..5cfa57d5e69 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_remix-IDE.md @@ -0,0 +1,6 @@ +:::tip Remix + +This guide will use the [Remix IDE](https://remix.ethereum.org/), but you can use this contract with any IDE you are +familiar with. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_admonitions/_token-demo-setup.md b/docs/build/isc/v1.3/docs/_admonitions/_token-demo-setup.md new file mode 100644 index 00000000000..9192df2e16e --- /dev/null +++ b/docs/build/isc/v1.3/docs/_admonitions/_token-demo-setup.md @@ -0,0 +1,6 @@ +:::info Setup Demo Repo + +Visit the Demo Repo GitHub page for instructions on how to properly setup, +[IOTA Cross Chain Token Demo](https://github.com/iotaledger/isc-cross-chain/tree/master?tab=readme-ov-file#iota-cross-chain-token-demo) + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_partials/_hardhat_config.md b/docs/build/isc/v1.3/docs/_partials/_hardhat_config.md new file mode 100644 index 00000000000..d40752cc44b --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/_hardhat_config.md @@ -0,0 +1,67 @@ +import CodeBlock from '@theme/CodeBlock'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + + +{` +networks: { + 'iotaevm-testnet': { + url: '${Networks['iota_testnet'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['iota_testnet'].evm.core.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + + + +{` +networks: { + 'shimmerevm-testnet': { + url: '${Networks['shimmer_testnet'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer_testnet'].evm.core.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + + + +{` +networks: { + 'iotaevm': { + url: '${Networks['iota'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['iota'].evm.core.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + + + +{` +networks: { + 'shimmerevm': { + url: '${Networks['shimmer'].evm.core.rpcUrls[0]}', + chainId: ${parseInt(Networks['shimmer'].evm.core.chainId)}, + accounts: [YOUR PRIVATE KEY], + }, +} +`} + + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_partials/_on_off_ledger_request.md b/docs/build/isc/v1.3/docs/_partials/_on_off_ledger_request.md new file mode 100644 index 00000000000..45d59c458c3 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/_on_off_ledger_request.md @@ -0,0 +1,13 @@ +### On-Ledger Requests + +An on-ledger request is a Layer 1 transaction that validator nodes retrieve from the Tangle. The Tangle acts as an +arbiter between users and chains and guarantees that the transaction is valid, making it the only way to transfer assets +to a chain or between chains. + +### Off-Ledger Requests + +If all necessary assets are in the chain already, it is possible to send a request directly to that chain's validator +nodes. +This way, you don’t have to wait for the Tangle to process the message, significantly reducing the overall confirmation +time. +Due to the shorter delay, off-ledger requests are preferred over on-ledger requests unless you need to deposit assets to the chain. \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_partials/how-tos/token/_check_storage_deposit.md b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_check_storage_deposit.md new file mode 100644 index 00000000000..f3b043b7ba5 --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_check_storage_deposit.md @@ -0,0 +1,10 @@ +### 1. Check the Storage Deposit + +Check if the amount paid to the contract is the same as the required [storage deposit](/learn/protocols/stardust/core-concepts/storage-deposit) + and set the allowance. + +```solidity +require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); +ISCAssets memory allowance; +allowance.baseTokens = _storageDeposit; +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_partials/how-tos/token/_example_code_intro.md b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_example_code_intro.md new file mode 100644 index 00000000000..daf06c0839b --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_example_code_intro.md @@ -0,0 +1,9 @@ +import Ownership from '../../../_admonitions/_ownership.md'; +import Payable from '../../../_admonitions/_payable.md'; +import CheckStorageDeposit from './_check_storage_deposit.md' + + + + + + diff --git a/docs/build/isc/v1.3/docs/_partials/how-tos/token/_get-nft-metadata.md b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_get-nft-metadata.md new file mode 100644 index 00000000000..a13f2634c7d --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_get-nft-metadata.md @@ -0,0 +1,5 @@ +:::tip Mint an NFT + +Mint your first NFT following our how to [mint an NFT guide](../../../how-tos/core-contracts/nft/mint-nft.md#about-nfts). + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/_partials/how-tos/token/_obsolete_token_creation.md b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_obsolete_token_creation.md new file mode 100644 index 00000000000..1a70e93ffaa --- /dev/null +++ b/docs/build/isc/v1.3/docs/_partials/how-tos/token/_obsolete_token_creation.md @@ -0,0 +1,5 @@ +:::caution + +This method is now obsolete, use the new [`createNativeTokenFoundry`](../../../how-tos/core-contracts/token/create-native-token.md) method instead. + +::: \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/explanations/consensus.md b/docs/build/isc/v1.3/docs/explanations/consensus.md new file mode 100644 index 00000000000..539e7c15adb --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/consensus.md @@ -0,0 +1,53 @@ +--- +description: IOTA Smart Contracts consensus is how Layer 2 validators agree to change the chain state in the same way. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - consensus + - validator committee + - validators + - validator nodes + - explanation +--- + +# Consensus + +To update the chain, its committee must reach a _consensus_, meaning that more than two thirds of its validators have to +agree to change the state in the exact same way. +This prevents a single malicious node from wreaking havoc over the chain, but there are also more mundane reasons for +individual nodes to act up. + +Smart contracts are deterministic. All honest nodes will produce the same output — but only if they have received the +same input. Each validator node has its point of access to the Tangle, so it may look different to different nodes, as +new transactions take time to propagate through the network. Validator nodes will receive smart contract requests with +random delays in a random order, and, finally, all computers run on their own always slightly skewed clocks. + +## Batch Proposals + +As the first step, each node provides its vision, a _batch proposal_. The proposal contains a local timestamp, a list of +unprocessed requests, and the node's partial signature of the commitment to the current state. + +Then the nodes must agree on which batch proposals they want to work on. In short, nodes A, B, and C have to confirm +that they plan to work on proposals from A, B, and C, and from no one else. As long as there are more than two thirds of +honest nodes, they will be able to find an _asynchronous common subset_ of the batch proposals. From that point, nodes +have the same input and will produce the same result independently. + +## The Batch + +The next step is to convert the raw list of batch proposals into an actual batch. All requests from all proposals are +counted and filtered to produce the same list of requests in the same order. +The partial signatures of all nodes are combined into a full signature that is then fed to a pseudo-random function that +sorts the smart contract requests. +Validator nodes can neither affect nor predict the final order of requests in the batch. (This protects ISC +from [MEV attacks](https://ethereum.org/en/developers/docs/mev/)). + +## State Anchor + +After agreeing on the input, each node executes every smart contract request in order, independently producing the same +new block. Each node then crafts a state anchor, a Layer 1 transaction that proves the commitment to this new chain +state. The timestamp for this transaction is derived from the timestamps of all batch proposals. + +All nodes then sign the state anchor with their partial keys and exchange these signatures. This way, every node obtains +the same valid combined signature and the same valid anchor transaction, which means that any node can publish this +transaction to Layer 1. In theory, nodes could publish these state anchors every time they update the state; in +practice, they do it only every approximately ten seconds to reduce the load on the Tangle. diff --git a/docs/build/isc/v1.3/docs/explanations/context.mdx b/docs/build/isc/v1.3/docs/explanations/context.mdx new file mode 100644 index 00000000000..ac2507210f4 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/context.mdx @@ -0,0 +1,50 @@ +--- +description: The call context is a predefined parameter to each smart contract function, which allows you to access the functionality that the call environment provides. +tags: + - WasmLib + - smart contract setup + - Func and View functions + - ScFuncContext + - ScViewContext + - Schema Tool +image: /img/logo/WASP_logo_dark.png +--- + +# Call Context + +Understanding the call context is vital in leveraging the Wasm code within a sandboxed host environment effectively. The following section explains the distinction between different function calls and the role of WasmLib in setting up a smart contract. + +## Function Calls: Func and View + +Smart contract function calls come in two types, each having specific access levels to the smart contract state: + +### Funcs + +Func functions grants full mutable access, resulting in a state update. They accommodate both on-ledger and off-ledger requests, finalized once the state update is registered in the Tangle ledger. + +### Views + +View functions allow limited immutable access, **no state update occurs**. Views are ideal for quickly querying the contract's current state, they only facilitate off-ledger calls. + +## Using Func and View + +WasmLib offers distinct contexts for these function types, namely `ScFuncContext` for Func and `ScViewContext` for View, controlling the accessible functionality and enforcing usage constraints through compile-time type-checking. + +## Smart Contract Setup with WasmLib + +Setting up a smart contract requires the following: + +### Defining Funcs and Views + +Outline available Funcs and Views and communicate them to the host through WasmLib. +It ensures the correct dispatch of function calls and maintains necessary restrictions. + +### Parameter and Return Value Determination + +Establish the parameters and return values for each function. ISC uses simple dictionaries to store details, necessitating consistent (de)serialization handled adeptly by WasmLib. + +### Utilizing Schema Tool + +Although you can use the WasmLib directly, the Schema Tool is recommended for automatically generating and updating the smart contract framework in a type-safe manner, using the preferred language. + +Grasping these concepts will facilitate a secure and efficient smart contract setup, steering clear of potential pitfalls while making the most of what WasmLib offers. diff --git a/docs/build/isc/v1.3/docs/explanations/core-contracts.md b/docs/build/isc/v1.3/docs/explanations/core-contracts.md new file mode 100644 index 00000000000..acfdbf5e22c --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/core-contracts.md @@ -0,0 +1,37 @@ +--- +description: There currently are 6 core smart contracts that are always deployed on each chain, root, _default, accounts, blob, blocklog, and governance. +image: /img/banner/banner_wasp_core_contracts_overview.png +tags: + - smart contracts + - core + - initialization + - request handling + - on-chain ledger + - accounts + - data + - receipts + - reference +--- + +# Core Contracts + +![Wasp Node Core Contracts Overview](/img/banner/banner_wasp_core_contracts_overview.png) + +There are currently 7 core smart contracts that are always deployed on each +chain. These are responsible for the vital functions of the chain and +provide infrastructure for all other smart contracts: + +- [`root`](../reference/core-contracts/root.md): Responsible for the initialization of the chain, maintains registry of deployed contracts. + +- [`accounts`](../reference/core-contracts/accounts.md): Manages the on-chain ledger of accounts. + +- [`blob`](../reference/core-contracts/blob.md): Responsible for the registry of binary objects of arbitrary size. + +- [`blocklog`](../reference/core-contracts/blocklog.md): Keeps track of the blocks and receipts of requests that were processed by the chain. + +- [`governance`](../reference/core-contracts/governance.md): Handles the administrative functions of the chain. For example: rotation of the committee of validators of the chain, fees and other chain-specific configurations. + +- [`errors`](../reference/core-contracts/errors.md): Keeps a map of error codes to error messages templates. These error codes are used in request receipts. + +- [`evm`](../reference/core-contracts/evm.md): Provides the necessary infrastructure to accept Ethereum + transactions and execute EVM code. diff --git a/docs/build/isc/v1.3/docs/explanations/how-accounts-work.md b/docs/build/isc/v1.3/docs/explanations/how-accounts-work.md new file mode 100644 index 00000000000..8847cb2c883 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/how-accounts-work.md @@ -0,0 +1,102 @@ +--- +description: 'IOTA Smart Contracts chains keep a ledger of on-chain account balances. On-chain accounts are identified +by an AgentID.' +image: /img/tutorial/accounts.png +tags: + +- smart contracts +- on-chain account +- ownership +- accounts Contract +- explanation + +--- +# How Accounts Work + +On the L1 Ledger, like with any _DLT_, we have **trustless** and **atomic** transfers of assets between addresses on the +ledger. + +Tokens controlled by an address can be moved to another address by providing a valid signature using the private key +that controls the source address. + +## L1 Addresses + +In IOTA Smart Contracts, [each chain has a L1 address](../explanations/states.md#digital-assets-on-the-chain) (also known as the _Chain +ID_) which enables it to control L1 assets (base tokens, native tokens and NFTs). +The chain acts as a custodian of the L1 assets on behalf of different entities, thus providing a _L2 Ledger_. + +## L2 Accounts + +The L2 ledger is a collection of _on-chain accounts_ (sometimes called just _accounts_). +L2 accounts can be owned by different entities, identified by a unique _Agent ID_. +The L2 ledger is a mapping of Agent ID => balances of L2 assets. + +## Types of Accounts + +### L1 Address + +Any L1 address can be the owner of a L2 account. +The Agent ID of an L1 address is just the address, + +e.g. `iota1pr7vescn4nqc9lpvv37unzryqc43vw5wuf2zx8tlq2wud0369hjjugg54mf`. + +Tokens in an address account can only be moved through a request signed by the private key of the L1 address. + +### Smart Contract + +Any _smart contract_ can be the owner of a L2 account. Recall that a smart +contract is uniquely identified in a chain by a [_hname_](smart-contract-anatomy.md#identifying-a-smart-contract). +However, the hname is not enough to identify the account since a smart contract on another chain could own it. + +Thus, the Agent ID of a smart contract is composed as the contract hname plus the [_chain +ID_](states.md#digital-assets-on-the-chain), with syntax `@`. For +example: `cebf5908@tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd`. + +Note that this allows trustless transfers of assets between smart contracts on the same or different chains. + +Tokens in a smart contract account can only be moved by that smart contract. + +### The Common Account + +The chain owns a unique L2 account, called the _common account_. +The common account is controlled by the chain owner (defined in the chain root contract) and is used to store funds +collected by fees or sent to the chain L1 address. + +The Agent ID of the common account is `@
`. + +### Ethereum Address + +An L2 account can also be owned by an Ethereum address. See [EVM](../introduction.md) for more information. +The Agent ID of an Ethereum address is just the address prefixed with `0x`, +e.g. `0xd36722adec3edcb29c8e7b5a47f352d701393462`. + +Tokens in an Ethereum account can only be moved by sending an Ethereum transaction signed by the same address. + +## The Accounts Contract + +The [`accounts` core contract](../reference/core-contracts/accounts.md) is responsible for managing the L2 ledger. +By calling this contract, it is possible to: + +- [View current account balances](../how-tos/core-contracts/basics/get-balance.md) +- [Deposit funds to the chain](../how-tos/send-funds-from-L1-to-L2.mdx) +- [Withdraw funds from the chain](../how-tos/core-contracts/basics/send-assets-to-l1.mdx) + +## Example + +The following diagram illustrates an example situation. +The IDs and hnames are shortened for simplicity. + +[![Example situation. Two chains are deployed, with three smart contracts and one address.](/img/tutorial/accounts.png)](/img/tutorial/accounts.png) + +Two chains are deployed, with IDs `chainA` and `chainB`. +`chainA` has two smart contracts on it (with hnames `3037` and `2225`), and `chainB` has one smart contract (`7003`). + +There is also an address on the L1 Ledger: `iota1a2b3c4d`. +This address controls 1337 base tokens and 42 `Red` native tokens on the L1 Ledger. + +The same address also controls 42 base tokens on `chainA` and 8 `Green` native tokens on `chainB`. + +So, the owner of the private key behind the address controls three different accounts: the L1 account and one L2 account +on each chain. + +Smart contract `7003@chainB` has five base tokens on its native chain and controls eleven base tokens on chain A. diff --git a/docs/build/isc/v1.3/docs/explanations/invocation.md b/docs/build/isc/v1.3/docs/explanations/invocation.md new file mode 100644 index 00000000000..28756fd0713 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/invocation.md @@ -0,0 +1,108 @@ +--- +description: 'Smart contracts can be invoked through their entry points, from outside via a request, or from inside via a +call.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- requests +- on-ledger +- off-ledger +- calls +- invocation +- explanation + +--- + +import OnOffLedgerRequest from '../_partials/_on_off_ledger_request.md'; + +# Calling a Smart Contract + +## Entry Points + +Like any other computer program, a smart contract will lie dormant until someone or something instructs it to activate. +In the case of smart contracts, the most common way to activate them is to call one of +their [entry points](./smart-contract-anatomy.md#entry-points). It is the same as calling a program's function. It will +take a set of instructions of the smart contract and execute it over the current chain's state. _View entry points_ can +only read the state, while _full entry points_ can read and write to it. + +To invoke a smart contract from outside the chain, the _sender_ (some entity that needs to be identified by a +private/public key pair) has to wrap the call to the entry point into a _request_. +The request has to be cryptographically signed and submitted to the [consensus](./consensus.md) procedure to let the +chain's committee evaluate it and engrave the outcome of its execution into a new state update. + +Upon receiving a request, the committee will execute the wrapped call fully or reject the request with all its potential +changes, never modifying the state halfway. This means that every single request is an atomic operation. + +### Synchronous Composability + +After being invoked by a request, the smart contract code is allowed to invoke entry points of other smart contracts on +the same chain. This means it can _call_ other smart contracts. + +Smart contract calls are deterministic and synchronous, meaning they always produce the same result and execute all +instructions immediately after another. +If a smart contract calls another smart contract, the resulting set of instructions is also deterministic and +synchronous. This means that for a request, it makes no difference if a smart contract's entry point contains the whole +set of instructions or if it is composed by multiple calls to different smart contracts of the chain. + +Being able to combine smart contracts in this way is called _synchronous composability_. + +--- + +## Requests + +A request contains a call to a smart contract and a signature of the sender. The sender also owns the assets and funds +processed within the request. +Unlike calls between smart contracts, requests are not executed immediately. +Instead, they must wait until the chain's _validator_ nodes include them in a request batch. +This means that requests have a delay and are executed in an unpredictable order. + +### Asynchronous Composability + +Requests are not sent by humans exclusively. Smart contracts can also create requests. +For example, a user can send a request to a smart contract that, in turn, sends a request to a decentralized third-party +exchange which would will the user's funds from one currency to another and send them back through another request. + +This is called _asynchronous composability_. + + + +--- + +## Gas + +Gas expresses the "cost" of running a request in a chain. Each operation (arithmetics, write to disk, dispatch events, +etc.) has an associated gas cost. The amount of gas required for a transaction depends on the complexity of the +operation. For example, simple transfers may require less gas, while interacting with smart contracts for actions such +as token swaps can require more due to the higher computational work involved. + +For users to specify how much they're willing to pay for a request, they need to specify a `GasBudget` in the request. +This gas budget is the "maximum operations that this request can execute" and will be charged as a fee based on the +chain's current [fee policy](../reference/core-contracts/governance.md#fee-policy). + +The funds to cover the gas used will be charged directly from the user's on-chain account. + +--- + +## Allowance + +An allowance is a feature within smart contracts that controls how much one address can spend on behalf +of another address. Before a third party can withdraw tokens from your account, you must explicitly set an allowance for +that third party's address, specifying the maximum amount of tokens they are allowed to transfer. This mechanism is used +in various decentralized finance (DeFi) applications, where you might allow a smart contract to interact with your +tokens to participate in staking, lending, or trading activities. The original token owner can adjust or revoke the +allowance at any time, providing control over how your tokens are used by others. + +Any funds sent to the chain are credited to the sender's account. If you want a contract to use +those funds, you must specify an `Allowance` in the request. Contracts can then claim any of the allowed funds using +the sandbox `TransferAllowedFunds` function. + +The Allowance property looks like the following: + +```go +{ + BaseTokens: uint64 + NativeTokens: [{TokenID, uint256}, ...] + NFTs: [NFTID, ...] +} +``` diff --git a/docs/build/isc/v1.3/docs/explanations/sandbox.md b/docs/build/isc/v1.3/docs/explanations/sandbox.md new file mode 100644 index 00000000000..d5ff9a7add4 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/sandbox.md @@ -0,0 +1,45 @@ +--- +description: 'Smart Contracts can only interact with the world by using the Sandbox interface which provides limited and +deterministic access to the state through a key/value storage abstraction.' +image: /img/sandbox.png +tags: + +- smart contracts +- sandbox +- interface +- storage abstraction +- explanation + +--- + +# Sandbox Interface + +A smart contract's access to the world has to be restricted. Imagine a smart contract that would directly tap into a +weather forecast website: as the weather changes, the result of the contract's execution will also change. This smart +contract is not deterministic, meaning that you cannot reproduce the result yourself to verify it because the result for +each execution could be different. + +The access to the chain's state has to be curated, too. The chain owner and developers of individual smart contracts are +not necessarily the same entity. A single malicious contract could ruin the whole chain if not limited to its own space. +Instead of working on the state as a whole, each smart contract can only modify a part of it. + +The only way for smart contracts to access data is to use the sandbox interface, which is deterministic. It provides +their internal state as a list of key/value pairs. + +![Sandbox](/img/sandbox.png) + +Besides reading and writing to the contract state, the Sandbox interface allows smart contracts to access: + +- The [ID](how-accounts-work.md) of the contract. +- The details of the current request or view call. +- The current request allowance and a way to claim the allowance. +- The balances owned by the contract. +- The ID of whoever had deployed the contract. +- The timestamp of the current block. +- Cryptographic utilities like hashing, signature verification, and so on. +- The [events](../schema/how-tos/events.mdx) dispatch. +- Entropy that emulates randomness in an unpredictable yet deterministic way. +- Logging. Used for debugging in a test environment. + +The Sandbox API available in "view calls" is slightly more limited than the one available in normal "execution calls". +For example, besides the state access being read-only for a view, they cannot issue requests, emit events, etc. diff --git a/docs/build/isc/v1.3/docs/explanations/smart-contract-anatomy.md b/docs/build/isc/v1.3/docs/explanations/smart-contract-anatomy.md new file mode 100644 index 00000000000..aa5539626a9 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/smart-contract-anatomy.md @@ -0,0 +1,77 @@ +--- +description: Each smart contract instance has a program with a collection of entry points and a state. +image: /img/tutorial/SC-structure.png +tags: + - smart contracts + - structure + - state + - entry points + - Wasm + - explanation +--- + +# Anatomy of a Smart Contract + +Smart contracts are programs that are immutably stored in the chain. + +Through _VM abstraction_, the ISC virtual machine is agnostic about the interpreter used to execute each smart contract. +It can support different _VM types_ (i.e., interpreters) simultaneously on the same chain. +For example, it is possible to have [Wasm](../getting-started/languages-and-vms.md#wasm-vm-for-isc) and [EVM/Solidity](../getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) smart +contracts coexisting on the same chain. + +![Smart Contract Structure](/img/tutorial/SC-structure.png) + +## Identifying a Smart Contract + +The ISC [core contracts](core-contracts.md) and WASM contracts on the chain are identified by a _hname_ (pronounced +"aitch-name"), which is a `uint32` value calculated as a hash of the smart contract's instance name (a string). +For example, the hname of the [`root`](../reference/core-contracts/root.md) core contract +is `0xcebf5908`. This value uniquely identifies this contract in every chain. This does not apply to EVM contracts. + +## State + +The smart contract state is the data owned by the smart contract and stored on the chain. +The state is a collection of key/value pairs. +Each key and value are byte arrays of arbitrary size (there are practical limits set by the underlying database, of +course). +You can think of the smart contract state as a partition of the chain's data state, which can only be written by the +smart contract program itself. + +The smart contract also owns an account on the chain, stored as part of the chain state. +The smart contract account represents the balances of base tokens, native tokens, and NFTs controlled by the smart +contract. + +The smart contract program can access its state and account through an interface layer called the _Sandbox_. +Only the smart contract program can change its data state and spend from its +account. Tokens can be sent to the smart contract account by any other agent on +the ledger, be it a wallet with an address or another smart contract. + +See [Accounts](./how-accounts-work.md) for more information on sending and receiving +tokens. + +## Entry Points + +Each smart contract has a program with a collection of _entry points_. +An entry point is a function through which you can invoke the program. + +There are two types of entry points: + +- _Full entry points_ (or simply _entry points_): These functions can modify + (mutate) the smart contract's state. +- _View entry points_ (or _views_): These are read-only functions. They are only used + to retrieve the information from the smart contract state. They cannot + modify the state, i.e., they are read-only calls. + +## Execution Results + +After a request to a Smart Contract is executed (a call to a full entry point), a _receipt_ will be added to +the [`blocklog`](../reference/core-contracts/blocklog.md) core contract. The receipt details the +execution results +of said request: whether it was successful, the block it was included in, and other information. +Any events dispatched by the smart contract in context of this execution will also be added to the receipt. + +## Error Handling + +Smart contract calls can fail: for example, if they are interrupted for any reason (e.g., an exception) or if it +produces an error (missing parameter or other inconsistency). +Any gas spent will be charged to the sender, and the error message or value is stored in the receipt. diff --git a/docs/build/isc/v1.3/docs/explanations/smart-contracts.md b/docs/build/isc/v1.3/docs/explanations/smart-contracts.md new file mode 100644 index 00000000000..b7b194d8749 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/smart-contracts.md @@ -0,0 +1,54 @@ +--- +description: 'Smart contracts are applications you can trust that run on a distributed network with multiple validators +all executing and validating the same code.' +image: /img/banner/banner_wasp_core_concepts_smart_contracts.png +tags: + +- smart contracts +- blockchain +- parallel +- scaling +- explanation + +--- + +# Smart Contracts + +![Wasp Node Smart Contracts](/img/banner/banner_wasp_core_concepts_smart_contracts.png) + +## What Are Smart Contracts? + +Smart contracts are software applications that run on a distributed network with multiple validators executing and +validating the same code. This ensures the application behaves as expected and that there is no tampering in the +program's execution. + +### Applications You Can Trust + +As you can be certain that the executed code is always the same (and will not change), this results in +applications you can trust. This allows you to use smart contracts for applications with a trust issue. The +smart contract rules define what the contract can and can not do, making it a decentralized and predictable +decision-maker. + +You can use smart contracts for all kinds of purposes. A recurring reason to use a smart contract is to automate +specific +actions without needing a centralized entity to enforce this specific action. A good example is a smart contract +that can exchange a certain amount of IOTA tokens for land ownership. The smart contract will accept +both the IOTA tokens and the land ownership, and will predictably exchange them between both parties without the risk of +one of the parties not delivering on their promise. **With a smart contract, code is law**. + +### Scalable Smart Contracts + +Anyone willing to pay the fees for deploying a smart contract on a public blockchain can deploy one. Once your smart +contract has been deployed to the chain, you no longer have the option to change it, and you can be sure that your +smart contract application will be there as long as that blockchain exists. Smart contracts can communicate with one +another, and you can invoke programmed public functions on a smart contract to trigger actions on a smart contract, or +address the state of a smart contract. + +Because smart contracts do not run on a single computer but on many validators, a network of validators can only +process so many smart contracts at once, even if the software has been written optimally. This means smart contracts are +expensive to execute, and do not scale well on a single blockchain, often resulting in congested networks and costly +fees for executing functions on smart contracts. **By allowing many blockchains executing smart contracts to run in +parallel** and communicate with one another, **IOTA Smart Contracts solves this scalability problem.** + +At the same time, ISC provides advanced means of communication between its chains and preserves the ability to create +complex, composed smart contracts. diff --git a/docs/build/isc/v1.3/docs/explanations/state_manager.md b/docs/build/isc/v1.3/docs/explanations/state_manager.md new file mode 100644 index 00000000000..dcbbf0c9e06 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/state_manager.md @@ -0,0 +1,209 @@ +--- +description: State manager is Wasp component, which is responsible for keeping the store up to date. +image: /img/logo/WASP_logo_dark.png +tags: + - state manager + - pruning + - snapshot + - write ahead log + - WAL +--- + +# State Manager + +State manager aims at keeping the state of the node up to date by retrieving missing data and ensuring that it is +consistently stored in the DB. It services requests by other Wasp components (consensus, _mempool_), which mainly +consist of ensuring that the required state is available in the node: that it may be retrieved from the permanent +store of the node (the database; DB). An obvious way to obtain the latest state is to obtain all of the blocks, +that resulted in making that state. So to obtain state index `n`, state manager first must commit block index `0` +(origin block), then block index `1`, then block index `2` etc. up to block index `n` precisely in that order. +There are two ways for state manager to obtain blocks (other than origin block): + +1. Receive them directly from this node's consensus when the new state[^1] is decided. State manager has no influence + to this process. +2. Receive them from neighbouring nodes upon request, provided the block is available there. + +Independently of the way the block is received, it is stored in state manager's cache (for quicker access) and WAL +(to ensure availability). Therefore it may happen that the block can be retrieved from there. + +[^1] A block is a difference between two consecutive states. To make state index `n`, block index `n` must be obtained +and committed on top of state index `n-1`. Although state manager manipulates blocks, in this description sometimes +"state" and "block" will be used interchangeably as "obtaining block" or "committing block" is essentially the same as +"obtaining state" or "committing state" respectively, having in mind that previous state is already obtained or committed. Block +and state has some other common properties, e.g. block index `n`, which applied to state index `n-1` produces state index `n`, +contains the same commitment as state index `n`. + +## Snapshot + +Once in a while there might be a need to add a new node to the network. This node has no knowledge of chain's history +and it still needs to have the newest state of the chain (to catch up the chain). If the chain has been running for a while, +it might have gone through many sate transitions and downloading that many blocks may take a long period of time. To avoid that, +some nodes in the network can be configured to dump a complete state of the chain at some time into a file periodically +(see `snapshots.period` parameter). This file is called a snapshot. Loading a snapshot to DB produces the same state as downloading +and committing all the blocks that produced that state. However as those blocks aren't downloaded, they are not available in the DB, +except a block with the same state index as snapshot. + +The snapshot format is as follows: + +1. number `4` in 4 byte unsigned integer little endian format representing the length of state index, +2. state index in 4 byte unsigned integer little endian format, +3. number `40` in 4 byte unsigned integer little endian format representing the length of state commitment: `20` bytes for trie root and + `20` bytes for hash of a block, which was last committed to make this state (block with the same index as state), +4. trie root in `20` bytes, +5. the mentioned block's hash in `20` bytes, +6. number `0` in 1 byte unsigned integer format representing snapshot version, +7. bytes representing mentioned block, +8. bytes representing trie of the state. + +The node that makes a snapshot can serve it over http and new nodes can use this to speed up the catch up. Serving the snapshots +over http is beyond the scope of Wasp and should be done in addition. Wasp is only responsible for making snapshots in local +(configurable by `snapshots.localPath` parameter) folder and obtaining them on start when needed from the same local folder or from +configured (by `snapshots.networkPaths` parameter) URLs. A folder, referenced in the `snapshots.networkPaths` parameter must contain +`INDEX` file with new line separated list of snapshot file names. + +If a chain starts with an empty database (usually if the database hasn't been created yet or was deleted), the node checks if +it can load a snapshot: it scans the local folder and all the network addresses for available snapshot files. In the local folder, it reads +all the files with names that satisfy the search pattern `*-*.snap`. In each network location, Wasp reads all the files listed in `INDEX` +file of that location. Wasp reads a state index and a commitment from the contents of these files. File names are not used to obtain +this information, and full snapshot files are not (down)loaded yet. The node chooses +the one with the largest state index and loads it to the store among all available snapshot files. If several files have the same largest state index, +the node loads them one by one, starting from the local ones until one snapshot is loaded correctly. If loading fails for all candidates, +the node will start with an empty database. + +You can use the `snapshots.snapshotsToLoad` parameter to load a specific snapshot. In that case, the node searches for snapshots with +the block hash provided in the parameter. Once again, if loading all found files fails, the node starts with an empty database. + +After a snapshot is loaded, earlier blocks (ones with a smaller state index than the snapshot) cannot be retrieved and committed to the DB +(this is discussed in [Obtaining blocks section](#obtaining-blocks)). This constraint can cause problems (especially in reorg) +if the loaded snapshot is too recent. To avoid that, making snapshots is delayed by `snapshots.delay` states. E.g., if `snapshots.period` +is `100` and `snapshots.delay` is `20`, then snapshot index `100` will be produced. When block index `120` is committed, snapshot index +`200` will be produced, when snapshot index `220` is committed, etc... For the data to be available after this delay, `snapshot.delay` +value must be considerably smaller than `stateManager.pruningMinStatesToKeep`. + +## Obtaining blocks + +Requests to the state manager contain the state commitment and the state manager must ensure, that block (state) with this +commitment is present in the DB. It is possible that to satisfy the request state manager needs to retrieve +several blocks. However this cannot be done in one step as only the commitment of the requested block is known. For this +reason state (block) contains a commitment of the previous block. Previous block must be committed prior to committing the +requested block. And this logic can be extended up to the block, which is already present in the DB, or until the origin +state is reached. + +E.g., let's say, that the last state in the DB is state index `10` and request to have state index `12` is received. +State manager does this in following steps: + +1. Block index `12` is obtained, and commitment of block index `11` is known. +2. As the commitment of block (state) index `11` is known, the block may be requested and obtained. After obtaining block + index `11` commitment of block index `10` is known. +3. Using block index `10` commitment the DB is checked to make sure that it is already present. +4. As block index `10` is already committed, block index `11` is committed. This makes state `11` present in the DB. +5. As state `11` is already committed, block index `12` is committed. This makes state `12` present in the DB and completes + the request. + +To obtain blocks, state manager sends requests to 5 other randomly chosen nodes. If the block is not received (either messages +got lost or these nodes do not have the requested block), 5 other randomly chosen nodes are queried. This process is repeated +until the block is received (usually from other node but may also be from this node's consensus) or the request is no longer +valid. + +If difference between state indexes of requested state and available in the DB state is large, this chain can get very long. +In order to limit its length, if requested block index is a) smaller than state index of snapshot, which was loaded on node +start, or b) smaller than largest state index among the pruned blocks (see [Pruning](#pruning)), the node panics. If this panicking +continues, the administrator may decide to delete the DB and start the node from (possibly configured) snapshot. + +## Block cache + +Block cache is in memory block storage. It keeps a limited amount (configured by `stateManager.blockCacheMaxSize`) of blocks +for limited amount of time (configured by `stateManager.blockCacheBlocksInCacheDuration`) to make the retrieval +quicker. E.g., in the last step of example of the previous section block index `12` must be committed. It is obtained in +the step 1, but as several steps of the algorithm are spread over time with requests to other nodes in between, and +several requests to obtain the same block may be present, it is not feasible to store it in request. However it would +be wasteful to fetch it twice on the same request. So the block is stored in cache in step 1 of the algorithm and +retrieved from cache later in the last step. + +The block is kept in the cache no longer that predetermined amount of time (configured by `stateManager.blockCacheBlocksInCacheDuration`). +If upon writing to cache blocks in cache limit is exceeded, block, which is in cache the longest, is removed from cache. + +## Block write ahead log (WAL) + +Upon receiving a block, its contents is dumped into a file and stored in a file system. The set of such files is WAL. + +The primary motivation behind creating it was in order not to deadlock the chain. Upon deciding on next state committee +nodes send the newest block to state manager and at the same time one of the nodes send the newest transaction to L1. +In an unfavourable chain of events it might happen that state managers of the committee nodes are not fast enough to commit +the block to the DB (see algorithm in [Obtaining blocks section](#obtaining-blocks)), before the node crashes. This leaves +the nodes in the old state as none of the nodes had time to commit the block. However the L1 reports the new state as +the latest although none of the nodes can be transferred to it. The solution is to put the block into WAL as soon as +possible so it won't be lost. + +Currently upon receiving the new confirmed block from node's consensus, state manager is sure that its predecessor is in the DB, +because consensus sends other requests before sending the new block, so WAL isn't that crucial any more. However, it is useful +in several occasions: + +1. Storing preliminary block, which is sent by consensus of other nodes. +2. When the node is catching up many states and block cache limit is too small to store all the blocks, WAL is used to avoid + fetching the same block twice. +3. In case of adding new node to the network to avoid catch up taking a lot of time when snapshots are not available, + the new node can be configured (`wal.loadToStore=true`) to load the DB with blocks from WAL on startup. WAL can be copied + from some other node. This is also true for any catch up over many states. + +## Pruning + +In order to limit the DB size, old states are deleted (pruned) from it on a regular basis. The amount of states to keep is +configured by two parameters: one in the configuration of the node (`stateManager.pruningMinStatesToKeep`) and one in the governance contract +(`BlockKeepAmount`). The resulting limit of previous states to keep is the larger of the two. Every time a block is committed +to the DB, states which are over the limit are pruned. However, to avoid freezing State manager for too long, no more than +`stateManager.pruningMaxStatesToDelete` blocks are pruned in a single run. The algorithm ensures that oldest states are pruned +first to avoid gaps between available states on the event of some failure. + +Pruning may be disabled completely via node configuration to make an archive node: node that contains all the state ever +obtained by the chain. Note, that such node will require a lot of resources to maintain: mainly disk storage. + +## Parameters + +### State manager + +The following parameters may be provided in section `stateManager`: + +- `blockCacheMaxSize`: the limit of the blocks in block cache. Default is 1k. +- `blockCacheBlocksInCacheDuration`: the limit of the time block stays in block cache. Default is 1 hour. +- `blockCacheBlockCleaningPeriod`: how often state manager should find and delete blocks, that stayed in block cache + for too long. Default is every minute. +- `stateManagerGetBlockRetry`: how often requests to retrieve the needed blocks from other nodes should be repeated. + Default is every 3 seconds. +- `stateManagerRequestCleaningPeriod`: how often state manager should find and delete requests, that are no longer valid. + Default is every second. +- `stateManagerTimerTickPeriod`: how often state manager should check if some maintenance (cleaning requests or block cache, + resending requests for blocks) is needed. Default is every second. There is no point in making this value larger than + any of `blockCacheBlockCleaningPeriod`, `stateManagerGetBlockRetry` or `stateManagerRequestCleaningPeriod`. +- `pruningMinStatesToKeep` : minimum number of old states to keep in the DB. Note that if `BlockKeepAmount` in + governance contract is larger than this value, then more old states will be kept. + Default is 10k. 0 (and below) disables pruning. +- `pruningMaxStatesToDelete`: maximum number of states to prune in one run. This is needed in order not to grab + state manager's time for pruning for too long. Default is 1k. + +### Snapshots + +The following parameters may be provided in section `snapshots`: + +- `snapshotsToLoad`: the comma sepparated list of `:` pairs, where chain `` must be started using snapshot with block hash ``. + The list can also contain `` entry. This hash will be used for other chains, which are not configured separately. There is + no point in having several `` or `:` entries with the same `` as only the last such entry is taken into + account. Note that if the chain is configured to start from some snapshot and the snapshot is not available (or another error occurs + during snapshot loading), the chain will start with an empty DB. The default is an empty list, which means that the newest available snapshot + will be loaded for every chain. +- `period`: how often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled". + Snapshots are disabled by default. +- `delay`: how many states to delay making the snapshot; it must be considerably smaller than `stateManager.pruningMinStatesToKeep`. + The default is 20. +- `localPath`: the path to the snapshots folder in this node's disk. Default is `waspdb/snap`. +- `networkPaths`: the comma-separated list of URLs that serve snapshots. The URLs may have the HTTP (e.g., `http://server.org/path/`) or the HTTPS + (e.g., `https://server.org/path/`) scheme for remote locations or a file path (e.g., `file://path/to/folder`) scheme for local snapshot locations. + The scheme is compulsory in the URL. The list is empty by default. + +### WAL + +The following parameters may be provided in section `wal`: + +- `loadToStore`: load blocks from WAL to the store on node start-up. This function is off (`false`) by default. +- `enabled`: whether the WAL is enabled. It is enabled by default. +- `path`: the path to the WAL folder. Default is `waspdb/wal`. diff --git a/docs/build/isc/v1.3/docs/explanations/states.md b/docs/build/isc/v1.3/docs/explanations/states.md new file mode 100644 index 00000000000..819068b9aaf --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/states.md @@ -0,0 +1,122 @@ +--- +description: 'The state of the chain consists of balances of native IOTA digital assets and a collection of key/value +pairs which represents use case-specific data stored in the chain by its smart contracts outside the UTXO ledger.' +image: /img/chain0.png +tags: + +- state +- transitions +- balances +- digital assets +- UTXO +- transitions +- explanation +--- + +# State, Transitions, and State Anchoring + +## State of the Chain + +The state of the chain consists of: + +- A ledger of accounts owning IOTA _digital assets_ (base tokens, native tokens, and NFTs). The chain acts as a custodian + for those funds on behalf of each account's owner. +- A collection of arbitrary key/value pairs (the _data state_) that contains use case-specific data stored by the smart + contracts in the chain. + +The chain's state is an append-only (immutable) _data structure_ maintained by the distributed consensus of its +validators. + +## Digital Assets on the Chain + +Each native L1 account in the IOTA UTXO ledger is represented by an address and controlled by an entity holding the +corresponding private/public key pair. +In the UTXO ledger, an account is a collection of UTXOs belonging to the address. + +Each ISC L2 chain has a L1 account, called the _chain account_, holding all tokens entrusted to the chain in a single +UTXO, the _state output_. +It is similar to how a bank holds all deposits in its vault. This way, the chain (the entity controlling the state +output) becomes a custodian for the assets owned by its clients, similar to how the bank’s client owns the money +deposited in the bank. + +The consolidated assets held in the chain are the _total assets on-chain_, which are contained in the state output of +the chain. + +The chain account is controlled by a _chain address_, also known as _chain ID_. +It is a special kind of L1 address, an _alias address_, which abstracts the controlling entity (the state controller +address) from the identity of the chain: the controlling entity of the chain may change, while the chain ID stays the +same. + +## The Data State + +The data state of the chain consists of a collection of key/value pairs. +Each key and each value are arbitrary byte arrays. + +In its persistent form, the data state is stored in a key/value database outside the UTXO ledger and maintained by the +validator nodes of the chain. +The state stored in the database is called the _solid state_. + +While a smart contract request is being executed, the _virtual state_ is an in-memory collection of key/value pairs that +can become solid upon being committed to the database. +An essential property of the virtual state is the possibility of having several virtual states in parallel as +candidates, with a possibility for one of them to be solidified. + +The data state has a state hash, a timestamp, and a state index. +The state hash is usually a Merkle root, but it can be any hashing function of all data in the data state. + +The data state hash and on-chain assets are contained in a single atomic unit on the L1 ledger: the state UTXO. +Each state mutation (state transition) of the chain is an atomic event that changes the on-chain assets and the data +state, consuming the previous state UTXO and producing a new one. + +## Anchoring the State + +The data state is stored outside the ledger, on the distributed database maintained by _validator_ nodes. +_Anchoring the state_ means placing the hash of the data state into the state UTXO and adding it to the L1 UTXO ledger. +The UTXO ledger guarantees that there is _exactly one_ such output for each chain on the ledger at every moment. +We call this output the _state output_ (or state anchor) and the containing transaction the _state transaction_ (or +anchor transaction) of the chain. +The state output is controlled (i.e., can be unlocked/consumed) by the entity running the chain. + +With the anchoring mechanism, the UTXO ledger provides the following guarantees to the IOTA Smart Contracts chain: + +- There is a global consensus on the state of the chain +- The state is immutable and tamper-proof +- The state is consistent (see below) + +The state output contains: + +- The identity of the chain (its L1 alias address) +- The hash of the data state +- The state index, which is incremented with each new state output + +## State Transitions + +The data state is updated by mutations of its key/value pairs. +Each mutation either sets a value for a key or deletes a key (and the associated value). +Any update to the data state can be reduced to a partially ordered sequence of mutations. + +A _block_ is a collection of mutations to the data state that is applied in a state transition: + +```go +next data state = apply(current data state, block) +``` + +The state transition in the chain occurs atomically in a L1 transaction that consumes the previous state UTXO and +produces the next one. The transaction includes the movement of the chain's assets and the update of the state hash, + +At any moment in time, the data state of the chain is a result of applying the historical sequence of blocks, starting +from the empty data state. + +![State transitions](/img/chain0.png) + +On the L1 UTXO ledger, the state's history is represented as a sequence (chain) of UTXOs, each holding the chain’s +assets in a particular state and the anchoring hash of the data state. +Note that not all the state's transition history may be available: due to practical reasons, older transactions may be +pruned in a snapshot process. +The only thing guaranteed is that the tip of the chain of UTXOs is always available (which includes the latest data +state hash). + +The ISC virtual machine (VM) computes the blocks and state outputs that anchor the state, which ensures that the state +transitions are calculated deterministically and consistently. + +![Chain](/img/chain1.png) diff --git a/docs/build/isc/v1.3/docs/explanations/validators.md b/docs/build/isc/v1.3/docs/explanations/validators.md new file mode 100644 index 00000000000..97ed59a19c0 --- /dev/null +++ b/docs/build/isc/v1.3/docs/explanations/validators.md @@ -0,0 +1,49 @@ +--- +description: Each chain is run by a network of validator nodes which run a consensus on the chain state update. +image: /img/logo/WASP_logo_dark.png +tags: + - validators + - validator nodes + - access nodes + - consensus + - state update + - explanation +--- + +# Validators + +Each chain is run by that chain's _committee of validators_. This committee owns a key that is split between all of its +validators. Each key share is useless on its own, but a collective signature gives validators complete control over the +chain. + +The committee of validators is responsible for executing the smart contracts in the chain and thus calculating a _state +update_. +All validators execute exactly the same code and reach a consensus on the state update. +Once the next state is computed and validated, it is committed to each validator's database, a new _block_ is added to +the chain (containing the state mutations), and the _state hash_ is saved in the L1 ledger. + +Depending on the governance model, chain owners can rotate the committee of validators. +By rotating the committee of validators, validators can be deleted, added, or replaced. + +ISC does not define how to select validators to form a committee: it could be a solitary choice of the chain's owner, or +it could be a public competition between candidates. +ISC does not define how validators are rewarded either. + +## Access Nodes + +It is possible to have some nodes act as _access nodes_ to the chain without being part of the committee of +validators. +All nodes in the subnet (validators and non-validators) are connected through statically assigned trust +relationships and each node is also connected to the IOTA L1 node to receive updates on the chain’s L1 +account. + +Any node can optionally provide access to smart contracts for external callers, allowing them to: + +- Query the state of the chain (i.e., _view calls_) +- Send off-ledger requests directly to the node (instead of sending an on-ledger request as a L1 transaction) + +It is common for validator nodes to be part of a private subnet and have only a group of access nodes exposed to the +outside world, protecting the committee from external attacks. + +The management of validator and access nodes is done through +the [`governance` core contract](../reference/core-contracts/governance.md). diff --git a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/compatibility.md b/docs/build/isc/v1.3/docs/getting-started/compatibility.mdx similarity index 70% rename from docs/build/isc/v1.0.0-rc.6/docs/getting-started/compatibility.md rename to docs/build/isc/v1.3/docs/getting-started/compatibility.mdx index 93168c9f134..2ffd0cbe144 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/getting-started/compatibility.md +++ b/docs/build/isc/v1.3/docs/getting-started/compatibility.mdx @@ -11,6 +11,7 @@ tags: - fees - reference --- +import QueryGasFees from '../_admonitions/_query_gas_fees.md'; # EVM Compatibility in IOTA Smart Contracts @@ -33,9 +34,8 @@ Here are some of the most important properties and limitations of EVM support in ### No Enforced Block Time -There is no guaranteed _block time_. A new EVM "block" will be created only when an ISC block is created, and ISC does -not enforce an average block time. This means that block times are variable; a new block will be created as soon as needed. -The average block time on [ShimmerEVM](/build/networks-endpoints#shimmerevm) is 2.8 seconds. +There is no guaranteed _block time_. A new EVM "_block_" will be created only when an ISC block is created, and ISC does +not enforce an average _block time_. This means that block times are variable; a new block will be created as soon as needed. ### The Magic Contract @@ -44,4 +44,9 @@ functionalities, introducing commands like `isc.send(...)` for token transfers. ### Gas Fees -Gas fees are set by the chain. +As in [Ethereum](https://ethereum.org/en/developers/docs/gas), gas fees depend on the current network usage. As in an +auction, if there is a high demand, users will compete and try to outbid each other's transactions. This means gas prices +increase in periods of high usage and decrease when the usage goes down. However, unlike Ethereum, the chain owner can set +the minimum gas fee. + + diff --git a/docs/build/isc/v1.3/docs/getting-started/languages-and-vms.md b/docs/build/isc/v1.3/docs/getting-started/languages-and-vms.md new file mode 100644 index 00000000000..1719a69053f --- /dev/null +++ b/docs/build/isc/v1.3/docs/getting-started/languages-and-vms.md @@ -0,0 +1,84 @@ +import EVMCompatibility from '../_admonitions/_EVM_compatibility.md' + +# Supported Virtual Machines & Languages + +The current release of IOTA Smart Contracts has support for [EVM/Solidity](#evmsolidity-based-smart-contracts) smart +contracts, as well as experimental [Wasm](#wasm-vm-for-isc) smart contracts, providing compatibility with +existing smart contracts and tooling from other EVM based chains like Ethereum. This allows us to offer the existing +ecosystem around EVM/Solidity a familiar alternative. + +## EVM Smart Contracts + +### What is EVM/Solidity? + +[EVM](https://ethereum.org/en/developers/docs/evm/) stands for "Ethereum Virtual Machine" and is currently the tried and +tested virtual machine running most smart contract networks. + +[Solidity](https://soliditylang.org/) is the programming language of choice for the EVM. It was created for this +specific purpose. + +The main benefit of using EVM/Solidity is its sheer amount of resources from years of development. The IOTA +Smart Contracts implementation is fully compatible with all of them. If you have experience developing on other EVM based chains, you will feel right at home. Any existing contracts you've written will need no +changes to function on IOTA Smart Contracts. + +### How IOTA Smart Contracts Work With EVM + +Every deployed ISC chain automatically includes a core contract +called [`evm`](../reference/core-contracts/evm.md). This core contract is responsible for running EVM code and +storing the EVM state. + +The Wasp node also provides a standard JSON-RPC service, which allows you to interact with the EVM layer using existing +tooling like [MetaMask](https://metamask.io/), [Remix](https://remix.ethereum.org/) or [Hardhat](https://hardhat.org/). +Deploying EVM contracts is as easy as pointing your tools to the JSON-RPC endpoint. + + + +## Wasm VM for ISC + +:::warning Experimental + +The Wasm _VM_ is in experimental state, showcasing ISC's "VM plugin" architecture. + +Experiment but avoid using it for production applications; opt for [EVM](quick-start.mdx). + +::: + +IOTA Smart Contracts (ISC) provide a sandboxed environment through an API, facilitating secure and deterministic +interactions with ISC functions. This API supports any Virtual Machine (VM) aiming to build a system for smart contract + code execution on ISC. + +![Wasp node ISC Host](/img/wasm_vm/IscHost.png) + +You can use a [WebAssembly (Wasm)](https://webassembly.org/) VM as a compilation target, facilitated by the open-source +[Wasmtime runtime](https://wasmtime.dev/). This setup encourages dynamic smart contract operations compiled to Wasm code, +promoting security and adaptability with different programming languages. + +![Wasm VM](/img/wasm_vm/WasmVM.png) + +The Wasm VM operates with self-contained `WasmLib` libraries linked to individual Wasm codes, optimizing the ISC sandbox +functionality and smart contract state storage access. + +### Supported Functionalities + +The ISC sandbox environment offers: + +- Smart contract metadata and state data access. +- Request data retrieval for function calls. +- Token management within the contract. +- Utility functions from the host. +- Smooth initiation of other smart contract functions. +- Logging facility. + +### Supported Languages + +The WasmLib started with [Rust](https://www.rust-lang.org/) support, expanding to include [Go](https://golang.org/) +and [TypeScript](https://www.typescriptlang.org/) with the help of respective Wasm code generators: + +| Language | Wasm code generator | +|------------|----------------------------------------------------| +| Go | [TinyGo](https://tinygo.org/) | +| Rust | [wasm-pack](https://rustwasm.github.io/wasm-pack/) | +| TypeScript | [AssemblyScript](https://www.assemblyscript.org/) | + +These generators maintain a common subset of their host language, aiming for a unified coding style to simplify the +initiation into smart contract creation, welcoming developers with a C-style language background to quickly adapt. \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/getting-started/networks-and-chains.mdx b/docs/build/isc/v1.3/docs/getting-started/networks-and-chains.mdx new file mode 100644 index 00000000000..ca5d667d66b --- /dev/null +++ b/docs/build/isc/v1.3/docs/getting-started/networks-and-chains.mdx @@ -0,0 +1,92 @@ +--- +description: Networks and endpoints in the IOTA ecosystem. +tags: + - mainnet + - shimmer + - devnet + - EVM Testnet + - reference + - Endpoints +--- +import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import { Networks } from '@theme/constant'; +import NetworkInfo from '@theme/NetworkInfo'; + +# Networks & Chains +## IOTA EVM Testnet + + + +[The IOTA EVM Testnet](https://explorer.evm.testnet.iotaledger.net/) runs as a layer 2 on top +of the [IOTA Testnet](/build/networks-endpoints#iota-testnet). This network uses ISC to facilitate +an Ethereum Virtual Machine and has an enshrined bridge to layer 1. + +:::info + +This network is subject to occasional resets (no data retention) which are usually announced with a one-week grace period. + +::: + + + +:::note + +The other values (network name and currency symbol) can be whatever value you like. + +::: + +## IOTA EVM + +[IOTA EVM](https://explorer.evm.iota.org) is the L2 EVM running on top of the IOTA network. + + + + + +### Additional Info + + + +## ShimmerEVM Testnet + + + +[The ShimmerEVM Testnet](https://explorer.evm.testnet.shimmer.network/) runs as a layer 2 on top +of the [Shimmer Testnet](/build/networks-endpoints#shimmer-testnet). This network uses ISC to facilitate +an Ethereum Virtual Machine and has an enshrined bridge to layer 1. + +:::info + +This network is subject to occasional resets (no data retention) which are usually announced with a one-week grace period. + +::: + + + +:::note + +The other values (network name and currency symbol) can be whatever value you like. + +::: + +### Additional Info + + + +## ShimmerEVM + +[ShimmerEVM](https://explorer.evm.shimmer.network/) is the L2 EVM running on top of the Shimmer network. + + + + + +### Additional Info + + + +## Core Contracts + +[IOTA EVM](#IOTAEVM), [ShimmerEVM](#shimmerEVM) and the testnet networks have 7 +[core contracts](../reference/core-contracts/overview.md) deployed, as well as the +[Magic Contract](../reference/magic-contract/introduction.md). diff --git a/docs/build/isc/v1.3/docs/getting-started/quick-start.mdx b/docs/build/isc/v1.3/docs/getting-started/quick-start.mdx new file mode 100644 index 00000000000..01601ba1d50 --- /dev/null +++ b/docs/build/isc/v1.3/docs/getting-started/quick-start.mdx @@ -0,0 +1,83 @@ +--- +description: This guide will help you quickly get started with the EVM +image: /img/logo/WASP_logo_dark.png +tags: + - quickstart + - developer + - using + - EVM + - Ethereum + - Solidity + - metamask + - JSON + - RPC +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import Link from '@docusaurus/Link'; + +# EVM Quickstart Guide + +This guide will help you quickly get started with our EVM, where you can deploy and interact with EVM-compatible smart contracts. + +## Prerequisites + +- [MetaMask](https://metamask.io/) browser extension installed + +## Setup MetaMask + +Click this button: + + + +:::tip + +Please read [the MetaMask section in the tools guide](tools.mdx#metamask) for a detailed guide. + +::: + +## Deploy and Interact with Smart Contracts + +:::tip Fund your testnet account + +If you are using one of the testnets you can just use the the toolkit to get testnet tokens. + +1. Go to the [IOTA EVM](https://evm-toolkit.evm.testnet.iotaledger.net) or [ShimmerEVM](https://evm-toolkit.evm.testnet.shimmer.network/) Testnet Toolkit. +2. Connect your MetaMask wallet by clicking "Connect Wallet" or paste an EVM address. +3. Select the account you want to receive testnet tokens. +4. Click "Send funds" to get testnet tokens. + +::: + +You can now deploy and interact with smart contracts. Utilize popular development tools and frameworks, such as [Hardhat](https://hardhat.org/), or [Remix](https://remix.ethereum.org/), to build, test, and deploy your smart contracts. + + + +## Explore the Network + +Visit the corresponding Block Explorer to monitor the chain, track transactions, and explore deployed smart contracts. + + + +Explorer + + +Explorer + + +Explorer + + +Explorer + + + +## Additional Resources + +- [GitHub issues page for Wasp](https://github.com/iotaledger/wasp/issues) +- [Firefly](https://firefly.iota.org) + +With this quickstart guide, you should now be able to set up and start exploring the EVM. As you begin to deploy and interact with smart contracts, remember to provide feedback on any issues or improvements you discover to help make our EVM even better. Happy developing! diff --git a/docs/build/isc/v1.3/docs/getting-started/tools.mdx b/docs/build/isc/v1.3/docs/getting-started/tools.mdx new file mode 100644 index 00000000000..4e09788a54e --- /dev/null +++ b/docs/build/isc/v1.3/docs/getting-started/tools.mdx @@ -0,0 +1,189 @@ +--- +description: 'Existing EVM tooling is compatible and can be used directly with an IOTA Smart Contracts chain running EVM. +You can configure hardhat, metamask, remix, Ether.js and Web3.js among others.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- chain +- EVM +- Solidity +- tooling +- wasp-cli +- hardhat +- metamask +- JSON-RPC +- reference + +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import HardhatConfig from '../_partials/_hardhat_config.md'; +import { Networks } from '@theme/constant'; +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import { ChainId } from '@theme/ChainId'; +import NetworkInfo from '@theme/NetworkInfo'; +import OraclesContractData from '../../../../_partials/_oracles_contract_data.mdx'; + +# Compatible Tools + +EVM on IOTA Smart Contracts has been integrated in a way that the existing EVM tooling is compatible and can be used +directly with an IOTA Smart Contracts chain running EVM as long as you take a couple of things into account. + +## Tooling Considerations + +1. Please make sure you use the correct JSON-RPC endpoint URL in your tooling for your chain. If you're running your own chain, you can find the JSON-RPC +endpoint URL in the Wasp dashboard (`[URL]/wasp/dashboard` when using `node-docker-setup`). +2. Please ensure you use the correct `Chain ID` configured while starting the JSON-RPC service. If you did not explicitly define this while starting the service, the default Chain ID will be +for IOTA EVM, +for ShimmerEVM or for the EVM Testnet. +3. Fees are handled on the IOTA Smart Contracts chain level, not the EVM level. The chain will reject any requests with a different gas price than specified by the chain. + +:::caution + +Re-using an existing Chain ID is not recommended and can be a security risk. For production usage, register a unique Chain +ID on [Chainlist](https://chainlist.org/) and use that instead of the default. **It is not possible to change the EVM +chain ID after deployment.** + +::: + +## Network RPCs + + + + + + + + + + + + + + + + + + + + +## IOTA EVM Tools + +The following tools are **only available on IOTA EVM**. + +### Blast API + +The [Blast API](/build/blastAPI) is a decentralized platform that provides reliable and scalable node infrastructure +for accessing blockchain data. You can find the Blast API URLs in the [Network RPCs](#network-rpcs) + +### EVM Toolkit + +You can use the [IOTA EVM Toolkit](https://evm-toolkit.evm.iotaledger.net) to withdraw assets from IOTA EVM to IOTA L1. +It also includes a wrapper IOTA <-> wIOTA. + +### Multicall3 + +If you need to aggregate results from multiple contract reads into a single JSON-RPC request or execute multiple +state-changing calls in a single transaction, you can use the [Multicall3 contract](https://explorer.evm.iota.org/address/0xcA11bde05977b3631167028862bE2a173976CA11?tab=contract). + +## IOTA EVM and ShimmerEVM Tools + +The following tools are available on both IOTA EVM end ShimmerEVM. + +### MultiSig Wallets + +If you require and additional level of security, you can use the [Safe{} Wallet](https://safe.iotaledger.net/) as a +Multisig solution on IOTA EVM. + +### Oracles + +If your project requires [Oracles](/build/oracles/) to provide data from the outside world, you find both Pyth and Supra have integrated IOTA EVM. + + + +### Subgraphs + +[Subgraphs](/build/subgraphs/) provide a streamlined way for developers to access blockchain data relevant to their applications, +significantly enhancing developer efficiency and user experience. IOTA EVM subgraphs available via [Goldsky](https://goldsky.com). + +## MetaMask + +[MetaMask](https://metamask.io/) is a popular EVM wallet which runs in a browser extension that allows you to +interact with EVM chains and their applications (dApps). + +To use your EVM chain with MetaMask, simply open up MetaMask and click on the network drop-down list at the very top. At +the bottom of this list, you will see the option `Add network`. On the new page you will see a list of popular network with the option `Add a network manually`. +For example this would be the configs to add our different [EVM chains](/build/networks-endpoints): + + + + + + + + + + + + + + + + + + + + +Ensure that your `RPC Url` and `Chain ID` are set correctly and match the dashboard values. The `Network Name` can be +whatever you see fit. Click "Save" to add the chain to MetaMask. + +If you wish to use additional EVM chains with Metamask, you can add more Custom RPC networks, as long as they have a +unique `Chain ID` and `RPC Url`. Once you have done this, you can start using MetaMask to manage your EVM wallet or +issue/sign transactions with any dApp running on that network. + +### Remix + +If you also want to use the [Remix IDE](https://remix.ethereum.org/) to deploy any regular Solidity Smart Contract, you +should set the environment as **Injected Provider - Metamask**, which should then connect with your MetaMask wallet. + +Click on the _Deploy & Run transactions_ button in the menu on the left and select `Injected Web3` from +the `Environment` dropdown. + +![Select Injected Provider from the Environment dropdown](/img/evm/remix-injected-provider-metamask.png) + + + +Metamask will ask to connect to Remix, and once connected, it will set the `Environment` to `Injected Web3` with +the "Custom (Chain ID) network". + +![Environment will be set to Injected Web3](/img/evm/remix-injected-provider-set.png)] + +## Hardhat + +[Hardhat](https://hardhat.org/) is a command line toolbox that allows you to deploy, test, verify, and interact with +Solidity smart contracts on an EVM chain. EVM chains running on IOTA Smart Contracts are compatible with Hardhat; simply +make sure you add the correct network parameters to your `hardhat.config.js`, for example: + + + + + +:::caution + +Currently, there is no validation service available for EVM/Solidity smart contracts on IOTA Smart Contracts, which is +often offered through block explorer APIs. + +::: + +## Ethers.js/Web3.js + +If you input the correct configuration parameters for the JSON-RPC endpoint to talk to, +[Ethers.js](https://docs.ethers.io/) and [Web3.js](https://web3js.readthedocs.io/) are also compatible with EVM chains on IOTA Smart Contracts. +Alternatively, you can let both interact through MetaMask instead so that it uses the +network configured in MetaMask. For more information on this, read their documentation. + +## Other Tooling + +Most tools available will be compatible if you enter the correct `Chain ID` and `RPC Url`. diff --git a/docs/build/isc/v1.3/docs/how-tos/ERC20.md b/docs/build/isc/v1.3/docs/how-tos/ERC20.md new file mode 100644 index 00000000000..adf0a6ccfa1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/ERC20.md @@ -0,0 +1,94 @@ +--- +description: Solidity smart contract ERC20. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - EVM + - Solidity + - ERC20 + - eip-20 + - token creation + - mint tokens + - how to +--- + +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import PriorKnowledge from '../_admonitions/_EVM-required-prior-knowledge.md'; +import RemixIDE from '../_admonitions/_remix-IDE.md'; + +# Create ERC20 Custom Tokens + +## Required Prior Knowledge + + + +## About ERC20 + +ERC20 is a standard for fungible tokens and is defined in +the [EIP-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20) by Ethereum. + +With the ERC20 standard, you can create your own tokens and transfer them to the EVM on IOTA Smart Contracts without +fees. + + + +## 1. Create the Smart Contract + +Create a new Solidity file, for example, `ERC20.sol` in the contracts folder of +your [Remix IDE](https://remix.ethereum.org/) and add this code snippet: + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.7; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ExampleERC20Token is ERC20 { + constructor() ERC20("ExampleERC20Token", "EET") { + _mint(msg.sender, 1000000 * 10 ** decimals()); + } +} +``` + +This imports all functions from the [OpenZeppelin ERC20](https://docs.openzeppelin.com/contracts/4.x/erc20) smart +contract and creates a new ERC20 token with your name and Symbol. + +:::tip OpenZeppelin + +OpenZeppelin provides many audited smart contracts and is a good point to start and learn. + +::: + +:::note Customize Your Token + +You can change the token name `ExampleERC20Token` and the token symbol `EET` for anything you want. + +::: + + + +## 2. Add Your Custom Tokens to MetaMask + +Once you have deployed your contract, you can add your new custom token to your Metamask account. + +1. Open Metamask, and click on the transaction that created the contract. From there, you can simply click + on `View on block explorer` to visit the transaction details. Alternatively, you can copy the transaction ID and + visit the [IOTA EVM Explorer](https://explorer.evm.iota.org), + [ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) + or [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) and use the search bar to find transaction. + +!['View on block explorer](/img/evm/how-tos/ERC20/metamask-get-transaction-or-go-to-block-explorer.png) + +2. Copy the contract address from the transaction details, and import your custom ERC20 tokens into MetaMask. + +![Copy contract address](/img/evm/how-tos/ERC20/metamask-import-tokens.png) + +## 3. Have some Fun + +Now you should see your token in MetaMask. You can send them to your friends without any fees or gas costs. + +![Copy contract address](/img/evm/how-tos/ERC20/metamask-erc20-balance.png) + +You also can ask in the [Discord Chat Server](https://discord.iota.org) to send them around and discover what the +community is building on IOTA Smart Contracts. diff --git a/docs/build/isc/v1.3/docs/how-tos/ERC721.md b/docs/build/isc/v1.3/docs/how-tos/ERC721.md new file mode 100644 index 00000000000..767661dbff2 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/ERC721.md @@ -0,0 +1,129 @@ +--- +description: Create and deploy a Solidity smart contract to mint NFTs using the ERC721 standard. +image: /img/evm/ozw-721.png +tags: + - smart contracts + - EVM + - Solidity + - ERC721 + - eip-721 + - token creation + - mint tokens + - how to +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; +import PriorKnowledge from '../_admonitions/_EVM-required-prior-knowledge.md'; +import RemixIDE from '../_admonitions/_remix-IDE.md'; + +# Create ERC721 NFTs + +:::info EVM-only NFT + +Please keep in mind that this is an EVM-only NFT. It's not tied to L1 native assets. Also, these are different from L1 +NFTs. + +::: + + + +## About ERC721 + +Non-fungible tokens or NFTs are a type of token that can represent any unique object, including a real-world asset on a +decentralized network. NFTs are commonly represented by the ([ERC721 standard](https://eips.ethereum.org/EIPS/eip-721)). +You can use the +openzepplin +lib [`@openzeppelin/contracts/token/ERC721/ERC721.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) +to streamline your development experience. + +You can also use the ([OpenZepplin Contracts Wizard](https://wizard.openzeppelin.com/#erc721)) to generate and customize +your smart contracts. + + + +## Create the Smart Contract + +The following is an example NFT Smart Contract called "IotaEVMSampleNFT". + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts@5.0.1/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts@5.0.1/access/Ownable.sol"; + +contract IotaEVMSampleNFT is ERC721, Ownable { + uint256 private _nextTokenId; + + constructor(address initialOwner) + ERC721("IotaEVMSampleNFT", "SSNFT") + Ownable(initialOwner) + {} + + function _baseURI() internal pure override returns (string memory) { + return "https://example.com/nft/"; + } + + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } +} +``` + +As you can see above, the contract uses standard methods for the most part. You should pay attention to the following: + +- `pragma solidity ^0.8.20;`: This line means the contract uses solidity compiler version `0.8.20` or above. +- `contract IotaEVMSampleNFT is ERC721, ERC721URIStorage, Ownable`: This line defines the contract's name, and what + other contracts it implements. +- `ERC721("IotaEVMSampleNFT", "SNFT") {}`: This line defines the token name and symbol. You can name it + whatever you want. We recommend using the same name for the token and the contract. +- `return "https://example.com/nft/";`: You should define the base URI of your NFTs. That means the URL you provide here + will be used for all your tokens. Since this contract uses auto-incremental token IDs, your token URI will look + something like `https://example.com/nft/0`, `https://example.com/nft/1`, `https://example.com/nft/2`, and so on. +- `function safeMint(address to, string memory uri) public onlyOwner {`: The `safeMint` function will + require that you manually input a token's `to` address and a `uri` every time you want to mint. This should work for + regular use cases. + +### Customize on OpenZeppelin + +You can customize your contract depending on how you want it to behave. You should consider the following topics +and questions: + +1. **Ownership** — Who owns it? How is it stored? +2. **Creation** — Method or Type of Creation. +3. **Transfer & Allowance** — How will tokens be transferred? How will they be available to other addresses and + accounts? +4. **Burn** — Do you want to destroy it? If yes, how? + +You can click on `Copy to Clipboard` and paste it into the IDE of your choice, download it, or click on `Open in Remix` +directly. + + +:::note Set the Initial Owner + +Before you can deploy this contract, you will need to set the `Initial Owner` address; this can be your own IOTA EVM address. + +!["Set the initial owner" img.png](/img/evm/how-tos/ERC721/set-initial-owner.png) + +::: + + + +### Mint Your Custom NFTs + +So far, you have [created](#create-the-smart-contract) and deployed the contract. But, you probably want to mint some NFTs. +To do, you should: + +1. Open the contract (listed under `Deployed Contracts`). +2. Insert your target IOTA EVM in beside the `safeMint` button and then click the button. + + ![Safe mint](/img/evm/how-tos/ERC721/safe-mint.png) + +3. Confirm the transaction on Metamask. + + ![Confirm in metamask](/img/evm/how-tos/ERC721/confirm-in-metamask.png) + +If you visit your address in the visit the [IOTA EVM Explorer](https://explorer.evm.iota.org), +[ShimmerEVM Explorer](https://explorer.evm.testnet.shimmer.network/) or [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/) +you should see your NFTs listed under `Tokens`. + diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/allow.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/allow.md new file mode 100644 index 00000000000..edf7027f439 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/allow.md @@ -0,0 +1,64 @@ +--- +description: How to allow native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allow + - allowance + - EVM + - magic + - solidity +--- + +# Allow + +The allowance concept is well known from the EVM contracts like ERC20. +In ISC, we have a similar concept for our native assets. You might want to use this, for example, to [send native assets to L1](../send-assets-to-l1.mdx) (which includes sending tokens to other L1 chain accounts). + +## Example Code + +### 1. Create the `allow` Function + +Create a function which allows an address or contract to access a specific ID of your account: + +```solidity +function allow(address _address, bytes32 _allowanceNFTID) public { +``` + +### 2. Create the `ISCAssets` object + +Create an `ISCAssets` object to pass as allowance: + +```solidity +NFTID[] memory nftIDs = new NFTID[](1); +nftIDs[0] = NFTID.wrap(_allowanceNFTID); +ISCAssets memory assets; +assets.nfts = nftIDs; +``` + +### 3. Use the Assets as Allowance + +With that asset, you can call `allow` to allow address to take our NFT: + +```solidity +ISC.sandbox.allow(_address, assets); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract Allowance { + function allow(address _address, bytes32 _allowanceNFTID) public { + NFTID[] memory nftIDs = new NFTID[](1); + nftIDs[0] = NFTID.wrap(_allowanceNFTID); + ISCAssets memory assets; + assets.nfts = nftIDs; + ISC.sandbox.allow(_address, assets); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/get-allowance.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/get-allowance.md new file mode 100644 index 00000000000..353df44011c --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/get-allowance.md @@ -0,0 +1,79 @@ +--- +description: How to get the allowance of native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allowance + - EVM + - magic + - solidity +--- + +# Get Allowance + +## Example Code + +There are multiple ways to check for an allowance. + +### `getAllowanceFrom()` + +`getAllowanceFrom()` fetches the funds currently allowed by the given address to the caller: + +```soliditiy +function getAllowanceFrom(address _address) public { + ISCAssets assets = ISC.sandbox.getAllowanceFrom(_address); + emit AllowanceFrom(assets) +} +``` + +### `getAllowanceTo()` + +`getAllowanceTo()` fetches the funds currently allowed by the caller to the given address: + +```soliditiy +function getAllowanceTo(address _target) public { + ISCAssets assets = ISC.sandbox.getAllowanceTo(_target); + emit AllowanceTo(assets) +} +``` + +### `getAllowance()` + +`getAllowance()` gets the funds currently allowed between the given addresses: + +```soliditiy +function getAllowance(address _from, address _to) public { + ISCAssets assets = ISC.sandbox.getAllowance(_from, _to); + emit Allowance(assets) +} +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract allowance { + event AllowanceFrom(ISCAssets assets) + event AllowanceTo(ISCAssets assets) + event Allowance(ISCAssets assets) + + function getAllowanceFrom(address _address) public { + ISCAssets assets = ISC.sandbox.getAllowanceFrom(_address); + emit AllowanceFrom(assets) + } + + function getAllowanceTo(address _target) public { + ISCAssets assets = ISC.sandbox.getAllowanceTo(_target); + emit AllowanceTo(assets) + } + + function getAllowance(address _from, address _to) public { + ISCAssets assets = ISC.sandbox.getAllowance(_from, _to); + emit Allowance(assets) + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/take-allowance.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/take-allowance.md new file mode 100644 index 00000000000..b41689fb898 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/allowance/take-allowance.md @@ -0,0 +1,56 @@ +--- +description: How to take the allowance of native assets and base token +image: /img/logo/WASP_logo_dark.png +tags: + - allowance + - EVM + - magic + - solidity +--- + +# Take allowed Funds + +After having [allowed](./allow.md) native assets, you can take the ones you need. + +## Example Code + +The following example will take the NFT which was allowed in the [allow how-to guide](./allow.md). + +### Create the `ISCAssets` + +First, you need to recreate the `ISCAssets` with the NFTID. + +```solidity +NFTID[] memory nftIDs = new NFTID[](1); +nftIDs[0] = NFTID.wrap(_allowanceNFTID); +ISCAssets memory assets; +assets.nfts = nftIDs; +``` + +### Call `takeAllowedFunds()` + +After that, you can call `takeAllowedFunds()` to take the allowance of the specified address/contract + +```solidity +ISC.sandbox.takeAllowedFunds(_address, NFTID); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract allowance { + function takeAllowedFunds(address _address, bytes32 NFTID) { + NFTID[] memory nftIDs = new NFTID[](1); + nftIDs[0] = NFTID.wrap(_allowanceNFTID); + ISCAssets memory assets; + assets.nfts = nftIDs; + ISC.sandbox.takeAllowedFunds(_address, NFTID); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/get-balance.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/get-balance.md new file mode 100644 index 00000000000..8ab06fafb02 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/get-balance.md @@ -0,0 +1,74 @@ +--- +description: How to get the balance of L1 assets on L2 +image: /img/logo/WASP_logo_dark.png +tags: + - native assets + - balance + - EVM + - how-to +--- + +# Get Balance + +Once you have your L1 assets on L2, you might want to check their balance. This guide explains how to do so by calling the three functions `getL2BalanceBaseTokens`, `getL2BalanceNativeTokens`and `getL2NFTAmount` for the corresponding token types. + + +## Example Code + +1. Get the [AgentID](../../../explanations/how-accounts-work.md) from the sender by calling `ISC.sandbox.getSenderAccount()`. + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +2. To get the base token balance, you can call `getL2BalanceBaseTokens` using the `agentID`. + +```solidity +uint64 baseBalance = ISC.accounts.getL2BalanceBaseTokens(agentID); +``` + +3. To get the native token balance of a specific `NativeTokenID`, use `ISC.accounts.getL2BalanceNativeTokens` with the `id` and `agentID`. + +```solidity +NativeTokenID memory id = NativeTokenID({ data: nativeTokenID}); +uint256 nativeTokens = ISC.accounts.getL2BalanceNativeTokens(id, agentID); +``` + +4. To get the number of NFTs, use `ISC.accounts.getL2NFTAmount` with the `agentID`. + +```solidity +uint256 nfts = ISC.accounts.getL2NFTAmount(agentID); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract GetBalance { + event GotAgentID(bytes agentID); + event GotBaseBalance(uint64 baseBalance); + event GotNativeTokenBalance(uint256 nativeTokenBalance); + event GotNFTIDs(uint256 nftBalance); + + function getBalance(bytes memory nativeTokenID) public { + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + emit GotAgentID(agentID.data); + + uint64 baseBalance = ISC.accounts.getL2BalanceBaseTokens(agentID); + emit GotBaseBalance(baseBalance); + + NativeTokenID memory id = NativeTokenID({ data: nativeTokenID}); + uint256 nativeTokens = ISC.accounts.getL2BalanceNativeTokens(id, agentID); + emit GotNativeTokenBalance(nativeTokens); + + uint256 nfts = ISC.accounts.getL2NFTAmount(agentID); + emit GotNFTIDs(nfts); + } +} +``` + diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx new file mode 100644 index 00000000000..a479d9bb2c1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/basics/send-assets-to-l1.mdx @@ -0,0 +1,70 @@ +--- +description: The ISC Magic Contract allows EVM contracts to access ISC functionality. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - magic + - Ethereum + - Solidity +--- + +import AboutAccounts from '../../../_admonitions/_about-accounts.md'; + +# Send Assets and Tokens to L1 + + + +:::info + +IOTA EVM and ShimmerEVM have 18 decimal places, while IOTA and Shimmer have 6. This means that any decimals beyond the 6th will be ignored by IOTA and Shimmer, even though you can see them on IOTA EVM and ShimmerEVM. Please keep this in mind while sending your tokens to L1. + +::: + +This guide will show you how to use the ISC sandbox interface to send assets from L2 to L1. This includes base tokens, native tokens, and NFTs. Before you can send these assets, you need to know how you get them on L2 and how you allow a contract to use them. + +Note that assets on L1 require a storage deposit; therefore, the number of base tokens sent to L1 should cover at least the storage deposit required to hold the assets on L1. + +## Explanation + +First, you will find out what assets this contract is allowed to take from the caller by calling the `ISC.sandbox.getAllowanceFrom()` function. + +```solidity +ISCAssets memory allowance = ISC.sandbox.getAllowanceFrom(msg.sender); +``` + +Then you take the allowance, which will transfer the assets from the caller to the contract. + +```solidity +ISC.sandbox.takeAllowedFunds(msg.sender, allowance); +``` + +Finally, you can send the assets to the specified L1 address. This will create an output to hold said assets. You can use additional options to add the [timelock](/learn/protocols/stardust/core-concepts/output-unlock-conditions/#timelock) and [expiration](/learn/protocols/stardust/core-concepts/output-unlock-conditions/#expiration) unlock conditions to the output. + +```solidity +ISCSendMetadata memory metadata; +ISCSendOptions memory options; +ISC.sandbox.send(to, allowance, false, metadata, options); +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract L1Assets { + function withdraw(L1Address memory to) public { + ISCAssets memory allowance = ISC.sandbox.getAllowanceFrom(msg.sender); + ISC.sandbox.takeAllowedFunds(msg.sender, allowance); + + ISCSendMetadata memory metadata; + ISCSendOptions memory options; + ISC.sandbox.send(to, allowance, false, metadata, options); + } +} +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/call-view.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/call-view.md new file mode 100644 index 00000000000..d66fe7c9726 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/call-view.md @@ -0,0 +1,96 @@ +--- +description: With call and callView you can interact with any core contract +image: /img/logo/WASP_logo_dark.png +tags: + - magic contract + - core + - EVM + - Ethereum + - Solidity + - ISC +--- + +# Interact with any Core contract + +## About `call` and `callView` + +The magic contract provides you with a solidity interface to the core contracts. Some functions like [`getL2BalanceBaseTokens`](../../reference/magic-contract/ISCAccounts.md#getl2balancebasetokens) are wrapped in the magic contract directly, others you need to call yourself. You can do that with the [`call`](../../reference/magic-contract/ISCSandbox.md#call) and [`callView`](../../reference/magic-contract/ISCSandbox.md#callview) functions. + +:::info WASM + +You can also use `call` and `callView` to interact with WASM contracts. + +::: + +## Example Code + +1. Get the [`AgentID`](../../explanations/how-accounts-work.md) from the sender by calling ISC.sandbox.getSenderAccount(). + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +2. Initialize the parameters for the call by creating a new [`ISCDict`](../../reference/magic-contract/ISCTypes.md#iscdict). As you can see in the docs, [`getl2balancenativetokens`](../../reference/magic-contract/ISCAccounts.md#getl2balancenativetokens) takes two parameters.: the Agent ID and the native token ID. So, you have to create a dictionary with two key-value pairs. The key of the first pair (Agent ID) has to be `a` and the key for the second pair (native token ID) `N`. + +```solidity +ISCDict memory params = ISCDict(new ISCDictItem[](2)); +params.items[0] = ISCDictItem("a", agentID.data); +params.items[1] = ISCDictItem("N", nativeTokenID); +``` + +3. Now, you can use [`callView`](../../reference/magic-contract/ISCSandbox.md#callview) to call our contract. The first parameter is the core contract `hname`, which we can get with the helper utility [`hn`](../../reference/magic-contract/ISCUtil.md#hn), and the second parameter is the function we want to call. The last parameter is the dictionary with all function parameters. + +```solidity +ISCDict memory result = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("balanceNativeToken"), + params +); +``` + +4. Next, you can either return or emit the result. + +```solidity +emit NativeTokenBalance(bytesToUint(result.items[0].value)); +``` + +:::info Return Dictionary + +Keep in mind that the call and callView functions will always return a dictionary. The values of this dictionary are always of type byte, so you need to take care of converting it yourself. + +::: + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract NativeTokenBalance { + event NativeTokenBalance(uint balance); + + function getNativeTokenBalance(bytes memory nativeTokenID) public { + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + + ISCDict memory params = ISCDict(new ISCDictItem[](2)); + params.items[0] = ISCDictItem("a", agentID.data); + params.items[1] = ISCDictItem("N", nativeTokenID); + + ISCDict memory result = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("balanceNativeToken"), + params + ); + + emit NativeTokenBalance(bytesToUint(result.items[0].value)); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/get-randomness-on-l2.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/get-randomness-on-l2.md new file mode 100644 index 00000000000..3bf4b3b35e1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/get-randomness-on-l2.md @@ -0,0 +1,127 @@ +--- +description: You can use the ISC Magic Contract in EVM contracts to access ISC functionality, such as randomness. +image: /img/logo/WASP_logo_dark.png +tags: + - magic contract + - randomness + - EVM + - Ethereum + - Solidity + - ISC +--- + +# Get Randomness on L2 + +ISC introduces a feature not found on many other smart contract protocols: randomness. + +In the ISC protocol, for each state update, each validator proposes a batch of smart contract requests that they would like to process next. They commit to their proposals with a signature, after which a common subset of requests is found, and a combined signature is produced. + +This combined signature is unpredictable, and not only serves as protection against MEV by pseudo-randomly ordering requests, but also provides a source of verifiable entropy for randomness on L2. + +This guide will show you how you can use this entropy to generate random values in your contracts. + +:::info A note about entropy + +While entropy is random for each smart contract request, entropy is constant within a request. This means multiple calls to get entropy within the same request will return the same value. + +::: + +## Explanation + +When you want to generate multiple random values within a single request, you need to take into account that entropy is constant within a request. In this contract we use an increasing nonce in addition to the entropy, to make sure we are generating unique values: + +```solidity +uint256 private _nonce; + +function getNonce() internal returns (bytes32) { + return bytes32(_nonce++); +} +``` + +### Generating Integers + +To then generate a random integer, you can take the entropy and a unique nonce and hash them together: + +```solidity +bytes32 entropy = ISC.sandbox.getEntropy(); +bytes32 nonce = getNonce(); +bytes32 digest = keccak256(bytes.concat(entropy, nonce)); +``` + +And then cast the digest to an integer: + +```solidity +uint256 value = uint256(digest); +``` + +### Generating bytes + +Similarly to generating a random integer, you can generate any sequence of random bytes by taking the entropy and a unique nonce and hash them together: + +```solidity +bytes32 entropy = ISC.sandbox.getEntropy(); +bytes32 nonce = getNonce(); +bytes32 digest = keccak256(bytes.concat(entropy, nonce)); +``` + +And then repeatidly hash the digest and copy it in a sequence of bytes until you reach the required length. + +```solidity +bytes memory value = new bytes(length); +for (uint i = 0; i < length; i += 32) { + digest = keccak256(bytes.concat(digest)); + for (uint j = 0; j < 32 && i + j < length; j++) { + value[i + j] = digest[j]; + } +} +``` + +## Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract Random { + event Int(uint256); + event Bytes(bytes); + + uint256 private _nonce; + + function getNonce() internal returns (bytes32) { + return bytes32(_nonce++); + } + + function getInt() public returns (uint256) { + bytes32 entropy = ISC.sandbox.getEntropy(); + bytes32 nonce = getNonce(); + bytes32 digest = keccak256(bytes.concat(entropy, nonce)); + + uint256 value = uint256(digest); + + emit Int(value); + return value; + } + + function getBytes(uint length) public returns (bytes memory) { + bytes32 entropy = ISC.sandbox.getEntropy(); + bytes32 nonce = getNonce(); + bytes32 digest = keccak256(bytes.concat(entropy, nonce)); + + bytes memory value = new bytes(length); + for (uint i = 0; i < length; i += 32) { + digest = keccak256(bytes.concat(digest)); + for (uint j = 0; j < 32 && i + j < length; j++) { + value[i + j] = digest[j]; + } + } + + emit Bytes(value); + return value; + } +} + +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/introduction.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/introduction.md new file mode 100644 index 00000000000..d8983b4e246 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/introduction.md @@ -0,0 +1,79 @@ +--- +description: The ISC Core Contracts allows VMs to access ISC functionality. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - magic + - Ethereum + - Solidity + - metamask + - JSON + - RPC +--- + +# The Core Contracts + +The [core contracs](../../explanations/core-contracts.md) are contracts deployed on every chain and are vital to interact with L1 and the chain itself. They can be called in Solidity through the [ISC Magic Contract](../../reference/magic-contract/introduction.md). + +## The ISC Magic Contract + +The Magic contract is an EVM contract deployed by default on every ISC chain, in the EVM genesis block, at +address `0x1074000000000000000000000000000000000000`. +The implementation of the Magic contract is baked-in in +the [`evm`](../../reference/core-contracts/evm.md) [core contract](../../reference/core-contracts/overview.md); +i.e. it is not a pure-Solidity contract. + +The Magic contract has several methods, which are categorized into specialized +interfaces: `ISCSandbox`, `ISCAccounts`, `ISCUtil` and so on. +You can access these interfaces from any Solidity contract by importing +the [ISC library](https://www.npmjs.com/package/@iota/iscmagic): + +```bash npm2yarn +npm install @iota/iscmagic +``` + +You can import it into your contracts like this: + +```solidity +import "@iota/iscmagic/ISC.sol"; +``` + +The Magic contract also provides proxy ERC20 contracts to manipulate ISC base +tokens and native tokens on L2. + +:::info Reference Docs + +If you need further info about magic contracts interfaces you can check out the [magic contract docs](../../reference/magic-contract/introduction.md). + +::: + +## Call a Function + +:::info Ease of use + +To make it easier for developers to use the core contracts, you should, in most cases, run the functions from the magic contract directly. For example, to get the native token balance, you could [call the `balanceNativeToken()`](./call-view.md) directly with `callView`, or use [`getl2balancenativetokens`](./basics/get-balance.md) of the magic contract, or (the suggested way) register your native token as [`ERC20`](../../reference/magic-contract/ERC20NativeTokens.md) and call the standard [`balanceof`](../../reference/magic-contract/ERC20NativeTokens.md#balanceof) function. What you use also depends on what you optimize for. For example, to save gas, it could be interesting for you to call core contracts from your favorite web3 library directly and compute other things off-chain. + +::: + +In the example below, `ISC.sandbox.getEntropy()` calls the +[`getEntropy`](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L20) +method of the `ISCSandbox` interface, which, in turn, +calls [ISC Sandbox's](../../explanations/sandbox.md) `GetEntropy`. + +```solidity +pragma solidity >=0.8.5; + +import "@iota/iscmagic/ISC.sol"; + +contract MyEVMContract { + event EntropyEvent(bytes32 entropy); + + // this will emit a "random" value taken from the ISC entropy value + function emitEntropy() public { + bytes32 e = ISC.sandbox.getEntropy(); + emit EntropyEvent(e); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx new file mode 100644 index 00000000000..3795884916c --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/get-nft-metadata.mdx @@ -0,0 +1,55 @@ +--- +description: How to get NFT metadata from a L1 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- +import GetNftMetadata from '../../../_partials/how-tos/token/_get-nft-metadata.md'; +import ERC721Admonition from '../../../_admonitions/_ERC721.md'; +import IRC27Admonition from '../../../_admonitions/_IRC27.md'; + +# Get IRC27 NFT Metadata + + + +This guide explains how to use the [`getIRC27NFTData`](../../../reference/magic-contract/ISCSandbox.md#getirc27nftdata) function within a smart contract to fetch information about a specific IRC27 NFT on the IOTA Network. + + + +## Understanding the `getIRC27NFTData` Function + +The [`getIRC27NFTData`](../../../reference/magic-contract/ISCSandbox.md#getirc27nftdata) function retrieves metadata for an IRC27 NFT based on its identifier. IRC27 is a series of standards to support interoperable and universal NFT systems throughout the IOTA ecosystem. + +## How To Use `getIRC27NFTData` + +Create a function called `fetchIRC27NFTData` in your contract that calls `getIRC27NFTData` and processes its return value. `getIRC27NFTData` returns a struct of type [`IRC27NFTMetadata`](../../../reference/magic-contract/ISCTypes.md#irc27nftmetadata) which contains properties like the NFT name, uri and more. + + + +```solidity +function fetchIRC27NFTData(uint256 tokenId) public view returns (IRC27NFT memory irc27NftData) { + irc27NftData = ISC.sandbox.getIRC27NFTData(ISCTypes.asNFTID(tokenId)); + return irc27NftData; +} +``` + +## Full Example Contract + +Combining all the above steps, here’s a complete example: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; +import "@iota/iscmagic/ISCTypes.sol"; + +contract IRCNFTMetadata { + function fetchIRC27NFTData(uint256 tokenId) public view returns (IRC27NFT memory irc27NftData) { + irc27NftData = ISC.sandbox.getIRC27NFTData(ISCTypes.asNFTID(tokenId)); + return irc27NftData; + } +} +``` \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/introduction.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/introduction.md new file mode 100644 index 00000000000..506f0dfef13 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/introduction.md @@ -0,0 +1,17 @@ +--- +description: How to handle native NFTs on L2 and use them as ERC721 +image: /img/logo/WASP_logo_dark.png +tags: + - native + - NFT + - EVM + - how-to +--- +import DocCardList from '@theme/DocCardList'; + +# Native NFT and ERC721 + +The IOTA L1 can create NFTs, also called native NFTs. To use these NFTs on L2, you have +an ERC20 contract called `ERC721NFTs`, which contains all L1 NFTs owned by the chain. The following guides will show you how to [mint your own L1 NFT from L2](./mint-nft.md) and [use](./use-as-erc721.md) it with the `ERC721NFTs` contract. + + \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/mint-nft.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/mint-nft.md new file mode 100644 index 00000000000..d889d7972a2 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/mint-nft.md @@ -0,0 +1,152 @@ +--- +description: How to mint L1 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Mint an NFT +## About NFTs + +The Stardust update allows you to create your own NFTs. You can also use [IRC27](/tips/tips/TIP-0027) for NFTs. This guide will show you how to create an IRC27 L1 NFT using a L2 smart contract. + +## Example Code + + + +2. Get the senders AgentID: + +```solidity +ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); +``` + +3. Create an `IRC27Metadata` struct with all the needed data: + +```solidity +IRC27NFTMetadata memory metadata = IRC27NFTMetadata({ + standard: "IRC27", + version: "v1.0", + mimeType: _mimeType, + uri: _uri, + name: _name +}); +``` + +4. Create all the data for the core contract call. To do so, you should create a new `ISCDict` with 2 parameters like specified in the reference docs for [`mintNFT`](../../../reference/core-contracts/accounts.md#mintnfti-immutabledata-a-agentid-c-collectionid-w-withdrawonmint) +* `I` is the immutable metadata we fill with the IRC27 metadata and +* `a` is the AgendID of the owner of the NFT + +```solidity +ISCDict memory params = ISCDict(new ISCDictItem[](2)); +params.items[0] = ISCDictItem("I", bytes(IRC27NFTMetadataToString(metadata))); +params.items[1] = ISCDictItem("a", agentID.data); +``` + +:::info IRC27NFTMetadataToString + +The full example below calls the `IRC27NFTMetadataToString` function, which simply converts the IRC27Metadata struct into a string. + +::: + +5. Call the magic contract `call` function with all the parameters. You should specify the core contract you want to call, which in this case is the [`account`](../../../reference/core-contracts/accounts.md) contract, and the function for [minting an NFT](../../../reference/core-contracts/accounts.md#mintnfti-immutabledata-a-agentid-c-collectionid-w-withdrawonmint) + +```solidity +ISCDict memory ret = ISC.sandbox.call( + ISC.util.hn("accounts"), + ISC.util.hn("mintNFT"), + params, + allowance +); +``` + +6. The call return value will contain a `mintID` which we can use in, for example, another contract function to get the actual L1 NFT ID once it is created using the [`accounts.NFTIDbyMintID`](../../../reference/core-contracts/accounts.md#nftidbymintidd-mintid) function + +```solidity +function getNFTIDFromMintID(bytes memory mintID) public view returns (bytes memory) { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + params.items[0] = ISCDictItem("D", mintID); + + ISCDict memory ret = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("NFTIDbyMintID"), + params + ); + return ret.items[0].value; +} +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract NFTContract { + event MintedNFT(bytes mintID); + + function mintNFT(string memory _name, string memory _mimeType, string memory _uri, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + ISCAgentID memory agentID = ISC.sandbox.getSenderAccount(); + + IRC27NFTMetadata memory metadata = IRC27NFTMetadata({ + standard: "IRC27", + version: "v1.0", + mimeType: _mimeType, + uri: _uri, + name: _name + }); + + ISCDict memory params = ISCDict(new ISCDictItem[](2)); + params.items[0] = ISCDictItem("I", bytes(IRC27NFTMetadataToString(metadata))); + params.items[1] = ISCDictItem("a", agentID.data); + + ISCDict memory ret = ISC.sandbox.call( + ISC.util.hn("accounts"), + ISC.util.hn("mintNFT"), + params, + allowance + ); + emit MintedNFT(ret.items[0].value); + } + + function getNFTIDFromMintID(bytes memory mintID) public view returns (bytes memory) { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + params.items[0] = ISCDictItem("D", mintID); + + ISCDict memory ret = ISC.sandbox.callView( + ISC.util.hn("accounts"), + ISC.util.hn("NFTIDbyMintID"), + params + ); + return ret.items[0].value; + } + + function IRC27NFTMetadataToString(IRC27NFTMetadata memory metadata) + public + pure + returns (string memory) + { + return string.concat( + '{"standard": "', + metadata.standard, + '", "version": "', + metadata.version, + '", "type": "', + metadata.mimeType, + '", "uri": "', + metadata.uri, + '", "name": "', + metadata.name, + '"}'); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/use-as-erc721.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/use-as-erc721.md new file mode 100644 index 00000000000..2263adca84c --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/nft/use-as-erc721.md @@ -0,0 +1,33 @@ +--- +description: How to use a native NFT like an ERC721 NFT +image: /img/logo/WASP_logo_dark.png +tags: + - NFT + - EVM + - how-to +--- + +# Use as ERC721 +## About the `ERC721NFTs` contract + +The `ERC721NFTs` contract is a hardcoded contract at address `0x1074030000000000000000000000000000000000`. Every L1 NFT owned by the chain can be accessed through it. In this example, we will show you how to use it by using `transferFrom`. + +## Example Code + +1. ERC721 uses the `tokenID` for almost all interactions with it. So first, you should convert the `NFTID` to a `tokenID`: + +```solidity +uint256 tokenID = uint256(NFTID.unwrap(nftID)); +``` + +:::info Token ID to NFT ID + +You can use the ISCTypes.asNFTID() function to convert a Token ID to an NFT ID, by either using it on a token ID `tokenID.asNFTID();` or passing it to function `ISCTypes.asNFTID(tokenID)`. + +::: + +2. Transfer the token with ID `tokenID`, by using the `ERC20NFTs` contract, which is exposed in the library as `ISC.nfts`, and calling the standard `transferFrom` function: + +```solidity +ISC.nfts.transferFrom(msg.sender, _destination, tokenID); +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-foundry.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-foundry.md new file mode 100644 index 00000000000..17ba120d40c --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-foundry.md @@ -0,0 +1,71 @@ +--- +description: How to create a L1 foundry +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; + +# Create a Foundry + + + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry allows you to specify your native token's maximum supply **once** and change the circulating supply. +This guide will show you how to create an L1 foundry using a L2 smart contract. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the `NativeTokenScheme` by specifying its `mintedTokens`, `meltedTokens` and `maximumSupply`: + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: _mintedTokens, + meltedTokens: _meltedTokens, + maximumSupply: _maximumSupply +}); +``` + +### 3. Create the Foundry + +Create the foundry by calling the `ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance)` function: + +```solidity +uint32 foundrySN = ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance); +``` + +### Full Example Code + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract CreateFoundry { + event CreatedFoundry(uint32 foundrySN); + + function createFoundry(uint _mintedTokens, uint _meltedTokens, uint _maximumSupply, uint64 _storageDeposit) public payable { + require(msg.value == _storageDeposit*(10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: _mintedTokens, + meltedTokens: _meltedTokens, + maximumSupply: _maximumSupply + }); + uint32 foundrySN = ISC.accounts.foundryCreateNew(nativeTokenScheme, allowance); + emit CreatedFoundry(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-native-token.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-native-token.md new file mode 100644 index 00000000000..06baa4615d1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/create-native-token.md @@ -0,0 +1,91 @@ +--- +description: How to Create a Native Token Foundary. +image: /img/logo/WASP_logo_dark.png +tags: + - foundry + - EVM + - how-to + - native tokens + - mint + - register +--- + +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; + +# Create a Native Token + +This guide will show you how you can efficiently mint new tokens and register them for use as ERC20 tokens with the [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) function in one seamless operation. It will create a foundry on L1 and register it as an ERC20 on L2. This method ensures that only the foundry owner can mint tokens, maintaining security and control over the token creation process. + +## About Foundries + +The Stardust update allows you to create your own native tokens. Native tokens are minted by a [Foundry](/tips/tips/TIP-0018/#foundry-output). +The Foundry lets you specify your native token's maximum supply **once** and change the circulating supply. + +## Example Code + + + +### 2. Define the Token Scheme + +Define the [`NativeTokenScheme`](../../../reference/magic-contract/ISCTypes.md#nativetokenscheme) by specifying the `maximumSupply`. + +```solidity +NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply +}); +``` + +### 3. Mint and Register Native Token + +Minting native tokens and registering them as ERC20 tokens using [`createNativeTokenFoundry`](../../../reference/magic-contract/ISCAccounts.md#createnativetokenfoundry) method + +```solidity +uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance +); +``` + +## Full Example Code + +```solidity +pragma solidity ^0.8.0; + +import "@iota/iscmagic/ISC.sol"; + +contract MyToken { + event MintedToken(uint32 foundrySN); + + constructor( + string memory _tokenName, + string memory _tokenSymbol, + uint8 _tokenDecimals, + uint256 _maximumSupply, + uint64 _storageDeposit + ) payable { + require(msg.value == _storageDeposit * (10**12), "Please send exact funds to pay for storage deposit"); + ISCAssets memory allowance; + allowance.baseTokens = _storageDeposit; + + NativeTokenScheme memory nativeTokenScheme = NativeTokenScheme({ + mintedTokens: 0, + meltedTokens: 0, + maximumSupply: _maximumSupply + }); + + uint32 foundrySN = ISC.accounts.createNativeTokenFoundry( + _tokenName, + _tokenSymbol, + _tokenDecimals, + nativeTokenScheme, + allowance + ); + emit MintedToken(foundrySN); + } +} +``` diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/erc20-native-token.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/erc20-native-token.md similarity index 100% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/erc20-native-token.md rename to docs/build/isc/v1.3/docs/how-tos/core-contracts/token/erc20-native-token.md diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/introduction.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/introduction.md new file mode 100644 index 00000000000..83fb4021e47 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/introduction.md @@ -0,0 +1,18 @@ +--- +description: How to handle native tokens on L2 and use them as ERC20 +image: /img/logo/WASP_logo_dark.png +tags: + - native token + - EVM + - how-to +--- +import DocCardList from '@theme/DocCardList'; + +# Native Token and ERC20NativeToken + +The IOTA L1 has functionality to create L1 tokens, also called native tokens. To use these native tokens on L2, you have +a ERC20 contract called `ERC20NativeToken`. The following guides will show you how to [create a foundry](create-foundry.md) +that can [mint your own L1 token from L2](mint-token.md), and [register](register-token.md) it as `ERC20NativeToken`, +so it can be used like any other ERC20 token with some additional features. + + \ No newline at end of file diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/mint-token.md similarity index 87% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md rename to docs/build/isc/v1.3/docs/how-tos/core-contracts/token/mint-token.md index 9e8e8d9b3c4..bd79533d844 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/mint-token.md +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/mint-token.md @@ -12,8 +12,7 @@ import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_int # Mint Native Tokens -To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, -so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract that [created the foundry](./create-foundry.md). +To mint tokens from a [foundry](/tips/tips/TIP-0018/#foundry-output), you first need to be aware that only the foundry owner can mint token, so you should execute the `ISC.accounts.mintNativeTokens` function in the same contract where you also [created the native token](./create-native-token.md). ## Example Code diff --git a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/register-token.md similarity index 92% rename from docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md rename to docs/build/isc/v1.3/docs/how-tos/core-contracts/token/register-token.md index 6a910327068..990ae5e69b3 100644 --- a/docs/build/isc/v1.0.0-rc.6/docs/how-tos/core-contracts/token/register-token.md +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/register-token.md @@ -7,9 +7,12 @@ tags: - how-to --- import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import ObsoleteTokenCreation from '../../../_partials/how-tos/token/_obsolete_token_creation.md'; # Register Tokens + + To properly use your native tokens, you should register them as ERC20 using the `registerERC20NativeToken` function from the ISC magic contract. ## Example Code diff --git a/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/send-token-across-chains.mdx b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/send-token-across-chains.mdx new file mode 100644 index 00000000000..9af496752e6 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/core-contracts/token/send-token-across-chains.mdx @@ -0,0 +1,118 @@ +--- +description: How to Send Native Tokens Across Chains. +image: /img/logo/WASP_logo_dark.png +tags: + - EVM + - how-to + - native tokens + - cross-chain +--- +import ExampleCodeIntro from '../../../_partials/how-tos/token/_example_code_intro.md'; +import DemoTokenSetup from '../../../_admonitions/_token-demo-setup.md'; +import CreateNativeToken from '../../../_admonitions/_create-native-token.md'; + +# Send Native Token Across Chains + +## Introduction + +Cross-chain token transfers are crucial in the evolving decentralized finance (DeFi) landscape. In this guide, you'll learn how to send L1 native Tokens from L1 to an L2 EVM account on a destination chain using the `sendCrossChain` function of the [`NativeTokenController.sol`](https://github.com/iotaledger/isc-cross-chain/blob/master/contracts/NativeTokenController.sol) contract. + + + +## Understanding the `sendCrossChain` Function + +First, let’s take a look at the `sendCrossChain` function in the `NativeTokenController.sol` file: + +```solidity +function sendCrossChain( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit +) external { + // Function implementation +} +``` +This function facilitates the transfer of native tokens from a Layer 1 (L1) address to a specified Layer 2 (L2) EVM account. It requires the L1 address of the destination chain (`chainAddress`), the recipient address on the destination chain (`_destination`), the destination chain's ID (`_chainID`), the amount of native tokens to be sent (`_amount`), and the amount of base tokens to cover the storage deposit (`_storageDeposit`). +The `sendCrossChain` wrapper function invokes the `ISC.sandbox.send` function, which manages the actual cross-chain message transmission. + +## Setting Up the Development Environment + + + +## Using the `sendCrossChain` Function + +To send native tokens across chains, you need to provide the following transaction details to the `sendCrossChain` function: + +* `ChainAddress` - The L1 address of the destination chain. +* `Destination` - The address on the destination chain that will receive the tokens. +* `chainID` - The ID of the destination chain. +* `amount` - The amount of native tokens to sent. +* `storageDeposit` - The base tokens to cover storage deposit. + +## Example Code + + +### 2. Send Token to Another Chain + +Let's define a function named `sendCrossChainMessage` in our contract, which will interact with the `sendCrossChain` function in the `NativeTokenController` contract. + +```solidity +function sendCrossChainMessage( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit +) external { + // Ensure the sender has enough tokens (assuming a balanceOf function exists) + uint256 senderBalance = IERC20(tokenAddress).balanceOf(msg.sender); + require(senderBalance >= amount, "Insufficient token balance"); + + // Call the sendCrossChain function from NativeTokenController + nativeTokenController.sendCrossChain(destinationChain, destinationAddress, amount, chainID, storageDeposit); +} +``` + +## Full Example Code + +```solidity + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./NativeTokenController.sol"; // Adjust the path as necessary +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract CrossChainMessenger { + + NativeTokenController public nativeTokenController; + + constructor(address _nativeTokenControllerAddress) { + nativeTokenController = NativeTokenController(_nativeTokenControllerAddress); +} + +function sendCrossChainMessage( + address destinationChain, + bytes memory destinationAddress, + uint256 amount, + ISCChainID chainID, + uint64 storageDeposit, + tokenAddress +) external { + // Ensure the sender has enough tokens (assuming a balanceOf function exists) + uint256 senderBalance = IERC20(tokenAddress).balanceOf(msg.sender); + require(senderBalance >= amount, "Insufficient token balance"); + + // Call the sendCrossChain function from NativeTokenController + nativeTokenController.sendCrossChain(destinationChain, destinationAddress, amount, chainID, storageDeposit); + } +} +``` +## Conclusion + +By following this guide, you have learned how to set up your development environment and use the `sendCrossChain` function in the [`NativeTokenController.sol`](https://github.com/iotaledger/isc-cross-chain/blob/master/contracts/NativeTokenController.sol) contract to send native tokens across chains. You can now interact with the `sendCrossChain` function within your own smart contracts to facilitate cross-chain token transfers. + +By leveraging cross-chain capabilities, you can create more interoperable and versatile decentralized applications, paving the way for a more connected blockchain ecosystem. \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/create-a-basic-contract.md b/docs/build/isc/v1.3/docs/how-tos/create-a-basic-contract.md new file mode 100644 index 00000000000..d060b3732ff --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/create-a-basic-contract.md @@ -0,0 +1,53 @@ +--- +description: Basic smart contract example. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - how to + - basic contract +--- +import DeployAdmonition from '../_admonitions/_deploy_a_smart_contract.md'; + +# Basic Smart Contract Example + +[Solidity](https://docs.soliditylang.org/en/v0.8.16/) smart contracts on IOTA Smart Contracts are compatible with +Solidity smart contracts on any other network. Most smart contracts will work directly without any modification. To get +a rough indication of what a simple Solidity smart contract looks like, see the example below: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.6; + +contract Counter { + uint private count; + + constructor() { + count = 0; + } + + function increment() public { + count += 1; + } + + function decrement() public { + require(count > 0, "Count is already zero"); + count -= 1; + } + + function getCount() public view returns (uint) { + return count; + } +} + +``` + +This contract simply updates a `count` variable. It has +three [entry points](../explanations/smart-contract-anatomy.md#entry-points): + +* `increment` and `decrement`: Two full entry points that can alter + the [state](../explanations/smart-contract-anatomy.md#state), i.e. the `count variable`. +* `getCount`: A view only entry point, which simply renders the current `count` state. + +For more information, please visit the [official Solidity documentation](https://docs.soliditylang.org/). + + \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/deploy-a-smart-contract.mdx b/docs/build/isc/v1.3/docs/how-tos/deploy-a-smart-contract.mdx new file mode 100644 index 00000000000..0a1860715ec --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/deploy-a-smart-contract.mdx @@ -0,0 +1,196 @@ +--- +tags: +- Smart Contract Deployment +- Shimmer EVM +- IOTA EVM +- Remix IDE +- Hardhat +- EVM Testnet +image: /img/logo/WASP_logo_dark.png +description: 'Learn how to deploy smart contracts to IOTA EVM, Shimmer EVM and EVM Testnet using popular tools like Remix and Hardhat.' +--- +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import HardhatConfig from '../_partials/_hardhat_config.md'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Deploy a Smart Contract + +You can deploy your smart contracts to any of your [EVM chains](/build/networks-endpoints/) using popular tools like [Remix](#remix) +and [Hardhat](#hardhat). + +:::tip Get a Basic Contract + +This guide will deploy the `Counter` contract you can find in +the [How to Create a Basic Solidity Contract Guide](create-a-basic-contract.md). + +::: + + + + +Deploying a Solidity smart contract using Remix is a straightforward process that doesn't require any installation or +setup of development environments on your machine. Remix is a powerful, browser-based IDE that allows you to write, +compile, and deploy smart contracts. + +### 1. Connect to Metamask + +Before you get started, make sure you have connected Metamask to your network of choice. + +:::tip Networks & Endpoints + +You can check the connection details in the [Networks & Endpoints section](/build/networks-endpoints/). + +::: + + + +### 2. Access Remix IDE + +Open your web browser and navigate to [Remix IDE](https://remix.ethereum.org/). + +### 3. Create Your Smart Contract + +1. In the `File Explorer` tab on the left, click the `Create New File` icon. +2. Name your file `Counter.sol`. +3. Copy the Solidity code for the [basic counter smart contract](create-a-basic-contract.md) and paste it into + the `Counter.sol` file you just created in Remix. + +### 4. Compile Your Smart Contract + +1. Navigate to the `Solidity Compiler` tab on the left sidebar. +2. Select the appropriate compiler version that matches the version specified in your contract (`^0.8.6` or similar). + You might need to enable "Auto compile" or click the "Compile" button manually. +3. If there are errors, Remix will display them, and you'll need to correct them before proceeding. + +### 5. Deploy Your Smart Contract + +1. Switch to the "Deploy & Run Transactions" tab on the left sidebar. +2. In the "Environment" dropdown, select and select `Injected Web3` from the `Environment` dropdown. + + ![Select Injected Provider from the Environment dropdown](/img/evm/remix-injected-provider-metamask.png) + +3. After selecting the environment, make sure the contract Counter is selected in the `Contract` dropdown. +4. Click the `Deploy` button. If you're using an Ethereum network, confirm the transaction in your Web3 wallet. + +### 6. Interact with Your Deployed Contract + +Once deployed, the contract instance will appear under the `Deployed Contracts` section. +Here, you can interact with your contract by calling its functions. For the Counter contract, you'll see buttons to call +its `increment`, `decrement`, and `getCount` functions directly from Remix. + + + + +The first thing you'll need to deploy a smart contract using [Hardhat](https://hardhat.org/) is to set up a Hardhat +project. Here's a step-by-step guide: + +### Requirements + +* [Node.js](https://nodejs.org/). +* [npm](https://www.npmjs.com/) or [yarn](https://yarnpkg.com/). + +### 1. Set Up Hardhat + +1. Open a new terminal window. +2. Create a new directory for your project, and navigate into it. For example: + ```bash + mkdir deploy-a-basic-contract && + cd deploy-a-basic-contract + ``` +3. Create a new node project by running: + ```bash + npm init -y + ``` +4. Install Hardhat by running: + ```bash + npm install --save-dev hardhat + ``` +5. Create a Hardhat Project by running the following command: + ```bash + npx hardhat init + ``` + + Select `Create a JavaScript project` (or whatever applies to your project) when prompted and answer the setup questions (you can press enter to + accept defaults). + +### 2. Add Your Contract + +1. Inside the `contracts` folder, create a new file called `Counter.sol` and paste the content of + the [Counter Basic Contract](create-a-basic-contract.md). + +### 3. Create a Deployment Script + +1. Navigate to the `scripts` folder. +2. Create a new file called `deploy.js` with the following code: + + ```javascript + async function main() { + const Counter = await ethers.getContractFactory("Counter"); + const counter = await Counter.deploy(); + + console.log("Counter deployed to:", await counter.getAddress()); + } + + main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); + ``` + +### 4. Compile and Deploy Your Contract + +1. Add your preferred network parameters to the `hardhat.config.js`, for example: + + + +:::info Export the Metamask Private Key + +1. Click on the Metamask logo in the upper right corner. +2. Select the account you want to export. +3. On the account page, click the menu (three dots) in the upper right corner, then click the "Account Details" button. +4. Click on "Export Private Key". +5. Enter your wallet password to access your private key and click `Confirm` to continue. +6. Your private key will now be displayed. Click to copy it and save it in a safe place. + +You can find more information in the [official Metamask Documentation](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). + +::: + +:::caution + +Currently, there is no validation service available for EVM/Solidity smart contracts on IOTA Smart Contracts, which is +often offered through block explorer APIs. + +::: + +2. Compile your contract by running the following command: + + ```bash + npx hardhat compile + ``` + +3. If you have no compilation errors, you can deploy your contract by running the following command: + + ```bash + npx hardhat run scripts/deploy.js --network evm-testnet + ``` + + **Expected output**: + + ```bash + Counter deployed to: 0x123456789ABCDEFGHIJK123456789ABCDEFGHIJK + ``` + ***** `0x123456789ABCDEFGHIJK123456789ABCDEFGHIJK` is the contract unlock address. + +4. You can verify your contract by visiting + the [EVM Testnet Explorer](https://explorer.evm.testnet.shimmer.network/), + and searching for the address from the previous step. If you access the `Contract` tab, you should be able to see + your code and interact with your contract. + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/introduction.md b/docs/build/isc/v1.3/docs/how-tos/introduction.md new file mode 100644 index 00000000000..cb6c63bbc87 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/introduction.md @@ -0,0 +1,29 @@ +--- +description: 'Explore the how-to guides for IOTA Smart Contracts, offering step-by-step instructions on various topics and functionalities.' +image: /img/logo/WASP_logo_dark.png +tags: + + - EVM + - Solidity + - smart contracts + - Ethereum + - explanation + - how-to guides + - instructions + - code examples +--- + +# About How-to Guides + +This section has several how-to guides that provide step-by-step instructions on various topics and functionalities. You +can use these guides to understand and implement specific tasks or features within your application. Whether you are a +beginner or an experienced developer, the how-to guides offer clear and concise explanations, making integrating IOTA smart contracts +functionality into your projects easier. + +To make the most of the how-to guides in this section, identify the specific topic or functionality you want to explore. +Whether you want to [get funds on L2](send-funds-from-L1-to-L2.mdx), [add ISC specific functionality](introduction.md), +or [send funds to L1](./core-contracts/basics/send-assets-to-l1.mdx), you can find dedicated guides that walk you through the process. + +With the how-to guides in the IOTA SDK, you can overcome implementation hurdles and gain a deeper understanding +of the IOTA ecosystem. These guides empower you with the knowledge and practical examples to seamlessly integrate IOTA +functionality into your projects. diff --git a/docs/build/isc/v1.3/docs/how-tos/send-ERC20-across-chains.md b/docs/build/isc/v1.3/docs/how-tos/send-ERC20-across-chains.md new file mode 100644 index 00000000000..af8cc67fa54 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/send-ERC20-across-chains.md @@ -0,0 +1,297 @@ +# Send ERC20 Tokens Across Chains + +## Introduction + +[LayerZero OFT V2](https://docs.layerzero.network/v2) enables cross-chain transfers of existing ERC20 tokens, such as wSMR and wIOTA (wrapped versions of the native gas tokens SMR and IOTA on ShimmerEVM and IOTA EVM respectively). For testing purposes, Sepolia is chosen as the source chain, while the BNB Testnet is chosen as the destination chain. + +:::info Community Libs + +You can clone the Utilities for LayerZero OFT V2 from [IOTA Community GitHub Repository](https://github.com/iota-community/layerzero-oft-v2-utils). + +::: + +### Why Would a User Need to Send ERC20 Tokens Across Chains? + +Sending ERC20 tokens across chains allows users to leverage different blockchain networks' strengths and unique features, optimize costs, and manage risks more effectively. This flexibility is crucial as the blockchain ecosystem continues to grow and diversify. + +#### Send Existing ERC20 Tokens Across Chains + +You need both the [OFT Adapter](https://docs.layerzero.network/v2/developers/evm/oft/adapter) and OFT contracts to enable existing ERC20 tokens for cross-chain sending, + +#### Create New Cross-chain Fungible Tokens + +If you are about to launch a new ERC20 token, you can use the [OFT standard](https://docs.layerzero.network/v2/developers/evm/oft/quickstart) to enable cross-chain sending without the OFT Adapter. + +## How To Use IOTA's Utilities for LayerZero OFT V2 + +The [Utilities for LayerZero OFT V2](https://github.com/iota-community/layerzero-oft-v2-utils) facilitate cross-chain sending of ERC20 tokens between a source chain (e.g., Sepolia or ShimmerEVM Testnet) and a destination chain (e.g., BNB Testnet or IOTA EVM Testnet). + +:::tip Further Information + +You can learn more about the available options in the [Layer Zero Documentation](https://docs.layerzero.network/v2/developers/evm/gas-settings/options#option-types.). + +::: + +### Send Tokens From One Source Chain to Another Destination Chain (and Vice Versa) + +To send existing ERC20 tokens, you will need both the OFT Adapter contract on the source chain and the OFT contract on the destination chain. You should then use the following procedure: + +#### 1. Approve the tokens + +The sender must approve their ERC20 tokens for the OFT Adapter contract. + +```typescript +const approveTx = await erc20TokenContract.approve(oftAdapterContractAddress, amountInWei); +``` + +#### 2. Estimate the fee + +The sender calls the function `quoteSend()` of the OFT Adapter contract to estimate the cross-chain fee to be paid in native tokens on the source chain. + +```typescript + const sendParam = [ + lzEndpointIdOnDestChain, + receiverAddressInBytes32, + amountInWei, + amountInWei, + options, // additional options + "0x", // composed message for the send() operation + "0x", // OFT command to be executed, unused in default OFT implementations + ]; + + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L127C60-L127C73 + // false is set for _payInLzToken Flag indicating whether the caller is paying in the LZ token + const [nativeFee] = await myOFTAdapterContract.quoteSend(sendParam as any, false); +``` + +#### 3. Send the tokens + +The sender calls the function `send()` of the OFT Adapter contract to transfer tokens from the source chain to the destination chain. + +```typescript + const sendTx = await myOFTAdapterContract.send( + sendParam as any, + [nativeFee, 0] as any, // set 0 for lzTokenFee + sender.address, // refund address + { + value: nativeFee, + }, + ); + const sendTxReceipt = await sendTx.wait(); + console.log("sendOFT - send tx on source chain:", sendTxReceipt?.hash); +``` + +#### 4. (Optional) Wait for Finalization + +The sender can wait for transaction finalization on the destination chain using the library [@layerzerolabs/scan-client](https://www.npmjs.com/package/@layerzerolabs/scan-client#example-usage). +```typescript + const deliveredMsg = await waitForMessageReceived( + Number(lzEndpointIdOnDestChain), + sendTxReceipt?.hash as string, + ); + console.log("sendOFT - received tx on destination chain:", deliveredMsg?.dstTxHash); +``` + +### Send the OFT-wrapped Tokens Back + +To send back the OFT-wrapped tokens on the destination chain to the source chain, the procedure is similar, except that the approval step is not needed: + +#### 1. Estimate the fee + +The sender calls the function `quoteSend()` of the OFT contract to estimate the cross-chain fee to be paid in native tokens on the sender chain. + +```typescript + // Set the send param + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L10 + const sendParam = [ + lzEndpointIdOnSrcChain, // Sepolia + receiverAddressInBytes32, + amountInWei, + amountInWei, + options, // additional options + "0x", // composed message for the send() operation + "0x", // OFT command to be executed, unused in default OFT implementations + ]; + + // Step 1: call the func quoteSend() to estimate cross-chain fee to be paid in native on the source chain + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/oapp/contracts/oft/interfaces/IOFT.sol#L127C60-L127C73 + // false is set for _payInLzToken Flag indicating whether the caller is paying in the LZ token + const [nativeFee] = await myOFTContract.quoteSend(sendParam as any, false); + console.log("sendOFTBack - estimated nativeFee:", ethers.formatEther(nativeFee)); + ``` + +#### 2. Send the tokens + +The sender calls the function `send()` of the OFT contract to transfer tokens from the destination chain back to the source chain. + +```typescript +const sendTx = await myOFTContract.send( + sendParam as any, + [nativeFee, 0] as any, // set 0 for lzTokenFee + sender.address, // refund address + { + value: nativeFee, + }, + ); + const sendTxReceipt = await sendTx.wait(); + console.log("sendOFTBack - send tx on source chain:", sendTxReceipt?.hash); + ``` + +#### 3. (Optional) Wait for Finalization + +The sender can wait for transaction finalization on the destination chain using the library `@layerzerolabs/scan-client`. +```typescript + const deliveredMsg = await waitForMessageReceived( + Number(lzEndpointIdOnDestChain), + sendTxReceipt?.hash as string, + ); + console.log("sendOFTBack - received tx on destination chain:", deliveredMsg?.dstTxHash); + ``` + +## Sample Solidity Code for OFT Adapter and OFT Contracts in the `contracts-standard` Folder + +The [contracts-standard](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-standard) contains scripts to: + +- [Deploy the OFT Adapter and OFT contracts](#deploy-the-oft-adapter-contract-on-the-source-chain). +- [Set your trusted peers](#optional-set-the-trusted-peers). +- Set enforced options. +- [Send tokens from the source chain to the destination chain](#send-the-origin-tokens-from-the-source-chain-to-the-destination-chain), +and [vice versa](#send-oft-wrapped-tokens-back-from-the-destination-chain-to-the-origin-chain). + +### Install the Library + +After you have cloned the [IOTA Community Utilities for LayerZero OFT V2 repository](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main), you should run the following command to install: + +``` +yarn +``` + +### Compile the Contracts + +If you want to use the standard implementation for ERC20, copy the [`contracts-standard`](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-standard) folder to `contracts`. If you want to use a custom implementation, copy the [`contracts-wiota`](https://github.com/iota-community/layerzero-oft-v2-utils/tree/main/contracts-wiota) to `contracts`. Then, run the following command to compile the contracts: + +```bash +yarn compile +``` + +### Set Your Configuration + +You should copy the template [`.env.example`](https://github.com/iota-community/layerzero-oft-v2-utils/blob/main/.env.example) file to a file called `.env`, and edit any of the configuration options you see fit. + +```bash +cp .env.example .env +``` + +### Deploy the Contracts + +#### Deploy the OFT Adapter Contract On the Source Chain + +The OFT Adapter facilitates the expansion of an existing token to any supported blockchain as a native token, maintaining a unified global supply and inheriting all features of the OFT Standard. This intermediary contract manages the sending and receiving of pre-deployed tokens. + +For instance, when an ERC20 token is transferred from the source chain (Chain A), it gets locked in the OFT Adapter. Consequently, a corresponding token is minted on the destination chain (Chain B) through the paired OFT Contract. + +```bash +yarn deploy-oft-adapter-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_oft_adapter.ts --network sepolia +Deployed MyOFTAdapter contract address: 0x4daa81978576cB91a2e1919960e90e46c2a6D586 +Done in 6.67s. +``` + +#### Deploy OFT on the Destination Chain + +You can use the following command to deploy OFT on destination chain (e.g. BNB Testnet): + +```bash +yarn deploy-oft-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_oft.ts --network bnbTestnet +Deployed MyOFT contract address: 0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1 +Done in 6.68s. +``` + +### (optional) Set the Trusted Peers + +#### On OFTAdapter + +You can set the trusted peer in the source chain's OFT Adapter (e.g., Sepolia) using the following command: + +```bash +yarn set-peer-oft-adapter-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/set_peer_oft_adapter.ts --network sepolia +setPeerMyOFTAdapter - oftAdapterContractAddress:0x4daa81978576cB91a2e1919960e90e46c2a6D586, lzEndpointIdOnDestChain:40102, oftContractAddress:0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1 +MyOFTAdapter - setPeer tx: 0xc17e7a54d96325768b6427ce893d9b6b7ed04bd920089b63a3f96c005073e9c2 +Done in 14.10s. +``` + +#### On OFT + +You can add a trusted peer in the destination chain (e.g. BNB Testnet) using the following command: + +```bash +yarn set-peer-oft-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/set_peer_oft.ts --network bnbTestnet +setPeerMyOFT - oftContractAddress:0xCc337C2e69F4Eb8EaBcf632a1fC5B8F729dC47F1, lzEndpointIdOnSrcChain:40161, oftAdapterContractAddress:0x4daa81978576cB91a2e1919960e90e46c2a6D586 +MyOFT - setPeer tx: 0xb0012378ee14c9df5c9f86980dd9c96fc8aedb3c19d92c1d91a4259f3981ac35 +Done in 4.66s. +``` + +### Send the Origin Tokens from the Source Chain to the Destination Chain + + +You can use the following command to send tokens from the source chain to the destination chain: + +```bash +yarn send-oft-from-sepolia +``` + +Expected log output : + +```bash +npx hardhat run scripts/send_oft.ts --network sepolia +sendOFT - oftAdapterContractAddress:0x5D7Cbc05fc6df2832c40023f1Eb2755628C51D81, oftContractAddress:0x075e512E25b45a3EaF8b432220F0Ca8D4e3c6a58, lzEndpointIdOnSrcChain:40161, lzEndpointIdOnDestChain:40102, gasDropInWeiOnDestChain:1000000000000000, executorLzReceiveOptionMaxGas:200000, receivingAccountAddress:0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, sender: 0x57a4bd139fb673d364a6f12df9177a3f686625f3, amount:2 +sendOFT - approve tx: 0x8fa692edb47b1ad9d21f60b0fa30993e5cd3abd78c3c56fb4f38db5f9b8ac369 +sendOFT - estimated nativeFee: 0.000734209489447653 +sendOFT - send tx on source chain: 0xeb3e44310a09ae2ab2f0d6d6d3fdfd7c490f8ac536bb20a5e16999b23232ef67 +Wait for cross-chain tx finalization by LayerZero ... +sendOFT - received tx on destination chain: 0xc2e5a4be8ae67718e817ff585a32765e393835880068f408fd7724667a25a46c +``` + +### Send Oft-Wrapped Tokens Back From the Destination Chain to the Origin Chain + +You can use the following command to send the OFT-wrapped tokens back to the origin chain: + + +```bash +yarn send-oft-back-from-bnb-testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/send_oft_back.ts --network bnbTestnet +sendOFTBack - oftAdapterContractAddress:0x5D7Cbc05fc6df2832c40023f1Eb2755628C51D81, oftContractAddress:0x075e512E25b45a3EaF8b432220F0Ca8D4e3c6a58, lzEndpointIdOnSrcChain:40161, lzEndpointIdOnDestChain:40102, gasDropInWeiOnDestChain:1000000000000000, executorLzReceiveOptionMaxGas:200000, receivingAccountAddress:0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, sender: 0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, amount:2 +sendOFTBack - estimated nativeFee: 0.054815809525020364 +sendOFTBack - send tx on source chain: 0x41bcf78b310dc1bbf9b4005f7412d995011c7815ad5af9cc26b37370e75bbfeb +Wait for cross-chain tx finalization by LayerZero ... +sendOFTBack - received tx on destination chain: 0xc1031694e92512a0189885ad6419e33196a65b8ae56baa9d555be8686d6d42fe +``` + diff --git a/docs/build/isc/v1.3/docs/how-tos/send-NFTs-across-chains.md b/docs/build/isc/v1.3/docs/how-tos/send-NFTs-across-chains.md new file mode 100644 index 00000000000..3e9b5a435a7 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/send-NFTs-across-chains.md @@ -0,0 +1,359 @@ +# Send NFTs Across Chains + +## Introduction + +[LayerZero ONFT V1FV](https://docs.layerzero.network/V1) enables cross-chain transfers of existing ERC721 tokens. For +testing purposes, the ShimmerEVM Testnet is chosen as the source chain, while the BNB Testnet is chosen as the destination +chain. + +:::info Community Libs + +You can clone the Utilities for LayerZero ONFT V1 +from [IOTA Community GitHub Repository](https://github.com/iota-community/layerzero-onft-v1-utils). + +::: + +## Why Would a User Need to Send ERC721 Tokens Across Chains? + +By facilitating the movement of ERC721 tokens across chains, users gain flexibility and can optimize their NFT usage +according to their specific needs, preferences, and circumstances. + +### Enable the Existing ERC721 Tokens for Cross-Chain Sending + +To enable the existing ERC721 tokens for cross-chain sending, you will need the `ProxyONFT` contract on the source +chain, +and the ONFT contract on the destination chain) are needed. + +The origin NFT token will be locked in the `ProxyONFT` contract so that the ONFT-wrapped tokens will be minted on the +destination chain. If the NFT token already exists on the destination chain (i.e., when the ONFT-wrapped token on +the destination chain is sent back to the source chain), no new token minting will happen. Instead, the NFT tokens will be +transferred from the ONFT contract to the user's wallet address. Relevant code + +### Enable Cross-Chain Sending for Unloached ERC721 NFTs + +If you are launching a new ERC721 token, you can use the ONFT standard to enable cross-chain sending without the need of +`ProxyONFT`. As with existing tokens, the NFT will be locked on the source chain and minted or transferred on the destination chain. + +:::info Contract Documentation + +- [ProxyONFT721](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/721#proxyonft721sol) +- [ProxyONFT1155](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/1155#proxyonft1155sol) +- [ONFT721](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/721#onft721sol) +- [ONFT1155](https://docs.layerzero.network/v1/developers/evm/evm-guides/contract-standards/1155#onft1155sol) + +::: + +## Scripts + +### Deploy the ProxyONFT and ONFT Contracts + +#### For ERC721 + +- MyProxyONFT721.sol: + - CTOR: + - [`minGasToTransferAndStore`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/ONFT721Core.sol#L169): + The minimum gas needed to transfer and store your NFT is typically 100k for ERC721. This value would vary + depending on your contract complexity; it's recommended to test. If this value is set too low, the destination + tx will fail, and a manual retry is needed. + - `lzEndpoint`: LayerZero Endpoint on the source chain. + - `proxyToken`: deployed contract address of the NFT tokens on the source chain. + +- MyONFT721.sol: + - CTOR: + - `name`: name of the ONFT-wrapped tokens on the destination chain + - `symbol`: symbol of the ONFT-wrapped tokens on the destination chain + - [`minGasToTransferAndStore`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/ONFT721Core.sol#L169): + The minimum gas needed to transfer and store your NFT typically 100k for ERC721. This value would vary + depending on your contract complexity; it's recommended to test. If this value is set too low, the destination + tx will fail, and a manual retry is needed. + - `lzEndpoint`: - lzEndpoint: LayerZero Endpoint on the destination chain + +### Set the Trusted Remote + +For **existing ERC721 tokens**, the `ProxyONFT` and `ONFT` contract instances must be paired. + +For the **upcoming ERC721 tokens** that want to leverage the `ONFT` standard, the `ONFT` contract instance on the source chain +needs to be paired with another `ONFT` contract instance on the destination chain. + +You can set this using the [`setTrustedRemote`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L138) method. + +### Set the `minGasLimit` + +Both the `ProxyONFT` and the `ONFT` contract instanceS need to be set for minimum gas on destination([`minGasLimit`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L85C37-L85C48)). + +You can set his using the [`setMinDstGas`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/LzApp.sol#L159) method. + +:::info + +It is required that `minDstGas` <= `providedGasLimit`, which is to be set via `adapterParams` upon cross-chain sending on +the source chain. + +::: + +### Set the Batch Size Limit + +Both the `ProxyONFT` and the `ONFT` contract instances need to set a limit for the batch size on the source +chain to limit the number of tokens to be sent to another chain when using the +[`sendBatchFrom`](https://github.com/LayerZero-Labs/solidity-examples/blob/c04e7d211b1b610f84761df943e6a38b0a53d304/contracts/token/onft721/ONFT721Core.sol#L67) +method. + +You can set this using the [`setDstChainIdToBatchLimit`](https://github.com/LayerZero-Labs/solidity-examples/blob/c04e7d211b1b610f84761df943e6a38b0a53d304/contracts/token/onft721/ONFT721Core.sol#L194) method; the default value is 1. + +## How To Send Tokens From a Source Chain to a Destination Chain (and Vice-Versa) + +### Required Contracts + +#### From the Source Chain to the Destination Chain + +For the existing ERC721 tokens, you will need the `ProxyONFT` contract on the source chain and the `ONFT` contract on +the destination chain. The procedure is as follows: + +1. The sender approves his ERC721 tokens for the `ProxyONFT` contract. +2. The sender calls the function [`estimateSendFee()`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/interfaces/IONFT721Core.sol#L70) of the ProxyONFT contract to estimate cross-chain fee to be paid in + native on the source chain. +3. The sender calls the function [`sendFrom()`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/onft721/interfaces/IONFT721Core.sol#L36) of the ProxyONFT contract to transfer tokens on source chain to destination + chain. +4. (Optional) Wait for the transaction finalization on the destination chain by using the + [@layerzerolabs/scan-client](https://www.npmjs.com/package/@layerzerolabs/scan-client#example-usage) library. + +#### From the Destination Chain Back to the Source Chain + +To send back the ONFT-wrapped tokens on the destination chain to the source chain, the procedure is similar as the +approve step is also required, but the operations will happen on the `ONFT` contract. + +#### References and Tools + +##### `AdapterParams` + +- You can use the [LayerZero Repository](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/libs/LzLib.sol#L44) as a reference to set gas drop on the destination in `adapterParams`. + - The provided gas drop must be `<=` the config one. Otherwise, you will get [`dstNativeAmt` too large](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/mocks/LZEndpointMock.sol#L413) error. +- You can use the [LayerZero Repository](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/libs/LzLib.sol#L34) as a refernce to set default `adapterParams` without needing a gas drop. + +##### LayerZero + +- [LayerZero Endpoint V1 (Testnet)](https://docs.layerzero.network/v1/developers/evm/technical-reference/testnet/testnet-addresses) +- [layerZero Endpoint V1 (Mainnet)](https://docs.layerzero.network/v1/developers/evm/technical-reference/mainnet/mainnet-addresses) +- [LayerZero explorer](https://Testnet.layerzeroscan.com/) + +### Install and Compile the Library + +After you have cloned +the [IOTA Community Utilities for LayerZero ONFT V1 repository](https://github.com/iota-community/layerzero-onft-v1-utils), +you should run the following command to install: + +```bash +yarn +``` +then compile the contracts: + +```bash +yarn compile +``` + +### Set Your Configuration + +You should copy the +template [`.env.example`](https://github.com/iota-community/layerzero-oft-V1-utils/blob/main/.env.example) file to a +file called `.env`, and edit any of the configuration options you see fit. + +```bash +cp .env.example .env +``` + +### Deploy the Contracts + +#### Deploy a mock ERC721 + +```bash +yarn deploy-ERC721-mock-smr-Testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_ERC721.ts --network shimmerEvmTestnet +Deployed ERC721Mock contract address:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +Done in 4.49s. +``` + +#### Deploy `ProxyONFT721` on the source chain + +You can use the following command to deploy ProxyONFT721 on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn deploy-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +npx hardhat run scripts/deploy_proxy_onft721.ts --network shimmerEvmTestnet +Deployed MyProxyONFT721 contract address:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2 +Done in 4.50s. +``` + +#### Deploy `ProxyONFT721` on the destination chain + +You can use the following command to deploy ProxyONFT721 on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-min-dest-gas-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_min_destination_gas.ts --network bnbTestnet +setMinDstGas - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xce044ded17daa77a8aefc3d39b99c5381216eb4057ddce6253affde6cda2091c +setMinDstGas (packetType 1) tx: 0x3a26ae40ac058099bfd8b85910009a5e5e8b03f16a5f032b572827d48be8f2b0 +Done in 9.34s. +``` + +### Set the Minimum Destination Gas + +#### On the source chain + +You can use the following command to set the minimum destination gas on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-min-dest-gas-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_min_destination_gas.ts --network shimmerEvmTestnet +setMinDstGas - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xcab06e9989448153a4bbc1bb166fc2d33467f3311d1851bf2ff719d982daa613 +setMinDstGas (packetType 1) tx: 0xe78fd3f0bf668fafbc423decd2cf14a27d74543af3ac9daf031f0b278c22ea78 +Done in 6.07s. +``` + +#### On the destination chain + +You can use the following command to set the minimum destination gas on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-min-dest-gas-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_min_destination_gas.ts --network bnbTestnet +setMinDstGas - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, minDstGas:150000 +setMinDstGas (packetType 0) tx: 0xce044ded17daa77a8aefc3d39b99c5381216eb4057ddce6253affde6cda2091c +setMinDstGas (packetType 1) tx: 0x3a26ae40ac058099bfd8b85910009a5e5e8b03f16a5f032b572827d48be8f2b0 +Done in 9.34s. +``` + +### Set the batch size limit + +#### On the source chain + +You can use the following command to set batch size limits on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-batch-size-limit-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_batch_size_limit.ts --network shimmerEvmTestnet +setBatchSizeLimit - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102, batchSizeLimit:1 +setBatchSizeLimit tx: 0x70c23b3d3d5e94ef82e50944f7eba93fa1fe8db3a5487ac371015e7a14482e75 +Done in 4.28s. +``` + +#### On the destination chain + +You can use the following command to set batch size limits on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-batch-size-limit-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_batch_size_limit.ts --network bnbTestnet +setBatchSizeLimit - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230, batchSizeLimit:1 +setBatchSizeLimit tx: 0x8cb44c2195ac93da552c646677e6585c95ab172df19463637541933ec70dc9b8 +Done in 4.26s. +``` + +### Set the Trusted Remote + +#### On the source chain + +You can use the following command to set a trusted remote on the `ProxyONFT` contract on the source chain (e.g., ShimmerEVM Testnet): + +```bash +yarn set-remote-proxy-onft-smr-Testnet +``` + +Expected log output : + +```bash +export isForProxy=true && npx hardhat run scripts/set_trusted_remote.ts --network shimmerEvmTestnet +setTrustedRemote - isForProxy:true, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10102 +setTrustedRemote tx: 0xce52c0f25090ef7c1668ef04ff2f6098551c9f56b3ce881d17181bf106457016 +Done in 4.24s. +``` + +##### On the destination chain + +You can use the following command to set a trusted remote on the `ONFT` contract on the destination chain (e.g., BNB Testnet): + +```bash +yarn set-remote-onft-bnb-Testnet +``` + +Expected log output : + +```bash +export isForProxy=false && npx hardhat run scripts/set_trusted_remote.ts --network bnbTestnet +setTrustedRemote - isForProxy:false, proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnRemoteChain:10230 +setTrustedRemote tx: 0x311a0568b5afce7d601df2613f8ff80428d8a4d2f2c91012e0e4a8cbc0aedf59 +Done in 4.88s. +``` + +### Send Origin Tokens From the Source Chain To the Destination Chain + +```bash +yarn send-onft-from-smr-Testnet +``` + +Expected log output: + +```bash +npx hardhat run scripts/send_onft.ts --network shimmerEvmTestnet +sendONFT - proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnSrcChain:10230, lzEndpointIdOnDestChain:10102, gasDropInWeiOnDestChain:0, providedGasLimit:200000, receivingAccountAddress:0x5e812d3128D8fD7CEac08CEca1Cd879E76a6E028, sender: 0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, nftTokenId:2, nftTokenAddress:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +sendONFT - approve tx: 0xa871bc79e45bf20f33c626044d6e208460c5745ab1f13d476dcbe04e1da7e592 +sendONFT - estimated nativeFee: 158.319172348046094655 +sendONFT - send tx on source chain: 0x72779c7549053194e42bcc78f78cf65e876867f0516dc91f28986c854e652596 +Wait for cross-chain tx finalization by LayerZero ... +sendONFT - received tx on destination chain: 0x2700a9d35c139eb84ba07b75490e6627a30e00bde130e3cb7c1cbb81c0326138 +Done in 53.50s. +``` + +### Send ONFT-Wrapped Tokens Back From the Destination Chain Back To the Origin Chain + +```bash +yarn send-onft-back-from-bnb-Testnet +``` + +Expected log output: + +```bash +npx hardhat run scripts/send_onft_back.ts --network bnbTestnet +sendONFTBack - proxyONFTContractAddress:0x7B0D46219C915e7Ff503C7F83a805c0b2F4ab2F2, onftContractAddress:0xC617A0Bd9DC6093a304515d3dbFF4244333fDeBB, lzEndpointIdOnSrcChain:10230, lzEndpointIdOnDestChain:10102, gasDropInWeiOnDestChain:0, providedGasLimit:200000, receivingAccountAddress:0x57A4bD139Fb673D364A6f12Df9177A3f686625F3, sender: 0x60917645A28258a75836aF63633850c5F3561C1b, nftTokenId:2, nftTokenAddress:0xFddbA8928a763679fb8C99d12541B7c6177e9c3c +sendONFTBack - approve tx: 0xe5bfff108528efdc67e72896845f0ad3e0186b4ed64835e7c5f3552eaab69d99 +sendONFTBack - estimated nativeFee: 0.000498452810033053 +sendONFTBack - send tx on source chain: 0xa43bb5547a5a35730fe183b4d554416a4ea34852e510d21f24d173db75db4e79 +Wait for cross-chain tx finalization by LayerZero ... +sendONFTBack - received tx on destination chain: 0xb05fa2de194153819b26d17893278c485abbaf355fa24f26fbc7a4c759994cde +Done in 212.16s. +``` diff --git a/docs/build/isc/v1.3/docs/how-tos/send-funds-from-L1-to-L2.mdx b/docs/build/isc/v1.3/docs/how-tos/send-funds-from-L1-to-L2.mdx new file mode 100644 index 00000000000..0b1b47dec7f --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/send-funds-from-L1-to-L2.mdx @@ -0,0 +1,102 @@ +--- +description: How to send funds from L1 to L2. +image: /img/logo/WASP_logo_dark.png +tags: + - configure + - using + - EVM + - Ethereum + - Solidity + - deploy + - hardhat + - metamask + - JSON + - RPC + - how to +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import {AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; +import MetamaskButtons from '../../../../_partials/_metamask_buttons.mdx'; +import { Networks } from '@theme/constant'; + +# Send Funds From L1 to L2 + +There are multiple types of assets available on both IOTA L1 and L2, here we discuss a few of them, and how to get them +onto L2. + +:::tip Testnet + +If you want to fund your EVM Testnet account using the EVM Toolkit, please refer to our [Testnet Quickstart Guide](../getting-started/quick-start.mdx) + +::: + +## Fund an Ethereum Account on a IOTA Smart Contracts Chain + +To send EVM transactions, you need to have an Ethereum address that owns tokens on the ISC chain (L2). These tokens will +be used to cover gas fees. + + + + +You can use your [Firefly Wallet](https://firefly.iota.org/) to easily send L1 IOTA or SMR to your L2 IOTA EVM or ShimmerEVM account. + +#### Requirements + +* [IOTA Tokens](/get-started/introduction/iota/iota-token/) or [Shimmer Tokens](/get-started/introduction/shimmer/shimmer-token/) +* [Firefly Wallet](https://firefly.iota.org/) +* [Metamask](https://metamask.io/) + +1. The first thing you will need to do is add the EVM to Metamask by hitting the following button. + + + +2. Once you have added the EVM to Metamask, you can get your address: + + ![Copy your Metamask address](/img/evm/how-tos/get-funds/copy-your-address.png) + +3. Next, you will need to open your [Firefly Wallet](https://firefly.iota.org/) and click on `Send Assets`. + + ![Click send assets](/img/evm/how-tos/get-funds/firefly/select-send-assets.png) + +4. Select the EVM chain you want to use in the network dropdown. + + ![Select the EVM network](/img/evm/how-tos/get-funds/firefly/select-shimmer-evm.png) + +5. Enter the amount of tokens you want to transfer, and the Metamask address from step 2, and click on `Next` + + ![Enter the amount of tokens and metamask address](/img/evm/how-tos/get-funds/firefly/enter-your-desired-amount-and-metamask-address.png) + +6. Review the transaction details and click on `Send`. + + ![Hit Send](/img/evm/how-tos/get-funds/firefly/hit-send.png) + + + + + +You can use your [Bloom Wallet](https://bloomwallet.io/) to easily send L1 base token to your L2 EVM account. + +1. First, you will need to open your [Bloom Wallet](https://firefly.iota.org/) and click on `Send`. + + ![Click send](/img/evm/how-tos/get-funds/bloom/select-send.png) + +2. Select an account with base tokens. + + ![Select an account with base tokens](/img/evm/how-tos/get-funds/bloom/select-the-smr-token.png) + +3. Bloom will automatically create an EVM address for you, so you can send funds to that address from the +EVM dropdown. Alternatively, you can input any other EVM address. + + ![Select you EVM Address](/img/evm/how-tos/get-funds/bloom/enter-the-recipient-address.png) + +4. Enter the amount of base tokens you want to transfer. + + ![Enter the amount of base tokens you want to transfer](/img/evm/how-tos/get-funds/bloom/enter-the-amount.png) + +5. Review the transaction details and click on `Confirm`. + + ![Hit Send](/img/evm/how-tos/get-funds/bloom/review-and-confirm-the-transaction.png) + + + \ No newline at end of file diff --git a/docs/build/isc/v1.3/docs/how-tos/test-smart-contracts.md b/docs/build/isc/v1.3/docs/how-tos/test-smart-contracts.md new file mode 100644 index 00000000000..c3f2a8aa344 --- /dev/null +++ b/docs/build/isc/v1.3/docs/how-tos/test-smart-contracts.md @@ -0,0 +1,108 @@ +--- +keywords: +- Smart Contract Testing +- Automated Testing +- Unit Tests +- Integration Tests +- Testing Frameworks +- EVM Testnet +- Solidity Testing +description: Learn how to test smart contracts before deploying them on public networks to avoid vulnerabilities and ensure functionality aligns with requirements using unit, and integration testing, alongside frameworks and testing with the IOTA Sandbox and the EVM Testnet. +--- + +# Testing Smart Contracts + +Once you have deployed a smart contract on a public network, altering it to fix an error can be hard, and it goes +against the principle of immutability, which can create trust issues with users. And, even if it were simple, you could +only fix an error or vulnerability after it is discovered. So, your contract and its users may be at risk if a third +party detects a vulnerability before you do. + +The best way to avoid these overheads and vulnerabilities is to test your contracts thoroughly before deploying them. +You can use [unit](#unit-tests) and [integration](#integration-tests) tests, as well +as [manual testing](#manual-testing), to ensure your contracts behave as expected. + +## Automated Testing + +You can use various tools to automatically test your smart contract’s code and for any error in execution. The great +benefit of automated testing is that it requires minimal human intervention, and it can be built right into your +deployment pipelines. + +Automated testing also allows you to run repetitive and time-consuming tasks without testing each case manually and +avoid human errors, which can happen when you manually input tons of data. + +However, you must be careful, as automated testing can lead to false positives or miss certain edge cases. + +### Unit Tests + +In a nutshell, unit testing ensures that each function and component works correctly by evaluating each independently. +You can use unit tests to ensure that functions return the expected values and modify your contract's state properly. +They should be simple, quick to run and provide helpful feedback if anything goes wrong. This makes them an ideal tool +to ensure your contracts run smoothly after any modifications. + +#### Unit Testing Guidelines + +##### Understand the logic behind your contract’s workflow + +Before you can write any tests, you should understand how your contract is supposed to behave. You should know its +functionalities and how users will access them. Your tests should cover different functions a user may call when +interacting with the contract and check that functions are disabled when they should be. + +#### Evaluate your contract’s assumptions + +It is important to verify that every internal decision the contract takes matches your assumptions on how it should +behave. This forces you to think about edge cases rather than only thinking of the “happy path” you want your users to +take. You can write negative tests to assert how your contract would respond to invalid or malicious inputs. + +##### Measure Code Coverage + +Code coverage is a key metric when it comes to understanding the effectiveness of your tests. It measures the number of +lines, statements, and branches that are actually executed during your unit tests. If you don’t have thorough code +coverage, your test may give what is commonly known as a “false negative”, where your contract passed all your tests, +but your tests didn’t evaluate all the possible vulnerabilities. + +#### Unit Testing Frameworks + +The quality of your unit test will depend on the quality of the tools you use to write and execute them. You should use +a testing framework that is regularly maintained and updated, provides features that are relevant to your contract, and +is popular amongst other developers. + +:::tip Solo + +If you want to test ISC-specific functionalities, like the [magic contract](./core-contracts/introduction.md), you should use +the [Solo Framework](../solo/getting-started.md). + +::: + +* [Waffle](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html#writing-tests) +* [Remix](https://remix-ide.readthedocs.io/en/latest/unittesting.html#write-tests) +* [Hardhat](https://hardhat.org/hardhat-runner/docs/guides/test-contracts) +* [Brownie](https://eth-brownie.readthedocs.io/en/v1.0.0_a/tests.html) +* [Ape](https://docs.apeworx.io/ape/stable/userguides/testing.html) +* [Foundry](https://book.getfoundry.sh/forge/writing-tests) + +### Integration Tests + +Integration tests are beneficial when your contract adopts a modular architecture or interfaces with other contracts +during its execution. While [unit tests](#unit-tests) focus on testing functions in isolation, trying each cog in the +machine individually, so to speak, integration tests evaluate how these functions work together as a whole, testing the +machine as a whole. You should use integration tests to detect any issues arising from interactions between different +functions in your contracts' cross-contract calls and ensure that inherited or extended functions are working as +expected. + +#### Tools + +You can use the [EVM Testnet](/build/networks-endpoints/#shimmerevm-testnet) to conduct integration tests without +incurring any fees or the [IOTA Sandbox](/iota-sandbox/getting-started/) if you want to run the tests locally. + +## Manual Testing + +Once you have a complete batch of [automated tests](#automated-testing), manually testing your contract to ensure it +behaves as expected in the real world is still good practice. However, to avoid incurring fees or deploying a faulty +contract, you can manually test your contract using a sandboxed local network and the EVM Testnet. + +Testing using the [IOTA Sandbox](/iota-sandbox/getting-started/) serves well for the first stage of automated and manual +integration tests, as you have complete control over the entire local network. Once you are confident about how your +contract behaves locally, you can deploy and test on the [EVM Testnet](/build/networks-endpoints/#shimmerevm-testnet), +which replicates the IOTA EVM and ShimmerEVM networks, but also enables cost and risk-free interactions. + + diff --git a/docs/build/isc/v1.3/docs/introduction.md b/docs/build/isc/v1.3/docs/introduction.md new file mode 100644 index 00000000000..b3811792692 --- /dev/null +++ b/docs/build/isc/v1.3/docs/introduction.md @@ -0,0 +1,74 @@ +--- +description: 'The current release of IOTA Smart Contracts also has experimental support for EVM/Solidity, providing +limited compatibility with existing smart contracts and tooling from other EVM based chains like Ethereum.' +image: /img/logo/WASP_logo_dark.png +tags: + + - EVM + - Solidity + - smart contracts + - Ethereum + - explanation + +--- +import OnOffLedgerRequest from './_partials/_on_off_ledger_request.md'; + +# Introduction + +Smart contracts are deterministic applications that run on a distributed network with multiple +[validators](explanations/validators.md) that execute and validate the same code. +Their deterministic and distributed nature makes them predictable, stable and trustworthy. + +## Scalable Smart Contracts + +Due to the distributed nature of smart contracts, i.e. they run on a network of validators instead of a single computer, +the execution of smart contract is resource intensive as it has to deal with the overhead of the communication between validators in the network. +This can lead to relatively high [fees](#gas) for smart contract execution, as well as scalability issues when running on +a single blockchain. However, the IOTA Smart Contract Protocol allows **many blockchains that execute smart contracts to +run in parallel** and communicate with one another, therefore solving the scalability problem. Enabling interoperability and horizontal scaling of dApps. + +At the same time, ISC provides advanced means of communication between its chains and preserves the ability to create +complex, composed smart contracts. + +## ISC Architecture + +IOTA Smart Contracts (ISC) function as a Layer 2 extension to the IOTA Multi-Asset Ledger. +As validator nodes execute the smart contracts, they tally these state changes and write them into the chain. +In turn ISC chains, each with their state and smart contracts, update their state collectively and interact with Layer 1 +and other L2 chains, offering a sophisticated multi-chain architecture. + +![IOTA Smart Contacts multichain architecture](/img/multichain.png 'Click to see the full-size image.') + +_IOTA Smart Contacts multichain architecture._ + +[Explore the comprehensive overview of IOTA Smart Contracts in the ISC white paper](https://files.iota.org/papers/ISC_WP_Nov_10_2021.pdf). + +## Supported VMs + +The IOTA Smart Contracts currently +supports [EVM/Solidity](getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) +smart contracts, as well as an **experimental** [Wasm VM](getting-started/languages-and-vms.md#wasm-vm-for-isc). + +## Sandbox Interface + +ISC Smart contracts can access the [Sandbox interface](explanations/sandbox.md). +This interface provides access to the chain state, native assets, allows interaction with other contracts/chains, as +well as various utilities like cryptographic functions and event dispatching. + +![Sandbox](/img/sandbox.png) + +## Calling a Smart Contract + +### Entry Points and Requests + +Smart contracts are activated through entry points, similar to function calls. Entry points can be view-only or allow state +modifications. They are triggered by requests, signed by senders. Smart contracts on the same chain can +synchronously invoke each other, ensuring deterministic results. However, requests between chains are asynchronous and +may involve delays. + +### Gas + +Running a request consumes 'gas'. Gas units are a measurement of "how expensive" a computation is to execute. You can specify a `GasBudget` +for each request, with costs charged to your on-chain account. + + diff --git a/docs/build/isc/v1.3/docs/reference/.gitignore b/docs/build/isc/v1.3/docs/reference/.gitignore new file mode 100644 index 00000000000..31a1d0913e6 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/.gitignore @@ -0,0 +1,3 @@ +magic-contract/* +!magic-contract/introduction.md +iscutils diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/accounts.md b/docs/build/isc/v1.3/docs/reference/core-contracts/accounts.md new file mode 100644 index 00000000000..18a3f77e787 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/accounts.md @@ -0,0 +1,393 @@ +--- +description: 'The `accounts` contract keeps the ledger of on-chain accounts.' +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - accounts + - deposit + - withdraw + - assets + - balance + - reference +--- + +# The `accounts` Contract + +The `accounts` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +This contract keeps a consistent ledger of on-chain accounts in its state, +i.e. [the L2 ledger](../../explanations/how-accounts-work.md). + +--- + +## Entry Points + +The `accounts` contract provides functions to deposit and withdraw tokens, information about the assets deposited on the +chain, and the functionality to create and use foundries. + +### `deposit()` + +A no-op that has the side effect of crediting any transferred tokens to the sender's account. + +:::note Gas Fees + +As with every call, the gas fee is debited from the L2 account right after executing the request. + +::: + +### `withdraw()` + +Moves tokens from the caller's on-chain account to the caller's L1 address. The number of +tokens to be withdrawn must be specified via the allowance of the request. + +:::note Contract Account + +Because contracts does not have a corresponding L1 address it does not make sense to +have them call this function. It will fail with an error. + +::: + +:::note Storage Deposit + +A call to withdraw means that a L1 output will be created. Because of this, the withdrawn +amount must be able to cover the L1 storage deposit. Otherwise, it will fail. + +::: + +### `transferAllowanceTo(a AgentID)` + +Transfers the specified allowance from the sender's L2 account to the given L2 account on +the chain. + +:::note + +When a transfer is made into an EVM account, an EVM tx will be created on the EVM side from the zero address (0x0000...) to the target account. +Information about what is being transferred will be encoded in the transaction's data using the following format: + +``` + + +``` + +The encoding used for this data can be found on [TIP-51](https://github.com/jorgemmsilva/tips/blob/b46d7bc36a0f7d4c2a1ad32ba25ec2abb4835cb3/tips/TIP-0051/tip-0051.md) + +::: + +#### Parameters + +- `a` (`AgentID`): The target L2 account. + +### `transferAccountToChain(g GasReserve)` + +Transfers the specified allowance from the sender SC's L2 account on +the target chain to the sender SC's L2 account on the origin chain. + +#### Parameters + +- `g` (`uint64`): Optional gas amount to reserve in the allowance for + the internal call to transferAllowanceTo(). Default 100 (MinGasFee). + +:::note Important Detailed Information + +[Read carefully before using this function.](xfer.md) + +::: + +### `nativeTokenCreate(t TokenScheme, tn TokenName, ts TokenSymbol, td TokenDecimal) s SerialNumber` + +Creates a new foundry and registers it as a ERC20 and IRC30 token. + +You can call this end point from the CLI using `wasp-cli chain create-native-token -h` + +#### Parameters + +- `t` ([`iotago::TokenScheme`](https://github.com/iotaledger/iota.go/blob/develop/token_scheme.go)): The token scheme + for the new foundry. +- `tn` (`string`): The token name +- `ts` (`string`): The token symbol +- `td` (`uint8`): The token decimals + +The storage deposit for the new foundry must be provided via allowance (only the minimum required will be used). + +#### Returns + +- `s` (`uint32`): The serial number of the newly created foundry + +### `nativeTokenModifySupply(s SerialNumber, d SupplyDeltaAbs, y DestroyTokens)` + +Mints or destroys tokens for the given foundry, which must be controlled by the caller. + +#### Parameters + +- `s` (`uint32`): The serial number of the foundry. +- `d` (positive `big.Int`): Amount to mint or destroy. +- `y` (optional `bool` - default: `false`): Whether to destroy tokens (`true`) or not (`false`). + +When minting new tokens, the storage deposit for the new output must be provided via an allowance. + +When destroying tokens, the tokens to be destroyed must be provided via an allowance. + +### `nativeTokenDestroy(s SerialNumber)` + +Destroys a given foundry output on L1, reimbursing the storage deposit to the caller. The foundry must be owned by the +caller. + +:::warning + +This operation cannot be reverted. + +::: + +#### Parameters + +- `s` (`uint32`): The serial number of the foundry. + + +### `foundryCreateNew(t TokenScheme) s SerialNumber` + +:::warning Deprecated + +This function is deprecated, please use [`nativeTokenCreate`](#nativetokencreatet-tokenscheme-s-serialnumber) instead + +::: + +Creates a new foundry with the specified token scheme, and assigns the foundry to the sender. + +You can call this end point from the CLI using `wasp-cli chain create-foundry -h` + +#### Parameters + +- `t` ([`iotago::TokenScheme`](https://github.com/iotaledger/iota.go/blob/develop/token_scheme.go)): The token scheme + for the new foundry. + +The storage deposit for the new foundry must be provided via allowance (only the minimum required will be used). + +#### Returns + +- `s` (`uint32`): The serial number of the newly created foundry + + +### `mintNFT(I ImmutableData, a AgentID, C CollectionID, w WithdrawOnMint)` + +Mints an NFT with ImmutableData `I` that will be owned by the AgentID `a`. +It's possible to mint as part of a collection `C` (the caller must be the owner of the collection NFT to mint new NFTs as part of said collection). +The mint can be done directly to any L1 address (it is not necessary for the target to have an account on the chain) + +#### Parameters + +- `I` (`[]byte`): ImmutableData for the NFT. +- `a` (`AgentID`): AgentID that will be the owner of the NFT. +- `C` (optional `NFTID` - default empty): collectionID (NFTID) for the NFT. +- `w` (optional `bool` - default `false`): whether to withdrawal the NFT in the minting step (can only be `true` when the targetAgentID is a L1 address). + +#### Returns + +- `D` (`MintID`): the internal ID of the NFT at the time of minting that can be used by users/contracts to obtain the resulting NFTID on the next block + +--- + +## Views + +### `balance(a AgentID)` + +Returns the fungible tokens owned by the given Agent ID on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +A map of [`TokenID`](#tokenid) => `big.Int`. An empty token ID (a string of zero length) represents the L1 base token. + +### `balanceBaseToken(a AgentID)` + +Returns the amount of base tokens owned by any AgentID `a` on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +- `B` (`uint64`): The amount of base tokens in the account. + +### `balanceNativeToken(a AgentID, N TokenID)` + +Returns the amount of native tokens with Token ID `N` owned by any AgentID `a` on the chain. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. +- `N` ([`TokenID`](#tokenid)): The Token ID. + +#### Returns + +- `B` (`big.Int`): The amount of native tokens in the account. + +### `totalAssets()` + +Returns the sum of all fungible tokens controlled by the chain. + +#### Returns + +A map of [`TokenID`](#tokenid) => `big.Int`. An empty token ID (a string of zero length) represents the L1 base token. + +### `accounts()` + +Returns a list of all agent IDs that own assets on the chain. + +#### Returns + +A map of `AgentiD` => `0x01`. + +### `getNativeTokenIDRegistry()` + +Returns a list of all native tokenIDs that are owned by the chain. + +#### Returns + +A map of [`TokenID`](#tokenid) => `0x01` + +### `nativeToken(s FoundrySerialNumber)` + +#### Parameters + +- `s` ([`FoundrySerialNumber`](#foundryserialnumber)): The Foundry serial number. + +#### Returns + +- `b`: [`iotago::FoundryOutput`](https://github.com/iotaledger/iota.go/blob/develop/output_foundry.go) + +### `accountNFTs(a AgentID)` + +Returns the NFT IDs for all NFTs owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +- `i` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::NFTID`](https://github.com/iotaledger/iota.go/blob/develop/output_nft.go)): + The NFT IDs owned by the account + +### `accountNFTAmount(a AgentID)` + +Returns the number of NFTs owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +- `A` (`uint32`) Amount of NFTs owned by the account + +### `accountNFTsInCollection(a AgentID)` + +Returns the NFT IDs for all NFTs in the given collection that are owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID +- `C` (`NFTID`): The NFT ID of the collection + +#### Returns + +- `i` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::NFTID`](https://github.com/iotaledger/iota.go/blob/develop/output_nft.go)): + The NFT IDs in the collection owned by the account + +### `accountNFTAmountInCollection(a AgentID)` + +Returns the number of NFTs in the given collection that are owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID +- `C` (`NFTID`): The NFT ID of the collection + +#### Returns + +- `A` (`uint32`) Amount of NFTs in the collection owned by the account + +### `accountFoundries(a AgentID)` + +Returns all foundries owned by the given account. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID + +#### Returns + +A map of [`FoundrySerialNumber`](#foundryserialnumber) => `0x01` + +### `nftData(z NFTID)` + +Returns the data for a given NFT with ID `z` that is on the chain. + +#### Returns + +- `e`: [`NFTData`](#nftdata) + +### `NFTIDbyMintID(D MintID)` + +Returns the NFTID `z` for a given MintID `D`. + +#### Parameters + +- `D` (`MintID`): MintID producted at the time the NFT was minted + +#### Returns + +- `z` (`NFTID`): The ID of the NFT + +### `getAccountNonce(a AgentID)` + +Returns the current account nonce for a give AgentID `a`. +The account nonce is used to issue off-ledger requests. + +#### Parameters + +- `a` (`AgentID`): The account Agent ID. + +#### Returns + +- `n` (`uint64`): The account nonce. + +## Schemas + +### `FoundrySerialNumber` + +``` +FoundrySerialNumber = uint32 +``` + +### `TokenID` + +``` +TokenID = [38]byte +``` + +### `NFTID` + +``` +NFTID = [32]byte +``` + +### `MintID` + +``` +MintID = [6]byte +``` + +### `NFTData` + +`NFTData` is encoded as the concatenation of: + +- The issuer ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)). +- The NFT metadata: the length (`uint16`) followed by the data bytes. +- The NFT owner (`AgentID`). diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/blob.md b/docs/build/isc/v1.3/docs/reference/core-contracts/blob.md new file mode 100644 index 00000000000..67e516e2a0a --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/blob.md @@ -0,0 +1,108 @@ +--- +description: The `blobs` contract maintains a registry of _blobs_ (a collection of arbitrary binary data) referenced from smart contracts via their hashes. +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - bloc + - binary data + - store + - get + - entry points + - views + - reference +--- + +# The `blob` Contract + +The `blob` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The objective of the `blob` contract is to maintain an on-chain registry of _blobs_. +A blob is a collection of named chunks of binary data. + +``` +: +: +... +: +``` + +Both names and chunks are arbitrarily long byte slices. + +Blobs can be used to store arbitrary data like, for example, a collection of Wasm binaries needed to deploy a smart contract. + +Each blob in the registry is referenced by its hash. The hash is deterministically calculated from the concatenation of all pieces: + +``` +blobHash = hash( fieldName1 || binaryChunk1 || fieldName2 || binaryChunk2 || ... || fieldNameN || binaryChunkN) +``` + +Usually, field names are short strings, but their interpretation is use-case specific. + +Two predefined field names are interpreted by the VM while deploying smart contracts from binary: + +- _fieldname_ = `"v"` is interpreted as the _VM type_. +- _fieldname_ = `"p"` is interpreted as the _smart contract program binary_. + +If the field `"v"` is equal to the string `"wasmtime"`, the binary chunk of `"p"` is interpreted as WebAssembly binary, executable by the Wasmtime interpreter. + +The blob describing a smart contract may contain extra fields (ignored by the VM), for example: + +``` +"v" : VM type +"p" : smart contract program binary +"d" : data schema for data exchange between smart contract and outside sources and consumers +"s" : program sources in .zip format +``` + +--- + +## Entry Points + +### `storeBlob()` + +Stores a new blob in the registry. + +#### Parameters + +The key/value pairs of the received parameters are interpreted as the field/chunk pairs of the blob. + +#### Returns + +- `hash` (`[32]byte`): The hash of the stored blob. + +--- + +## Views + +### `getBlobInfo(hash BlobHash)` + +Returns the size of each chunk of the blob. + +#### Parameters + +- `hash` (`[32]byte`): The hash of the blob. + +#### Returns + +``` +: (uint32) +... +: (uint32) +``` + +### `getBlobField(hash BlobHash, field BlobField)` + +Returns the chunk associated with the given blob field name. + +#### Parameters + +- `hash` (`[32]byte`): The hash of the blob. +- `field` (`[]byte`): The field name. + +#### Returns + +- `bytes` (`[]byte`): The chunk associated with the given field name. + +### `listBlobs()` + +Returns a list of pairs `blob hash`: `total size of chunks` (`uint32`) for all blobs in the registry. diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/blocklog.md b/docs/build/isc/v1.3/docs/reference/core-contracts/blocklog.md new file mode 100644 index 00000000000..c78d57d17a6 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/blocklog.md @@ -0,0 +1,202 @@ +--- +description: The `blocklog` contract keeps track of the blocks of requests processed by the chain. +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - blocklog + - views + - information + - request status + - receipts + - events + - reference +--- + +# The `blocklog` Contract + +The `blocklog` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The `blocklog` contract keeps track of the blocks of requests processed by the chain, providing views to get request +status, receipts, block, and event details. + +To avoid having a monotonically increasing state size, only the latest `N` +blocks (and their events and receipts) are stored. This parameter can be configured +when [deploying the chain](/wasp/how-tos/setting-up-a-chain). + +--- + +## Entry Points + +### `retryUnprocessable(u requestID)` + +Tries to retry a given request that was marked as "unprocessable". + +:::note +"Unprocessable" requests are on-ledger requests that do not include enough base tokens to cover the deposit fees (example if an user tries to deposit many native tokens in a single output but only includes the minimum possible amount of base tokens). Such requests will be collected into an "unprocessable list" and users are able to deposit more funds onto their on-chain account and retry them afterwards. +::: + +#### Parameters + +- `u` ([`isc::RequestID`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)): The requestID to be retried. (sender of the retry request must match the sender of the "unprocessable" request) + +--- + +## Views + +### `getBlockInfo(n uint32)` + +Returns information about the block with index `n`. + +#### Parameters + +- `n`: (optional `uint32`) The block index. Default: the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `i` ([`BlockInfo`](#blockinfo)):The information about the block. + +### `getRequestIDsForBlock(n uint32)` + +Returns a list with all request IDs in the block with block index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. The default value is the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `u`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`RequestID`](#requestid)) + +### `getRequestReceipt(u RequestID)` + +Returns the receipt for the request with the given ID. + +#### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `n` (`uint32`):The block index. +- `r` (`uint16`):The request index within the block. +- `d` ([`RequestReceipt`](#requestreceipt)):The request receipt. + +### `getRequestReceiptsForBlock(n uint32)` + +Returns all the receipts in the block with index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. Defaults to the latest block. + +#### Returns + +- `n` (`uint32`):The block index. +- `d`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`RequestReceipt`](#requestreceipt)) + +### `isRequestProcessed(u RequestID)` + +Returns whether the request with ID `u` has been processed. + +#### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `p` (`bool`):Whether the request was processed or not. + +### `getEventsForRequest(u RequestID)` + +Returns the list of events triggered during the execution of the request with ID `u`. + +### Parameters + +- `u` ([`RequestID`](#requestid)):The request ID. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`). + +### `getEventsForBlock(n blockIndex)` + +Returns the list of events triggered during the execution of all requests in the block with index `n`. + +#### Parameters + +- `n` (optional `uint32`):The block index. Defaults to the latest block. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`). + +### `getEventsForContract(h Hname)` + +Returns a list of events triggered by the smart contract with hname `h`. + +#### Parameters + +- `h` (`hname`):The smart contract’s hname. +- `f` (optional `uint32` - default: `0`):"From" block index. +- `t` (optional `uint32` - default: `MaxUint32`):"To" block index. + +#### Returns + +- `e`: ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) of `[]byte`) + +### `hasUnprocessable(u requestID)` + +Asserts whether or not a given requestID (`u`) is present in the "unprocessable list" + +#### Parameters + +- `u` ([`isc::RequestID`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)): The requestID to be checked + +#### Returns + +- `x` ([`bool`]) Whether or not the request exists in the "unprocessable list" + +--- + +## Schemas + +### `RequestID` + +A `RequestID` is encoded as the concatenation of: + +- Transaction ID (`[32]byte`). +- Transaction output index (`uint16`). + +### `BlockInfo` + +`BlockInfo` is encoded as the concatenation of: + +- The block timestamp (`uint64` UNIX nanoseconds). +- Amount of requests in the block (`uint16`). +- Amount of successful requests (`uint16`). +- Amount of off-ledger requests (`uint16`). +- Anchor transaction ID ([`iotago::TransactionID`](https://github.com/iotaledger/iota.go/blob/develop/transaction.go)). +- Anchor transaction sub-essence hash (`[32]byte`). +- Previous L1 commitment (except for block index 0). + - Trie root (`[20]byte`). + - Block hash (`[20]byte`). +- Total base tokens in L2 accounts (`uint64`). +- Total storage deposit (`uint64`). +- Gas burned (`uint64`). +- Gas fee charged (`uint64`). + +### `RequestReceipt` + +`RequestReceipt` is encoded as the concatenation of: + +- Gas budget (`uint64`). +- Gas burned (`uint64`). +- Gas fee charged (`uint64`). +- The request ([`isc::Request`](https://github.com/iotaledger/wasp/blob/develop/packages/isc/request.go)). +- Whether the request produced an error (`bool`). +- If the request produced an error, the + [`UnresolvedVMError`](./errors.md#unresolvedvmerror). diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/errors.md b/docs/build/isc/v1.3/docs/reference/core-contracts/errors.md new file mode 100644 index 00000000000..e4e5dbb2244 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/errors.md @@ -0,0 +1,77 @@ +--- +description: 'The errors contract keeps a map of error codes to error message templates. These error codes are used in +request receipts.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `errors` Contract + +The `errors` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `errors` contract keeps a map of error codes to error message templates. +This allows contracts to store lengthy error strings only once and then reuse them by just providing the error code (and +optional extra values) when producing an error, thus saving storage and gas. + +--- + +## Entry Points + +### `registerError(m ErrorMessageFormat) c ErrorCode` + +Registers an error message template. + +#### Parameters + +- `m` (`string`): The error message template, which supports standard [go verbs](https://pkg.go.dev/fmt#hdr-Printing) + for variable printing. + +#### Returns + +- `c` (`ErrorCode`): The error code of the registered template + +--- + +## Views + +### `getErrorMessageFormat(c ErrorCode) m ErrorMessageFormat` + +Returns the message template stored for a given error code. + +#### Parameters + +- `c` (`ErrorCode`): The error code of the registered template. + +#### Returns + +- `m` (`string`): The error message template. + +--- + +## Schemas + +### `ErrorCode` + +`ErrorCode` is encoded as the concatenation of: + +- The contract hname(`hname`). +- The error ID, calculated as the hash of the error template(`uint16`). + +### `UnresolvedVMError` + +`UnresolvedVMError` is encoded as the concatenation of: + +- The error code ([`ErrorCode`](#errorcode)). +- CRC32 checksum of the formatted string (`uint32`). +- The JSON-encoded list of parameters for the template (`string` prefixed with `uint16` size). diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/evm.md b/docs/build/isc/v1.3/docs/reference/core-contracts/evm.md new file mode 100644 index 00000000000..99be19b75bc --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/evm.md @@ -0,0 +1,170 @@ +--- +description: 'The evm core contract provides the necessary infrastructure to accept Ethereum transactions and execute +EVM code.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `evm` Contract + +The `evm` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts chain. + +The `evm` core contract provides the necessary infrastructure to accept Ethereum transactions and execute EVM code. +It also includes the implementation of the [ISC Magic contract](../../how-tos/core-contracts/introduction.md). + +:::note + +For more information about how ISC supports EVM contracts, refer to the [EVM](../../getting-started/languages-and-vms.md#evmsolidity-based-smart-contracts) section. + +::: + +--- + +## Entry Points + +Most entry points of the `evm` core contract are meant to be accessed through the JSON-RPC service provided +automatically by the Wasp node so that the end users can use standard EVM tools like [MetaMask](https://metamask.io/). +We only list the entry points not exposed through the JSON-RPC interface in this document. + +### `init()` + +Called automatically when the ISC is deployed. + +Some parameters of the `evm` contract can be specified by passing them to the +[`root` contract `init` entry point](root.md#init): + +- `evmg` (optional [`GenesisAlloc`](#genesisalloc)): The genesis allocation. The balance of all accounts must be 0. +- `evmbk` (optional `int32` - default: keep all): Amount of EVM blocks to keep in the state. +- `evmchid` (optional `uint16` - default: 1074): EVM chain iD + + :::caution + + Re-using an existing Chain ID is not recommended and can be a security risk. For serious usage, register a unique + Chain ID on [Chainlist](https://chainlist.org/) and use that instead of the default. **It is not possible to change + the EVM chain ID after deployment.** + + ::: + +- `evmw` (optional [`GasRatio`](#gasratio) - default: `1:1`): The ISC to EVM gas ratio. + +### `registerERC20NativeToken` + +Registers an ERC20 contract to act as a proxy for the native tokens, at address +`0x107402xxxxxxxx00000000000000000000000000`, where `xxxxxxxx` is the +little-endian encoding of the foundry serial number. + +Only the foundry owner can call this endpoint. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals + +You can call this endpoint with the `wasp-cli register-erc20-native-token` command. See +`wasp-cli chain register-erc20-native-token -h` for instructions on how to use the command. + +### `registerERC20NativeTokenOnRemoteChain` + +Registers an ERC20 contract to act as a proxy for the native tokens **on another +chain**. + +The foundry must be controlled by this chain. Only the foundry owner can call +this endpoint. + +This endpoint is intended to be used in case the foundry is controlled by chain +A, and the owner of the foundry wishes to register the ERC20 contract on chain +B. In that case, the owner must call this endpoint on chain A with `target = +chain B`. The request to chain B is then sent as an on-ledger request. +After a few minutes, call +[`getERC20ExternalNativeTokenAddress`](#geterc20externalnativetokenaddress) +on chain B to find out the address of the ERC20 contract. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals +- `A` (`uint8`): The target chain address, where the ERC20 contract will be + registered. + +You can call this endpoint with the `wasp-cli register-erc20-native-token-on-remote-chain` command. See +`wasp-cli chain register-erc20-native-token-on-remote-chain -h` for instructions on how to use the command. + +### `registerERC20ExternalNativeToken` + +Registers an ERC20 contract to act as a proxy for the native tokens. + +Only an alias address can call this endpoint. + +If the foundry is controlled by another ISC chain, the foundry owner can call +[`registerERC20NativeTokenOnRemoteChain`](#registererc20nativetokenonchain) +on that chain, which will automatically call this endpoint on the chain set as +target. + +#### Parameters + +- `fs` (`uint32`): The foundry serial number +- `n` (`string`): The token name +- `t` (`string`): The ticker symbol +- `d` (`uint8`): The token decimals +- `T` (`TokenScheme`): The native token scheme + +### `registerERC721NFTCollection` + +Registers an ERC721 contract to act as a proxy for an NFT collection, at address +`0x107404xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`, where `xxx...` is the first 17 +bytes of the collection ID. + +The call will fail if the address is taken by another collection with the same prefix. + +#### Parameters + +- `C` (`NTFID`): The collection ID + +--- + +## Views + +### `getERC20ExternalNativeTokenAddress` + +Returns the address of an ERC20 contract registered with +[`registerERC20NativeTokenOnRemoteChain`](#registererc20nativetokenonchain). + +Only the foundry owner can call this endpoint. + +#### Parameters + +- `N` (`NativeTokenID`): The native token ID + +--- + +## Schemas + +### `GenesisAlloc` + +`GenesisAlloc` is encoded as the concatenation of: + +- Amount of accounts `n` (`uint32`). +- `n` times: + - Ethereum address (`[]byte` prefixed with `uint32` size). + - Account code (`[]byte` prefixed with `uint32` size). + - Amount of storage key/value pairs `m`(`uint32`). + - `m` times: + - Key (`[]byte` prefixed with `uint32` size). + - Value(`[]byte` prefixed with `uint32` size). + - Account balance (must be 0)(`[]byte` prefixed with `uint32` size). + - Account nonce (`uint64`). + - Account private key (may be used for tests)(`uint64`). diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/governance.md b/docs/build/isc/v1.3/docs/reference/core-contracts/governance.md new file mode 100644 index 00000000000..9958c2a9ad8 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/governance.md @@ -0,0 +1,353 @@ +--- +description: 'The `governance` contract defines the set of identities that constitute the state controller, access nodes, +who is the chain owner, and the fees for request execution.' +image: /img/logo/WASP_logo_dark.png +tags: + +- core contracts +- governance +- state controller +- identities +- chain owner +- rotate +- remove +- claim +- add +- chain info +- fee info +- reference +--- + +# The `governance` Contract + +The `governance` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `governance` contract provides the following functionalities: + +- It defines the identity set that constitutes the state controller (the entity that owns the state output via the chain + Alias Address). It is possible to add/remove addresses from the state controller (thus rotating the committee of + validators). +- It defines the chain owner (the L1 entity that owns the chain - initially whoever deployed it). The chain owner can + collect special fees and customize some chain-specific parameters. +- It defines the entities allowed to have an access node. +- It defines the fee policy for the chain (gas price, what token is used to pay for gas, and the validator fee share). + +--- + +## Fee Policy + +The Fee Policy looks like the following: + +```go +{ + GasPerToken Ratio32 // how many gas units are paid for each token + EVMGasRatio Ratio32 // the ratio at which EVM gas is converted to ISC gas + ValidatorFeeShare uint8 // percentage of the fees that are credited to the validators (0 - 100) +} +``` + +--- + +## Entry Points + +### `rotateStateController(S StateControllerAddress)` + +Called when the committee is about to be rotated to the new address `S`. + +If it succeeds, the next state transition will become a governance transition, thus updating the state controller in the +chain's Alias Output. If it fails, nothing happens. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address of the next + state controller. Must be an + [allowed](#addallowedstatecontrolleraddresss-statecontrolleraddress) state controller address. + +### `addAllowedStateControllerAddress(S StateControllerAddress)` + +Adds the address `S` to the list of identities that constitute the state controller. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address to add to the + set of allowed state controllers. + +### `removeAllowedStateControllerAddress(S StateControllerAddress)` + +Removes the address `S` from the list of identities that constitute the state controller. + +It can only be invoked by the chain owner. + +#### Parameters + +- `S` ([`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The address to remove from + the set of allowed state controllers. + +### `delegateChainOwnership(o AgentID)` + +Sets the Agent ID `o` as the new owner for the chain. This change will only be effective +once [`claimChainOwnership`](#claimchainownership) is called by `o`. + +It can only be invoked by the chain owner. + +#### Parameters + +- `o` (`AgentID`): The Agent ID of the next chain owner. + +### `claimChainOwnership()` + +Claims the ownership of the chain if the caller matches the identity set +in [`delegateChainOwnership`](#delegatechainownershipo-agentid). + +### `setFeePolicy(g FeePolicy)` + +Sets the fee policy for the chain. + +#### Parameters + +- `g`: ([`FeePolicy`](#feepolicy)). + +It can only be invoked by the chain owner. + +### `setGasLimits(l GasLimits)` + +Sets the gas limits for the chain. + +#### Parameters + +- `l`: ([`GasLimits`](#gaslimits)). + +It can only be invoked by the chain owner. + +### `setEVMGasRatio(e Ratio32)` + +Sets the EVM gas ratio for the chain. + +#### Parameters + +- `e` ([`Ratio32`](#ratio32)): The EVM gas ratio. + +It can only be invoked by the chain owner. + +### `addCandidateNode(ip PubKey, ic Certificate, ia API, i ForCommittee)` + +Adds a node to the list of candidates. + +#### Parameters + +- `ip` (`[]byte`): The public key of the node to be added. +- `ic` (`[]byte`): The certificate is a signed binary containing both the node public key and their L1 address. +- `ia` (`string`): The API base URL for the node. +- `i` (optional `bool` - default: `false`): Whether the candidate node is being added to be part of the committee or + just an access node. + +It can only be invoked by the access node owner (verified via the Certificate field). + +### `revokeAccessNode(ip PubKey, ic Certificate, ia API, i ForCommittee)` + +Removes a node from the list of candidates. + +#### Parameters + +- `ip` (`[]byte`): The public key of the node to be removed. +- `ic` (`[]byte`): The certificate of the node to be removed. + +It can only be invoked by the access node owner (verified via the Certificate field). + +### `changeAccessNodes(n actions)` + +Iterates through the given map of actions and applies them. + +#### Parameters + +- `n` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) of `public key` => `byte`): + The list of actions to perform. Each byte value can be one of the following: + - `0`: Remove the access node from the access nodes list. + - `1`: Accept a candidate node and add it to the list of access nodes. + - `2`: Drop an access node from the access node and candidate lists. + +It can only be invoked by the chain owner. + +### `startMaintenance()` + +Starts the chain maintenance mode, meaning no further requests will be processed except +calls to the governance contract. + +It can only be invoked by the chain owner. + +### `stopMaintenance()` + +Stops the maintenance mode. + +It can only be invoked by the chain owner. + +### `setCustomMetadata(x bytes)` + +Changes optional extra metadata that is appended to the L1 AliasOutput. + +#### Parameters + +- `x` (`bytes`): the optional metadata + +### `setPayoutAgentID` + +`setPayoutAgentID` sets the payout AgentID. The default AgentID is the chain owner. Transaction fee will be taken to ensure the common account has minimum storage deposit which is in base token. The rest of transaction fee will be transferred to payout AgentID. + +#### Parameters + +- `s` (`AgentID`): the payout AgentID + +### `setMinCommonAccountBalance` + +`setMinCommonAccountBalance` sets the minimum balanced to be held in the common account. + +#### Parameters + +- `ms` (`AgentID`): the minimum common account balance + +--- + +## Views + +### `getAllowedStateControllerAddresses()` + +Returns the list of allowed state controllers. + +#### Returns + +- `a` ([`Array`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/array.go) + of [`iotago::Address`](https://github.com/iotaledger/iota.go/blob/develop/address.go)): The list of allowed state + controllers. + +### `getChainOwner()` + +Returns the AgentID of the chain owner. + +#### Returns + +- `o` (`AgentID`): The chain owner. + +### `getChainInfo()` + +Returns information about the chain. + +#### Returns + +- `c` (`ChainID`): The chain ID +- `o` (`AgentID`): The chain owner +- `g` ([`FeePolicy`](#feepolicy)): The gas fee policy +- `l` ([`GasLimits`](#gaslimits)): The gas limits +- `x` (`bytes`): The custom metadata + +### `getFeePolicy()` + +Returns the gas fee policy. + +#### Returns + +- `g` ([`FeePolicy`](#feepolicy)): The gas fee policy. + +### `getEVMGasRatio` + +Returns the ISC : EVM gas ratio. + +#### Returns + +- `e` ([`Ratio32`](#ratio32)): The ISC : EVM gas ratio. + +### `getGasLimits()` + +Returns the gas limits. + +#### Returns + +- `l` ([`GasLimits`](#gaslimits)): The gas limits. + +### `getChainNodes()` + +Returns the current access nodes and candidates. + +#### Returns + +- `ac` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) + of public key => `0x01`): The access nodes. +- `an` ([`Map`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/collections/map.go) + of public key => [`AccessNodeInfo`](#accessnodeinfo)): The candidate nodes. + +### `getMaintenanceStatus()` + +Returns whether the chain is undergoing maintenance. + +#### Returns + +- `m` (`bool`): `true` if the chain is in maintenance mode + +### `getCustomMetadata()` + +Returns the extra metadata that is added to the chain AliasOutput. + +#### Returns + +- `x` (`bytes`): the optional metadata + +### `getPayoutAgentID` + +`getPayoutAgentID` gets the payout AgentID. + +Returns the payout AgentID of the chain. + +#### Returns + +- `s` (`AgentID`): the payout AgentID. + +### `getMinCommonAccountBalance` + +`getMinCommonAccountBalance` returns the minimum balanced to be held in the common account. + +#### Returns + +- `ms` (`uint64`): the minimum storage deposit. + +## Schemas + +### `Ratio32` + +A ratio between two values `x` and `y`, expressed as two `int32` numbers `a:b`, where `y = x * b/a`. + +`Ratio32` is encoded as the concatenation of the two `uint32` values `a` & `b`. + +### `FeePolicy` + +`FeePolicy` is encoded as the concatenation of: + +- Gas per token ([`Ratio32`](#ratio32)): expressed as an `a:b` (`gas/token`) ratio, meaning how many gas units each token pays for. +- Validator fee share. Must be between 0 and 100, meaning the percentage of the gas fees distributed to the + validators. (`uint8`) +- The ISC:EVM gas ratio ([`Ratio32`](#ratio32)): such that `ISC gas = EVM gas * a/b`. + +### `GasLimits` + +`GasLimits` is encoded as the concatenation of: + +- The maximum gas per block (`uint64`). A request that exceeds this limit is + skipped and processed in the next block. +- The minimum gas per request (`uint64`). If a request consumes less than this + value, it is charged for this instead. +- The maximum gas per request (`uint64`). If a request exceeds this limit, it + is rejected as failed. +- The maximum gas per external view call (`uint64). This is the gas budget + assigned to external view calls. + +### `AccessNodeInfo` + +`AccessNodeInfo` is encoded as the concatenation of: + +- The validator address. (`[]byte` prefixed by `uint16` size) +- The certificate. (`[]byte` prefixed by `uint16` size) +- Whether the access node is part of the committee of validators. (`bool`) +- The API base URL. (`string` prefixed by `uint16` size) diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/overview.md b/docs/build/isc/v1.3/docs/reference/core-contracts/overview.md new file mode 100644 index 00000000000..e3d70cd2419 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/overview.md @@ -0,0 +1,37 @@ +--- +description: There currently are 6 core smart contracts that are always deployed on each chain, root, _default, accounts, blob, blocklog, and governance. +image: /img/banner/banner_wasp_core_contracts_overview.png +tags: + - smart contracts + - core + - initialization + - request handling + - on-chain ledger + - accounts + - data + - receipts + - reference +--- + +# Core Contracts + +![Wasp Node Core Contracts Overview](/img/banner/banner_wasp_core_contracts_overview.png) + +There are currently 7 core smart contracts that are always deployed on each +chain. These are responsible for the vital functions of the chain and +provide infrastructure for all other smart contracts: + +- [`root`](./root.md): Responsible for the initialization of the chain, maintains registry of deployed contracts. + +- [`accounts`](./accounts.md): Manages the on-chain ledger of accounts. + +- [`blob`](./blob.md): Responsible for the registry of binary objects of arbitrary size. + +- [`blocklog`](./blocklog.md): Keeps track of the blocks and receipts of requests that were processed by the chain. + +- [`governance`](./governance.md): Handles the administrative functions of the chain. For example: rotation of the committee of validators of the chain, fees and other chain-specific configurations. + +- [`errors`](./errors.md): Keeps a map of error codes to error messages templates. These error codes are used in request receipts. + +- [`evm`](./evm.md): Provides the necessary infrastructure to accept Ethereum + transactions and execute EVM code. diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/root.md b/docs/build/isc/v1.3/docs/reference/core-contracts/root.md new file mode 100644 index 00000000000..439e438befb --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/root.md @@ -0,0 +1,121 @@ +--- +description: 'The root contract is the first smart contract deployed on the chain. It functions as a smart contract +factory for the chain.' +image: /img/logo/WASP_logo_dark.png +tags: + +- smart contracts +- core +- root +- initialization +- entry points +- fees +- ownership +- views +- reference +--- + +# The `root` Contract + +The `root` contract is one of the [core contracts](overview.md) on each IOTA Smart Contracts +chain. + +The `root` contract is responsible for the initialization of the chain. +It is the first smart contract deployed on the chain and, upon receiving the `init` request, bootstraps the state of the +chain. +Deploying all of the other core contracts is a part of the state initialization. + +The `root` contract also functions as a smart contract factory for the chain: upon request, it deploys other smart +contracts and maintains an on-chain registry of smart contracts in its state. +The contract registry keeps a list of contract records containing their respective name, hname, description, and +creator. + +--- + +## Entry Points + +### `init()` + +The constructor. Automatically called immediately after confirmation of the origin transaction and never called again. +When executed, this function: + +- Initializes base values of the chain according to parameters. +- Sets the caller as the _chain owner_. +- Deploys all the core contracts. + +### `deployContract(ph ProgramHash, nm Name, ds Description)` + +Deploys a non-EVM smart contract on the chain if the caller has deployment permission. + +#### Parameters + +- `ph` (`[32]byte`): The hash of the binary _blob_ (that has been previously stored in the [`blob` contract](blob.md)). +- `nm` (`string`): The name of the contract to be deployed, used to calculate the + contract's _hname_. The hname must be unique among all contract hnames in the chain. +- `ds` (`string`): Description of the contract to be deployed. + +Any other parameters that are passed to the deployContract function will be passed on to +the `init` function of the smart contract being deployed. Note that this means that the +init parameter names cannot be the above ones, as they will have been filtered out. + +### `grantDeployPermission(dp AgentID)` + +The chain owner grants deploy permission to the agent ID `dp`. + +#### Parameters + +`dp`(AgentID): The agent ID. + +### `revokeDeployPermission(dp AgentID)` + +The chain owner revokes the deploy permission of the agent ID `dp`. + +#### Parameters + +`dp`(AgentID): The agent ID. + +### `requireDeployPermissions(de DeployPermissionsEnabled)` + +#### Parameters + +- `de` (`bool`): Whether permissions should be required to deploy a contract on the chain. + +By default, permissions are enabled (addresses need to be granted the right to deploy), but the chain owner can override +this setting to allow anyone to deploy contracts on the chain. + +--- + +## Views + +### `findContract(hn Hname)` + +Returns the record for a given smart contract with Hname `hn` (if it exists). + +#### Parameters + +`hn`: The smart contract’s Hname + +#### Returns + +- `cf` (`bool`): Whether or not the contract exists. +- `dt` ([`ContractRecord`](#contractrecord)): The requested contract record (if it exists). + +### `getContractRecords()` + +Returns the list of all smart contracts deployed on the chain and related records. + +#### Returns + +A map of `Hname` => [`ContractRecord`](#contractrecord) + +--- + +## Schemas + +### `ContractRecord` + +A `ContractRecord` is encoded as the concatenation of: + +- Program hash (`[32]byte`). +- Contract description (`string`). +- Contract name (`string`). diff --git a/docs/build/isc/v1.3/docs/reference/core-contracts/xfer.md b/docs/build/isc/v1.3/docs/reference/core-contracts/xfer.md new file mode 100644 index 00000000000..208316b58c8 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/core-contracts/xfer.md @@ -0,0 +1,71 @@ +--- +description: 'The `transferAccountToChain` contract needs special consideration.' +image: /img/logo/WASP_logo_dark.png +tags: + - core contracts + - accounts + - deposit + - withdraw + - assets + - balance + - reference +--- + +# `accounts.transferAccountToChain` + +The `transferAccountToChain` function of the `accounts` contract is one that needs +careful consideration before use. Make sure you understand precisely how to use it to +prevent + +--- + +## Entry Point + +### `transferAccountToChain(g GasReserve)` + +Transfers the specified allowance from the sender SC's L2 account on +the target chain to the sender SC's L2 account on the origin chain. + +Caller must be a contract, and we will transfer the allowance from its L2 account +on the target chain to its L2 account on the origin chain. This requires that +this function takes the allowance into custody and in turn sends the assets as +allowance to the origin chain, where that chain's accounts.TransferAllowanceTo() +function then transfers it into the caller's L2 account on that chain. + +#### Parameters + +- `g` (`uint64`): Optional gas amount to reserve in the allowance for + the internal call to transferAllowanceTo(). Default 100 (MinGasFee). + But better to provide it so that it matches the fee structure. + +### IMPORTANT CONSIDERATIONS + +1. The caller contract needs to provide sufficient base tokens in its + allowance, to cover the gas fee GAS1 for this request. + Note that this amount depends on the fee structure of the target chain, + which can be different from the fee structure of the caller's own chain. + +2. The caller contract also needs to provide sufficient base tokens in + its allowance, to cover the gas fee GAS2 for the resulting request to + accounts.TransferAllowanceTo() on the origin chain. The caller needs to + also specify this GAS2 amount through the GasReserve parameter. + +3. The caller contract also needs to provide a storage deposit SD with + this request, holding enough base tokens _independent_ of the GAS1 and + GAS2 amounts. + Since this storage deposit is dictated by L1 we can use this amount as + storage deposit for the resulting accounts.TransferAllowanceTo() request, + where it will then be returned to the caller as part of the transfer. + +4. This means that the caller contract needs to provide at least + GAS1 + GAS2 + SD base tokens as assets to this request, and provide an + allowance to the request that is exactly GAS2 + SD + transfer amount. + Failure to meet these conditions may result in a failed request and + worst case the assets sent to accounts.TransferAllowanceTo() could be + irretrievably locked up in an account on the origin chain that belongs + to the accounts core contract of the target chain. + +5. The caller contract needs to set the gas budget for this request to + GAS1 to guard against unanticipated changes in the fee structure that + raise the gas price, otherwise the request could accidentally cannibalize + GAS2 or even SD, with potential failure and locked up assets as a result. diff --git a/docs/build/isc/v1.3/docs/reference/json-rpc-spec.md b/docs/build/isc/v1.3/docs/reference/json-rpc-spec.md new file mode 100644 index 00000000000..e15f1c9684d --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/json-rpc-spec.md @@ -0,0 +1,68 @@ +# JSON-RPC API + +The [JSON-RPC](https://www.jsonrpc.org/specification) is a stateless, lightweight remote procedure call (RPC) protocol. It defines several data structures and the rules around their processing. It is transport agnostic because the concepts can be used within the same process, over sockets, HTTP, or in various message-passing environments. It uses JSON (RFC 4627) as data format. + +This page deals with the JSON-RPC API used by EVM execution clients. + +## JSON-RPC Methods According to [Ethereum Client API](https://ethereum.org/en/developers/docs/apis/json-rpc/) + + +| Method | Description | Status | +|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------| +| [eth_getBlockByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash) | _Returns information about a block by hash_ | ✅ | +| [eth_getBlockByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) | _Returns information about a block by number_ | ✅ | +| [eth_getBlockTransactionCountByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash) | _Returns the number of transactions in a block from a block matching the given block hash_ | ✅ | +| [eth_getBlockTransactionCountByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber) | _Returns the number of transactions in a block matching the given block number_ | ✅ | +| [eth_getUncleCountByBlockHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblockhash) | _Returns the number of uncles in a block from a block matching the given block hash_ | ✅ | +| [eth_getUncleCountByBlockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblocknumber) | _Returns the number of uncles in a block from a block matching the given block number_ | ✅ | +| [eth_protocolVersion](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_protocolversion) | _Returns the current Ethereum protocol version_ | ✅ | +| [eth_chainId](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid) | _Returns the chain ID of the current network_ | ✅ | +| [eth_syncing](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing) | _Returns an object with data about the sync status or false-copy_ | ✅ | +| [eth_coinbase](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_coinbase) | _Returns the client Coinbase address_ | ✅ | +| [eth_accounts](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts) | _Returns a list of addresses owned by client_ | ✅ | +| [eth_blockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber) | _Returns the number of most recent block._ | ✅ | +| [eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) | _Executes a new message call immediately without creating a transaction on the blockchain_ | ✅ | +| [eth_estimateGas](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas) | _Generates and returns an estimate of how much gas is necessary to allow the transaction to complete._ | ✅ | +| [eth_gasPrice](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice) | _Returns the current price per gas in wei_ | ✅ | +| [eth_feeHistory](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_feehistory) | _Returns fee history_ | ✅ | +| [eth_newFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter) | _Creates a filter object, based on filter options, to notify when the state changes (logs)_ | ❌ | +| [eth_newBlockFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newblockfilter) | _Creates a filter in the node, to notify when a new block arrives_ | ❌ | +| [eth_newPendingTransactionFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter) | _Creates a filter in the node, to notify when new pending transactions arrive_ | ❌ | +| [eth_uninstallFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallfilter) | _Uninstalls a filter with given id_ | ❌ | +| [eth_getFilterChanges](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges) | _Polling method for a filter, which returns an array of logs which occurred since last poll_| ❌ | +| [eth_getFilterLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs) | _Returns an array of all logs matching filter with given id. Can compute the same results with an `eth_getLogs call`_ | ❌ | +| [eth_getLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) | _Anytime a transaction is mined, we can see event logs for that transaction by making a request to eth_getLogs and then take actions based off those results_ | ✅ | +| [eth_mining](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_mining) | _Returns whether the client is actively mining new blocks_ | ✅ | +| [eth_hashrate](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_hashrate) | _Returns the number of hashes per second that the node is mining with_ | ✅ | +| [eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) | _Returns an EIP-191 signature over the provided data._ | ✅ | +| [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction) | _Signs and submits a transaction_ | ✅ | +| [eth_getBalance](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance) | _Returns the balance of the account of given address_ | ✅ | +| [eth_getStorageAt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat) | _Returns the value from a storage position at a given address_ | ✅ | +| [eth_getTransactionCount](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount) | _Returns the number of transactions sent from an address_ | ✅ | +| [eth_getCode](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode) | _Returns code at a given address_ | ✅ | +| [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction) | _Signs and submits a transaction_ | ✅ | +| [eth_sendRawTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction) | _Submits a raw transaction_ | ✅ | +| [eth_getTransactionByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash) | _Returns the information about a transaction requested by transaction hash_ | ✅ | +| [eth_getTransactionByBlockHashAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex) | _Returns information about a transaction by block hash and transaction index position_ | ✅ | +| [eth_getTransactionByBlockNumberAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex) | _Returns information about a transaction by block number and transaction index position_ | ✅ | +| [eth_getTransactionReceipt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionrecepit) | _Returns the receipt of a transaction by transaction hash_ | ✅ | + + +## JSON-RPC methods according to the [Web3 Module API](https://openethereum.github.io/JSONRPC-web3-module) + +| Method | Description | Status | +|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------------------------| +| [web3_clientVersion](https://openethereum.github.io/JSONRPC-web3-module#web3_clientversion) | _Returns the current client version_ | ✅ | +| [web3_sha](https://openethereum.github.io/JSONRPC-web3-module#web3_sha3) | _Returns Keccak-256 (not the standardized SHA3-256) of the given data_ | ✅ | + + + +## JSON-RPC methods according to the [Net Module API](https://openethereum.github.io/JSONRPC-net-module) + +| Method | Description | Status | +|----------------------------------------------------------------------------------|------------------------------------------------------------------------|--------------------------------| +| [net_listening](https://openethereum.github.io/JSONRPC-net-module#net_listening) | _Returns true if client is actively listening for network connections_ | ✅ | +| [net_peerCount](https://openethereum.github.io/JSONRPC-net-module#net_peercount) | _Returns number of peers currently connected to the client_ | ✅ | +| [net_version](https://openethereum.github.io/JSONRPC-net-module#net_version) | _Returns the current network protocol version_ | ✅ | + +You can find the complete set of available specs in the [Ethereum API Documentation](https://ethereum.github.io/execution-apis/api-documentation/). diff --git a/docs/build/isc/v1.3/docs/reference/magic-contract/introduction.md b/docs/build/isc/v1.3/docs/reference/magic-contract/introduction.md new file mode 100644 index 00000000000..3ca44996914 --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/magic-contract/introduction.md @@ -0,0 +1,38 @@ +--- +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; + +# Introduction + +This section documents the magic contract and all it's interfaces: + + + + +## Call a Native Contract + +You can call native contracts using [`ISC.sandbox.call`](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L56): + +```solidity +pragma solidity >=0.8.5; + +import "@iota/iscmagic/ISC.sol"; + +contract MyEVMContract { + event EntropyEvent(bytes32 entropy); + + function callInccounter() public { + ISCDict memory params = ISCDict(new ISCDictItem[](1)); + bytes memory int64Encoded42 = hex"2A00000000000000"; + params.items[0] = ISCDictItem("counter", int64Encoded42); + ISCAssets memory allowance; + ISC.sandbox.call(ISC.util.hn("inccounter"), ISC.util.hn("incCounter"), params, allowance); + } +} +``` + +`ISC.util.hn` is used to get the `hname` of the `inccounter` contract and the +`incCounter` entry point. You can also call view entry points using +[ISC.sandbox.callView](https://github.com/iotaledger/wasp/blob/develop/packages/vm/core/evm/iscmagic/ISCSandbox.sol#L59). diff --git a/docs/build/isc/v1.3/docs/reference/wasm-lib-data-types.mdx b/docs/build/isc/v1.3/docs/reference/wasm-lib-data-types.mdx new file mode 100644 index 00000000000..28789a1772d --- /dev/null +++ b/docs/build/isc/v1.3/docs/reference/wasm-lib-data-types.mdx @@ -0,0 +1,104 @@ +--- +tags: + - data types + - WasmLib + - array + - proxies + - map + - reference + +description: The WasmLib provides direct support for the basic value data types that are found in all programming languages, and WasmLib versions of ISC-specific value data types. +image: /img/logo/WASP_logo_dark.png +--- + +# WasmLib Data Types + +You will need to manipulate data with your smart contracts. We distinguish two groups of +predefined data types that can be used in schema definition files. The WasmLib +implementations for each supported programming language provide full support for these +predefined data types. Each predefined data type can be (de)serialized as byte string or +as human-readable text string. + +## Basic Value Data Types + +These are mostly simple built-in scalar data types as provided by most programming +languages. Each integer data type has a clearly defined storage size. The +[Schema Tool](../schema/how-tos/usage.mdx) will attempt to use the closest matching built-in data type when +generating code for a specific language. + +- `BigInt` - An arbitrary-length unsigned integer. +- `Bool` - An 8-bit boolean value (0 or 1). +- `Bytes` - An arbitrary-length byte array. +- `Int8` - 8-bit signed integer value. +- `Int16` - 16-bit signed integer value. +- `Int32` - 32-bit signed integer value. +- `Int64` - 64-bit signed integer value. +- `String` - An arbitrary-length UTF-8 encoded string value. +- `Uint8` - 8-bit unsigned integer value. +- `Uint16` - 16-bit unsigned integer value. +- `Uint32` - 32-bit unsigned integer value. +- `Uint64` - 64-bit unsigned integer value. + +## ISC-specific Value Data Types + +These are ISC-specific value data types that are needed in the ISC sandbox function calls. +WasmLib provides its own implementations for each of the ISC value data types. + +- `Address` - A 33-byte encoded _Tangle_ address. +- `AgentID` - An ISC Agent ID (Address + Hname). +- `ChainID` - A 32-byte ISC Chain ID. +- `Hash` - A 32-byte hash value. +- `Hname` - A 4-byte unsigned integer hash value derived from a name string. +- `NftID` - A 32-byte ISC NFT ID. +- `RequestID` - A 34-byte ISC transaction request ID. +- `TokenID` - A 38-byte ISC token ID. + +## Full Matrix of WasmLib Types + +WasmLib implements a full set of [value proxies](../schema/proxies.mdx#value-proxies) for each +predefined value type that provide access to data on the ISC host. But there is one aspect +of this data that we have not considered yet. Some data provided by the host is mutable, +whereas other data may be immutable. To facilitate this distinction, each value proxy type +comes in two flavors that reflect this, and make sure that the data can only be used as +intended. + +The rule is that from an immutable container you can only derive immutable container and +value proxies. The referenced data can never be changed through immutable proxies. +Separating these constraints for types into separate value proxy types allows the use of +compile-time type-checking to enforce these constraints. To guard against client code that +tries to bypass them, the ISC sandbox will also check these constraints at runtime on the +host. + +| ISC type | WasmLib type | Mutable proxy | Immutable proxy | +|-----------|-------------------|------------------------|--------------------------| +| BigInt | Sc**BigInt** | ScMutable**BigInt** | ScImmutable**BigInt** | +| Bool | _boolean_ | ScMutable**Bool** | ScImmutable**Bool** | +| Bytes | _byte array_ | ScMutable**Bytes** | ScImmutable**Bytes** | +| Int8 | _8-bit signed_ | ScMutable**Int8** | ScImmutable**Int8** | +| Int16 | _16-bit signed_ | ScMutable**Int16** | ScImmutable**Int16** | +| Int32 | _32-bit signed_ | ScMutable**Int32** | ScImmutable**Int32** | +| Int64 | _64-bit signed_ | ScMutable**Int64** | ScImmutable**Int64** | +| String | _UTF-8 string_ | ScMutable**String** | ScImmutable**String** | +| Uint8 | _8-bit unsigned_ | ScMutable**Uint8** | ScImmutable**Uint8** | +| Uint16 | _16-bit unsigned_ | ScMutable**Uint16** | ScImmutable**Uint16** | +| Uint32 | _32-bit unsigned_ | ScMutable**Uint32** | ScImmutable**Uint32** | +| Uint64 | _64-bit unsigned_ | ScMutable**Uint64** | ScImmutable**Uint64** | +| | | | | +| Address | Sc**Address** | ScMutable**Address** | ScImmutable**Address** | +| AgentId | Sc**AgentId** | ScMutable**AgentId** | ScImmutable**AgentId** | +| ChainId | Sc**ChainId** | ScMutable**ChainId** | ScImmutable**ChainId** | +| Hash | Sc**Hash** | ScMutable**Hash** | ScImmutable**Hash** | +| Hname | Sc**Hname** | ScMutable**Hname** | ScImmutable**Hname** | +| NftID | Sc**NftID** | ScMutable**NftID** | ScImmutable**NftID** | +| RequestId | Sc**RequestId** | ScMutable**RequestId** | ScImmutable**RequestId** | +| TokenID | Sc**TokenID** | ScMutable**TokenID** | ScImmutable**TokenID** | + +The consistent naming makes it easy to remember the type names. Bool, Bytes, String, and +the integer types are the odd ones out. They are implemented in WasmLib by the closest +equivalents in the chosen WasmLib implementation programming language. + +The [Schema Tool](../schema/how-tos/usage.mdx) will automatically generate the proper immutable proxies +from the schema definition. For example, View functions will only be able to access the +[State](../schema/how-tos/state.mdx) map through immutable proxies. The same goes for the +[Params](../schema/how-tos/params.mdx) map that was passed into a Func or View, and for the +[Results](../schema/how-tos/results.mdx) map that was returned from a call to a Func or View. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/access.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/access.mdx new file mode 100644 index 00000000000..a9c799a32a2 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/access.mdx @@ -0,0 +1,37 @@ +--- +description: "This article explains how to define access controls for functions using the optional 'access' subsection in the schema definition file." +tags: + - Access Control + - Schema Tool + - Smart Contract + - AgentID + - Function Access +image: /img/logo/WASP_logo_dark.png +--- + +# Limit Access + +You can define function access controls through the optional `access` subsection in the schema definition file. +By default, functions are accessible to everyone. However, when specified, the `access` identifier restricts who can +call a function. + +## Access Identifiers + +You can set access identifiers with **one** of the following options: + +- `self`: Restricts access to the smart contract itself. +- `chain`: Allows only the chain owner to invoke the function. +- Other: Specify an AgentID or AgentID[] variable in state storage, controlling the agent(s) permitted to call the + function. + You should provide a mechanism to initialize and manage this variable. + +The [Schema Tool](usage.mdx) handles the auto-generation of the code for access verification. + +## Usage Examples + +You can find examples in the schema definition file where the `owner` state variable operates as an access identifier. +Functions such as `init` initialize the state variable, while `setOwner` can modify ownership, +enhancing the security by limiting function access to the current owner. + +Remember to tailor access identifiers to individual functions as required, +and establish multiple identifiers if necessary. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/call.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/call.mdx new file mode 100644 index 00000000000..3a0f26d0df1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/call.mdx @@ -0,0 +1,178 @@ +--- +description: "Explore how synchronous function calls work between smart contracts, highlighting the role of function descriptors in parameter and token passage, and understanding the ISC host's role in this procedure." +tags: + - Synchronous Calls + - Smart Contracts + - Function Descriptors + - ISC Host + - Function Parameters + - Smart Contract Memory +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Call Functions + +Synchronous function calls between smart contracts act very similar to how normal function calls work in any programming language, +but with a slight twist. +With normal function calls, you share all the global memory that you can access with every function that you call. +However, when calling a smart contract function, +you can only access the memory assigned to that specific smart contract. + +## How Synchronous Calls Operate + +### Data Sharing + +If you want to share data between smart contracts, you will need to use: + +- Function [parameters](params.mdx) +- [Return](results.mdx) values + +## The ISC Host Role + +Ensuring smooth synchronous calls between contracts on the same chain, the ISC host: + +- Recognizes all contracts functioning on a chain. +- Directs the call appropriately to the destined contract function using function descriptors. + +### Function Descriptors + +Function descriptors allow: + +- Specification of call parameters via the [Params](params.mdx) proxy. +- Function invocation through the `func` interface. +- Passing tokens to non-[View](views.mdx) function calls within the same chain. + +:::note + +The only way to call a function and properly pass tokens to it within the same chain is through the function descriptor. +Otherwise, the allowance() function will not register any incoming tokens. + +::: + +### Call Process + +During a call: + +- The initiator function pauses and awaits the completion of the called function. +- Post-completion, retrieves potential returned values through the [Results](results.mdx) proxy. + +### Calling From View Functions + +When a view function initiates a call: + +- It can only reach out to other [view](views.mdx) functions. +- The `ScFuncs` interface mandates an `ScViewContext` for the constructor creating the function descriptor. + +## Usage Example + +Here's how a smart contract would tell a `dividend` contract on the same chain to divide the 1000 tokens it passes to the function: + + + + + +```go +f := dividend.ScFuncs.Divide(ctx) +f.Func.TransferBaseTokens(1000).Call() +``` + + + + +```rust +let f = dividend::ScFuncs::divide(ctx); +f.func.transfer_base_tokens(1000).call(); +``` + + + + +```ts +let f = dividend.ScFuncs.divide(ctx); +f.func.transferBaseTokens(1000).call(); +``` + + + + +And here is how a smart contract would ask a `dividend` contract on the same chain to +return the dispersion factor for a specific address: + + + + + +```go +f := dividend.ScFuncs.GetFactor(ctx) +f.Params.Address().SetValue(address) +f.Func.Call() +factor := f.Results.Factor().Value() +``` + + + + +```rust +let f = dividend::ScFuncs::get_factor(ctx); +f.params.address().set_value(&address); +f.func.call(); +let factor = f.results.factor().value(); +``` + + + + +```ts +let f = dividend.ScFuncs.getFactor(ctx); +f.params.address().setValue(address); +f.func.call(); +let factor = f.results.factor().value(); +``` + + + + +1. Create a function descriptor for the desired function. +2. Use the [Params](params.mdx) proxy in the descriptor to set its parameters. +3. Direct the `func` member of the descriptor to call the associated function +4. Use the [Results](results.mdx) proxy in the descriptor to retrieve its results. + +The function descriptors assume that the function to be called is associated with the +default Hname of the contract, in this case ScHname::new("dividend"). If you deployed the +contract that contains the function you want to call under a different name, then you +would have to provide its associated Hname to the `func` member through the of_contract() +member function like this: + + + + + +```go +altContract := NewScHname("alternateName") +f := dividend.ScFuncs.Divide(ctx) +f.Func.OfContract(altContract).TransferBaseTokens(1000).Call() +``` + + + + +```rust +let alt_contract = ScHname::new("alternateName"); +let f = dividend::ScFuncs::divide(ctx); +f.func.of_contract(alt_contract).transfer_base_tokens(1000).call(); +``` + + + + +```ts +let altContract = ScHname.fromString('alternateName'); +let f = dividend.ScFuncs.divide(ctx); +f.func.ofContract(altContract).transferBaseTokens(1000).call(); +``` + + + diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/events.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/events.mdx new file mode 100644 index 00000000000..02bd5174e73 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/events.mdx @@ -0,0 +1,317 @@ +--- +description: "This article outlines how to trigger events in smart contracts utilizing ISC sandbox's ScFuncContext and the Schema Tool for structured events." +tags: + - Smart Contracts + - ISC Sandbox + - Schema Tool + - Event-driven + - Call Context + - ScFuncContext + - Event Triggering +image: /img/logo/WASP_logo_dark.png +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Trigger Events + +Smart contracts operate in a confined environment but need a mechanism to interact with users. +A solution to this is triggering events, which is facilitated through smart contracts. + +## ISC Sandbox Interface + +The `ScFuncContext` [Call Context](../../explanations/context.mdx) in ISC _Sandbox_ has an `event()` function to support event triggering. +This function takes a text string parameter, requiring creators and users to maintain and understand the chosen format. +However, this setup is prone to errors and inconsistency due to the arbitrary nature of the text strings used. + +## Structured Events with Schema Tool + +To mitigate issues stemming from the rudimentary interface, +use the [Schema Tool](usage.mdx) to define structured events, +making event creation and handling more consistent and less error-prone. + +This tool allows you to establish structured events that are integrated into all Func function contexts. +Note that events: + +- Can only be triggered within a Func +- Become part of the smart contract's state +- Are logged in the core `blocklog` contract +- Cannot be triggered within a View + +## Event Structure + +Define each event in the `events` section of the schema definition file. +This setup ensures that events are encoded consistently, +utilizing a function that automatically formats the event string with the event name, timestamp, and parameter fields, +delimited by vertical bars. +This structured approach facilitates streamlined, error-resistant event triggering. + +### Example + +Here is the `events` section that can be found in the demo `fairroulette` smart contract: + + + + +```yaml +events: + bet: + address: Address # address of better + amount: Uint64 # amount of tokens to bet + number: Uint16 # number to bet on + payout: + address: Address # address of winner + amount: Uint64 # amount of tokens won + round: + number: Uint32 # current betting round number + start: + stop: + winner: + number: Uint16 # the winning number +``` + + + + +The [Schema Tool](usage.mdx) will generate `events.xx` which contains the following code +for the `FairRouletteEvents` struct: + + + + + +```go +package fairroulette + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type FairRouletteEvents struct { +} + +func (e FairRouletteEvents) Bet( + // address of better + address wasmtypes.ScAddress, + // amount of tokens to bet + amount uint64, + // number to bet on + number uint16, +) { + evt := wasmlib.NewEventEncoder("fairroulette.bet") + evt.Encode(wasmtypes.AddressToString(address)) + evt.Encode(wasmtypes.Uint64ToString(amount)) + evt.Encode(wasmtypes.Uint16ToString(number)) + evt.Emit() +} + +func (e FairRouletteEvents) Payout( + // address of winner + address wasmtypes.ScAddress, + // amount of tokens won + amount uint64, +) { + evt := wasmlib.NewEventEncoder("fairroulette.payout") + evt.Encode(wasmtypes.AddressToString(address)) + evt.Encode(wasmtypes.Uint64ToString(amount)) + evt.Emit() +} + +func (e FairRouletteEvents) Round( + // current betting round number + number uint32, +) { + evt := wasmlib.NewEventEncoder("fairroulette.round") + evt.Encode(wasmtypes.Uint32ToString(number)) + evt.Emit() +} + +func (e FairRouletteEvents) Start() { + evt := wasmlib.NewEventEncoder("fairroulette.start") + evt.Emit() +} + +func (e FairRouletteEvents) Stop() { + evt := wasmlib.NewEventEncoder("fairroulette.stop") + evt.Emit() +} + +func (e FairRouletteEvents) Winner( + // the winning number + number uint16, +) { + evt := wasmlib.NewEventEncoder("fairroulette.winner") + evt.Encode(wasmtypes.Uint16ToString(number)) + evt.Emit() +} +``` + + + + +```rust +use wasmlib::*; + +pub struct FairRouletteEvents { +} + +impl FairRouletteEvents { + + pub fn bet(&self, + // address of better + address: &ScAddress, + // amount of tokens to bet + amount: u64, + // number to bet on + number: u16, + ) { + let mut evt = EventEncoder::new("fairroulette.bet"); + evt.encode(&address_to_string(&address)); + evt.encode(&uint64_to_string(amount)); + evt.encode(&uint16_to_string(number)); + evt.emit(); + } + + pub fn payout(&self, + // address of winner + address: &ScAddress, + // amount of tokens won + amount: u64, + ) { + let mut evt = EventEncoder::new("fairroulette.payout"); + evt.encode(&address_to_string(&address)); + evt.encode(&uint64_to_string(amount)); + evt.emit(); + } + + pub fn round(&self, + // current betting round number + number: u32, + ) { + let mut evt = EventEncoder::new("fairroulette.round"); + evt.encode(&uint32_to_string(number)); + evt.emit(); + } + + pub fn start(&self) { + let mut evt = EventEncoder::new("fairroulette.start"); + evt.emit(); + } + + pub fn stop(&self) { + let mut evt = EventEncoder::new("fairroulette.stop"); + evt.emit(); + } + + pub fn winner(&self, + // the winning number + number: u16, + ) { + let mut evt = EventEncoder::new("fairroulette.winner"); + evt.encode(&uint16_to_string(number)); + evt.emit(); + } +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as wasmtypes from 'wasmlib/wasmtypes'; + +export class FairRouletteEvents { + bet( + // address of better + address: wasmtypes.ScAddress, + // amount of tokens to bet + amount: u64, + // number to bet on + number: u16, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.bet'); + evt.encode(wasmtypes.addressToString(address)); + evt.encode(wasmtypes.uint64ToString(amount)); + evt.encode(wasmtypes.uint16ToString(number)); + evt.emit(); + } + + payout( + // address of winner + address: wasmtypes.ScAddress, + // amount of tokens won + amount: u64, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.payout'); + evt.encode(wasmtypes.addressToString(address)); + evt.encode(wasmtypes.uint64ToString(amount)); + evt.emit(); + } + + round( + // current betting round number + number: u32, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.round'); + evt.encode(wasmtypes.uint32ToString(number)); + evt.emit(); + } + + start(): void { + const evt = new wasmlib.EventEncoder('fairroulette.start'); + evt.emit(); + } + + stop(): void { + const evt = new wasmlib.EventEncoder('fairroulette.stop'); + evt.emit(); + } + + winner( + // the winning number + number: u16, + ): void { + const evt = new wasmlib.EventEncoder('fairroulette.winner'); + evt.encode(wasmtypes.uint16ToString(number)); + evt.emit(); + } +} +``` + + + + +Notice how the generated functions use the WasmLib EventEncoder to encode the parameters +into a single string before emitting it. Here is the way in which `fairroulette` emits the +`bet` event in its smart contract code: + + + + + +```go + f.Events.Bet(bet.Better.Address(), bet.Amount, bet.Number) +``` + + + + +```rust + f.events.bet(&bet.better.address(), bet.amount, bet.number); +``` + + + + +```ts +f.events.bet(bet.better.address(), bet.amount, bet.number); +``` + + + + +The smart contract client code can define handler functions to listen in to the event +stream and respond to any events it deems noteworthy. The [Schema Tool](usage.mdx) will +automatically generate the necessary client side code that properly listens for the +events, parses the event strings into a type-safe structure, and passes this structure to +the corresponding handler function. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/funcdesc.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/funcdesc.mdx new file mode 100644 index 00000000000..bb4f18ee046 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/funcdesc.mdx @@ -0,0 +1,404 @@ +--- +tags: + - descriptor + - view + - access + - contract functions + - schema tool + +description: The schema tool provides us with an easy way to get access to smart contract functions through function descriptors, which allow you to initiate the function by calling it synchronously, or posting a request to run it asynchronously. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Add Function Descriptors + +You can use the [Schema Tool](usage.mdx) to access, and initiate smart contract functions seamlessly using +function descriptors. +These descriptors allow you to access optional [Params](params.mdx) and [Results](results.mdx) maps through strict +compile-time checked interfaces. + +## Function Descriptors Overview + +Function descriptors are structures that: + +- Offer access to the optional [Params](params.mdx) and [Results](results.mdx) maps. +- Allow synchronous or asynchronous initiation of functions through [`call()`](call.mdx) or [`post()`](post.mdx) requests. + +## The Schema Tool in Action + +The Schema Tool performs the following tasks: + +### 1. **Generate Specific Descriptors**: + +- For each function (`func`) and view. +- The outcome: Structs granting access to [Params](params.mdx) or [Results](results.mdx) maps, wherever specified. + +## 2. **Create the `ScFuncs` Interface**: + +- Facilitate the creation and initialization of each function descriptor. +- Incorporate a member function for every func or view to craft their respective function descriptor properly. + + + + + +```go +package dividend + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + +type DivideCall struct { + Func *wasmlib.ScFunc +} + +type InitCall struct { + Func *wasmlib.ScInitFunc + Params MutableInitParams +} + +type MemberCall struct { + Func *wasmlib.ScFunc + Params MutableMemberParams +} + +type SetOwnerCall struct { + Func *wasmlib.ScFunc + Params MutableSetOwnerParams +} + +type GetFactorCall struct { + Func *wasmlib.ScView + Params MutableGetFactorParams + Results ImmutableGetFactorResults +} + +type GetOwnerCall struct { + Func *wasmlib.ScView + Results ImmutableGetOwnerResults +} + +type Funcs struct{} + +var ScFuncs Funcs + +// divide tokens over members +func (sc Funcs) Divide(ctx wasmlib.ScFuncCallContext) *DivideCall { + return &DivideCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncDivide)} +} + +func (sc Funcs) Init(ctx wasmlib.ScFuncCallContext) *InitCall { + f := &InitCall{Func: wasmlib.NewScInitFunc(ctx, HScName, HFuncInit)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) Member(ctx wasmlib.ScFuncCallContext) *MemberCall { + f := &MemberCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncMember)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) SetOwner(ctx wasmlib.ScFuncCallContext) *SetOwnerCall { + f := &SetOwnerCall{Func: wasmlib.NewScFunc(ctx, HScName, HFuncSetOwner)} + f.Params.proxy = wasmlib.NewCallParamsProxy(&f.Func.ScView) + return f +} + +func (sc Funcs) GetFactor(ctx wasmlib.ScViewCallContext) *GetFactorCall { + f := &GetFactorCall{Func: wasmlib.NewScView(ctx, HScName, HViewGetFactor)} + f.Params.proxy = wasmlib.NewCallParamsProxy(f.Func) + wasmlib.NewCallResultsProxy(f.Func, &f.Results.proxy) + return f +} + +func (sc Funcs) GetOwner(ctx wasmlib.ScViewCallContext) *GetOwnerCall { + f := &GetOwnerCall{Func: wasmlib.NewScView(ctx, HScName, HViewGetOwner)} + wasmlib.NewCallResultsProxy(f.Func, &f.Results.proxy) + return f +} +``` + + + + + +```rust +use wasmlib::*; +use crate::*; + +pub struct DivideCall { + pub func: ScFunc, +} + +pub struct InitCall { + pub func: ScInitFunc, + pub params: MutableInitParams, +} + +pub struct MemberCall { + pub func: ScFunc, + pub params: MutableMemberParams, +} + +pub struct SetOwnerCall { + pub func: ScFunc, + pub params: MutableSetOwnerParams, +} + +pub struct GetFactorCall { + pub func: ScView, + pub params: MutableGetFactorParams, + pub results: ImmutableGetFactorResults, +} + +pub struct GetOwnerCall { + pub func: ScView, + pub results: ImmutableGetOwnerResults, +} + +pub struct ScFuncs { +} + +impl ScFuncs { + // divide tokens over members + pub fn divide(_ctx: &dyn ScFuncCallContext) -> DivideCall { + DivideCall { + func: ScFunc::new(HSC_NAME, HFUNC_DIVIDE), + } + } + + pub fn init(_ctx: &dyn ScFuncCallContext) -> InitCall { + let mut f = InitCall { + func: ScInitFunc::new(HSC_NAME, HFUNC_INIT), + params: MutableInitParams { proxy: Proxy::nil() }, + }; + ScInitFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn member(_ctx: &dyn ScFuncCallContext) -> MemberCall { + let mut f = MemberCall { + func: ScFunc::new(HSC_NAME, HFUNC_MEMBER), + params: MutableMemberParams { proxy: Proxy::nil() }, + }; + ScFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn set_owner(_ctx: &dyn ScFuncCallContext) -> SetOwnerCall { + let mut f = SetOwnerCall { + func: ScFunc::new(HSC_NAME, HFUNC_SET_OWNER), + params: MutableSetOwnerParams { proxy: Proxy::nil() }, + }; + ScFunc::link_params(&mut f.params.proxy, &f.func); + f + } + + pub fn get_factor(_ctx: &dyn ScViewCallContext) -> GetFactorCall { + let mut f = GetFactorCall { + func: ScView::new(HSC_NAME, HVIEW_GET_FACTOR), + params: MutableGetFactorParams { proxy: Proxy::nil() }, + results: ImmutableGetFactorResults { proxy: Proxy::nil() }, + }; + ScView::link_params(&mut f.params.proxy, &f.func); + ScView::link_results(&mut f.results.proxy, &f.func); + f + } + + pub fn get_owner(_ctx: &dyn ScViewCallContext) -> GetOwnerCall { + let mut f = GetOwnerCall { + func: ScView::new(HSC_NAME, HVIEW_GET_OWNER), + results: ImmutableGetOwnerResults { proxy: Proxy::nil() }, + }; + ScView::link_results(&mut f.results.proxy, &f.func); + f + } +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as sc from './index'; + +export class DivideCall { + func: wasmlib.ScFunc; + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncDivide); + } +} + +export class DivideContext { + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class InitCall { + func: wasmlib.ScInitFunc; + params: sc.MutableInitParams = new sc.MutableInitParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScInitFunc(ctx, sc.HScName, sc.HFuncInit); + } +} + +export class InitContext { + params: sc.ImmutableInitParams = new sc.ImmutableInitParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class MemberCall { + func: wasmlib.ScFunc; + params: sc.MutableMemberParams = new sc.MutableMemberParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncMember); + } +} + +export class MemberContext { + params: sc.ImmutableMemberParams = new sc.ImmutableMemberParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class SetOwnerCall { + func: wasmlib.ScFunc; + params: sc.MutableSetOwnerParams = new sc.MutableSetOwnerParams( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScFuncCallContext) { + this.func = new wasmlib.ScFunc(ctx, sc.HScName, sc.HFuncSetOwner); + } +} + +export class SetOwnerContext { + params: sc.ImmutableSetOwnerParams = new sc.ImmutableSetOwnerParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class GetFactorCall { + func: wasmlib.ScView; + params: sc.MutableGetFactorParams = new sc.MutableGetFactorParams( + wasmlib.ScView.nilProxy, + ); + results: sc.ImmutableGetFactorResults = new sc.ImmutableGetFactorResults( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScViewCallContext) { + this.func = new wasmlib.ScView(ctx, sc.HScName, sc.HViewGetFactor); + } +} + +export class GetFactorContext { + params: sc.ImmutableGetFactorParams = new sc.ImmutableGetFactorParams( + wasmlib.paramsProxy(), + ); + results: sc.MutableGetFactorResults = new sc.MutableGetFactorResults( + wasmlib.ScView.nilProxy, + ); + state: sc.ImmutableDividendState = new sc.ImmutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class GetOwnerCall { + func: wasmlib.ScView; + results: sc.ImmutableGetOwnerResults = new sc.ImmutableGetOwnerResults( + wasmlib.ScView.nilProxy, + ); + public constructor(ctx: wasmlib.ScViewCallContext) { + this.func = new wasmlib.ScView(ctx, sc.HScName, sc.HViewGetOwner); + } +} + +export class GetOwnerContext { + results: sc.MutableGetOwnerResults = new sc.MutableGetOwnerResults( + wasmlib.ScView.nilProxy, + ); + state: sc.ImmutableDividendState = new sc.ImmutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +export class ScFuncs { + // divide tokens over members + static divide(ctx: wasmlib.ScFuncCallContext): DivideCall { + return new DivideCall(ctx); + } + + static init(ctx: wasmlib.ScFuncCallContext): InitCall { + const f = new InitCall(ctx); + f.params = new sc.MutableInitParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static member(ctx: wasmlib.ScFuncCallContext): MemberCall { + const f = new MemberCall(ctx); + f.params = new sc.MutableMemberParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static setOwner(ctx: wasmlib.ScFuncCallContext): SetOwnerCall { + const f = new SetOwnerCall(ctx); + f.params = new sc.MutableSetOwnerParams(wasmlib.newCallParamsProxy(f.func)); + return f; + } + + static getFactor(ctx: wasmlib.ScViewCallContext): GetFactorCall { + const f = new GetFactorCall(ctx); + f.params = new sc.MutableGetFactorParams( + wasmlib.newCallParamsProxy(f.func), + ); + f.results = new sc.ImmutableGetFactorResults( + wasmlib.newCallResultsProxy(f.func), + ); + return f; + } + + static getOwner(ctx: wasmlib.ScViewCallContext): GetOwnerCall { + const f = new GetOwnerCall(ctx); + f.results = new sc.ImmutableGetOwnerResults( + wasmlib.newCallResultsProxy(f.func), + ); + return f; + } +} +``` + + + + +## `dividend` Example - Generated Code + +In the `dividend` example in `contract.xx`, specific structs for [Funcs and Views](../../schema/proxies.mdx) are created. +Here's how they operate: + +### Access + +- Via the `func` member within each struct. +- The `func` member type: Either `ScFunc` or `ScView`, contingent on whether it’s a function or a view. + +### Utilization + +- The `func` member is used to initiate function calls in various ways. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/funcs.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/funcs.mdx new file mode 100644 index 00000000000..0c48c6c85ed --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/funcs.mdx @@ -0,0 +1,82 @@ +--- +tags: + - functions + - views + - state + - access + - params + - results + +image: /img/logo/WASP_logo_dark.png +description: The code generated for Funcs will be able to inspect and modify the smart contract state, whereas the code generated for Views will only be able to inspect the state. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Functions + +Here is the full schema definition file for the `dividend` example. We will now focus on +its [`funcs` and `views` sections](../../explanations/context.mdx). Since they are structured identically we will only need +to explain the layout of these sections once. + + + + +```yaml +name: Dividend +description: Simple dividend smart contract +structs: {} +typedefs: {} +state: + memberList: Address[] # array with all the recipients of this dividend + + # factors per member + + members: map[Address]Uint64 # map with all the recipient factors of this dividend + owner: AgentID # owner of contract, the only one who can call 'member' func + totalFactor: Uint64 # sum of all recipient factors +funcs: + # divide tokens over members + divide: {} + init: + params: + owner: AgentID? # optional owner of contract, defaults to contract creator + member: + access: owner # only defined owner of contract can add members + params: + address: Address # address of dividend recipient + factor: Uint64 # relative division factor + setOwner: + access: owner # only defined owner of contract can change owner + params: + owner: AgentID # new owner of smart contract +views: + getFactor: + params: + address: Address # address of dividend recipient + results: + factor: Uint64 # relative division factor + getOwner: + results: + owner: AgentID # current owner of this smart contract +``` + + + + + +As you can see each of the `funcs` and `views` sections defines their functions in the +same way. The only resulting difference is in the way the [Schema Tool](usage.mdx) +generates code for them: + +- The code generated for Funcs will be able to inspect and modify the smart contract state. +- The code generated for Views will only be able to inspect the state. + +Functions are defined as named subsections in the schema definition file. The name of the +subsection will become the name of the function. In turn, there can be 3 optional +subsections under each function subsection. + +- [`access`](access.mdx) indicates who is allowed to access the function. +- `params` holds the field definitions that describe the function parameters. +- `results` holds the field definitions that describe the function results. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/init.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/init.mdx new file mode 100644 index 00000000000..3425089182c --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/init.mdx @@ -0,0 +1,269 @@ +--- +tags: + - init + - initialization + - owner + - initial state + - smart contract creator + - one-time + - contract deployment + +description: The init function will automatically be called immediately after the first time the contract has been deployed to the VM. This is a one-time initialization call, meant to be performed by the contract deployment mechanism. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Initialize a Smart Contract + +Smart contracts begin with a blank slate. You can define an initial state through the `init()` function. +This function is vital for setting configurations at the time of deployment. + +## Features of the `init()` Function + +### One-time Call + +Triggered automatically post-deployment, **it can only be used once** to set the initial configurations. + +### Security + +The ISC ensures the `init()` function is inaccessible after its initial execution, +safeguarding it from unauthorized accesses. + +### Necessity For a Separate Configuration Function + +To facilitate reconfiguration in the future, develop a distinct configuration function with proper access controls. + +## Usage Example + +To show how creating a smart contract with WasmLib works, we will slowly start fleshing +out the smart contract functions of the `dividend` example in this tutorial. Here is the +first part of the code that implements it, which contains the `init()` function: + + + + + +```go +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'var' statements with their assignment type to improve understanding. + +//nolint:revive,goimports +package dividend + +import ( + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" +) + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +func funcInit(ctx wasmlib.ScFuncContext, f *InitContext) { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + var owner wasmtypes.ScAgentID = ctx.RequestSender() + + // Now we check if the optional 'owner' parameter is present in the params map. + if f.Params.Owner().Exists() { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.Params.Owner().Value() + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.State.Owner().SetValue(owner) +} +``` + + + + +```rust +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'let' statements with their assignment type to improve understanding. + +use wasmlib::*; + +use crate::*; + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +pub fn func_init(ctx: &ScFuncContext, f: &InitContext) { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + let mut owner: ScAgentID = ctx.request_sender(); + + // Now we check if the optional 'owner' parameter is present in the params map. + if f.params.owner().exists() { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.params.owner().value(); + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.state.owner().set_value(&owner); +} +``` + + + + +```ts +// This example implements 'dividend', a simple smart contract that will +// automatically disperse iota tokens which are sent to the contract to a group +// of member accounts according to predefined division factors. The intent is +// to showcase basic functionality of WasmLib through a minimal implementation +// and not to come up with a complete robust real-world solution. +// Note that we have drawn sometimes out constructs that could have been done +// in a single line over multiple statements to be able to properly document +// step by step what is happening in the code. We also unnecessarily annotate +// all 'let' statements with their assignment type to improve understanding. + +import * as wasmlib from 'wasmlib'; +import * as sc from './index'; + +// 'init' is used as a way to initialize a smart contract. It is an optional +// function that will automatically be called upon contract deployment. In this +// case we use it to initialize the 'owner' state variable so that we can later +// use this information to prevent non-owners from calling certain functions. +// The 'init' function takes a single optional parameter: +// - 'owner', which is the agent id of the entity owning the contract. +// When this parameter is omitted the owner will default to the contract creator. +export function funcInit(ctx: wasmlib.ScFuncContext, f: sc.InitContext): void { + // The schema tool has already created a proper InitContext for this function that + // allows us to access call parameters and state storage in a type-safe manner. + + // First we set up a default value for the owner in case the optional 'owner' + // parameter was omitted. We use the agent that sent the deploy request. + let owner: wasmlib.ScAgentID = ctx.requestSender(); + + // Now we check if the optional 'owner' parameter is present in the params map. + if (f.params.owner().exists()) { + // Yes, it was present, so now we overwrite the default owner with + // the one specified by the 'owner' parameter. + owner = f.params.owner().value(); + } + + // Now that we have sorted out which agent will be the owner of this contract + // we will save this value in the 'owner' variable in state storage on the host. + // Read the documentation on schema.yaml to understand why this state variable is + // supported at compile-time by code generated from schema.yaml by the schema tool. + f.state.owner().setValue(owner); +} +``` + + + + +We define an owner variable and allow it to be something other than the default value of +the contract creator. It is always a good idea to be flexible enough to transfer +ownership to another entity if necessary. Remember that once a smart contract has been +deployed it is no longer possible to change it. Therefore, it is good practice to think +through situations that could require a change in advance and allow the contract itself to +handle such changes through its state by providing a proper function interface: + + + + + +```go +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +func funcSetOwner(_ wasmlib.ScFuncContext, f *SetOwnerContext) { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.State.Owner().SetValue(f.Params.Owner().Value()) +} +``` + + + + +```rust +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +pub fn func_set_owner(_ctx: &ScFuncContext, f: &SetOwnerContext) { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.state.owner().set_value(&f.params.owner().value()); +} +``` + + + + +```ts +// 'setOwner' is used to change the owner of the smart contract. +// It updates the 'owner' state variable with the provided agent id. +// The 'setOwner' function takes a single mandatory parameter: +// - 'owner', which is the agent id of the entity that will own the contract. +// Only the current owner can change the owner. +export function funcSetOwner( + ctx: wasmlib.ScFuncContext, + f: sc.SetOwnerContext, +): void { + // Note that the schema tool has already dealt with making sure that this function + // can only be called by the owner and that the required parameter is present. + // So once we get to this point in the code we can take that as a given. + + // Save the new owner parameter value in the 'owner' variable in state storage. + f.state.owner().setValue(f.params.owner().value()); +} +``` + + + + +Note that we only define a single owner here. +A proper fall-back could require multiple owners in case the owner entity could disappear, +which would allow others to take over instead of the contract becoming immutable about the “owner functionality”. +We cannot stress enough how important it is to **think through every aspect of a smart contract before deployment**. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/params.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/params.mdx new file mode 100644 index 00000000000..60691771f75 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/params.mdx @@ -0,0 +1,102 @@ +--- +description: "Learn how to define function parameters using the 'params' subsection, and how the Schema Tool facilitates this process." +tags: + - Function Parameters + - Schema Tool + - Params Subsection + - Optional Parameters + - Parameter Proxy +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Function Parameters + +You can use the optional [`params`](params.mdx) subsection to specify the parameters a function accepts. +This section can define both mandatory and optional parameters. +Optional parameters are denoted with a question mark `?` following the field type. + +## Schema Tool Automation + +The [Schema Tool](usage.mdx) streamlines the creation of functions by: + +- Generating an immutable structure holding parameter proxies from the [Params](params.mdx) map. +- Checking the presence and data type of non-optional parameters before the function call. + +These functionalities allow users to directly use parameter proxies in the structure passed to the function. + +:::note + +Omitting the `params` subsection results in no structure generation or parameter passing to the function. + +::: + +For example, here is the structure generated for the immutable [Params](params.mdx) for +the `member` function: + + + + + +```go +type ImmutableMemberParams struct { + proxy wasmtypes.Proxy +} + +// address of dividend recipient +func (s ImmutableMemberParams) Address() wasmtypes.ScImmutableAddress { + return wasmtypes.NewScImmutableAddress(s.proxy.Root(ParamAddress)) +} + +// relative division factor +func (s ImmutableMemberParams) Factor() wasmtypes.ScImmutableUint64 { + return wasmtypes.NewScImmutableUint64(s.proxy.Root(ParamFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct ImmutableMemberParams { + pub(crate) proxy: Proxy, +} + +impl ImmutableMemberParams { + // address of dividend recipient + pub fn address(&self) -> ScImmutableAddress { + ScImmutableAddress::new(self.proxy.root(PARAM_ADDRESS)) + } + + // relative division factor + pub fn factor(&self) -> ScImmutableUint64 { + ScImmutableUint64::new(self.proxy.root(PARAM_FACTOR)) + } +} +``` + + + + +```ts +export class ImmutableMemberParams extends wasmtypes.ScProxy { + // address of dividend recipient + address(): wasmtypes.ScImmutableAddress { + return new wasmtypes.ScImmutableAddress(this.proxy.root(sc.ParamAddress)); + } + + // relative division factor + factor(): wasmtypes.ScImmutableUint64 { + return new wasmtypes.ScImmutableUint64(this.proxy.root(sc.ParamFactor)); + } +} +``` + + + + +The [Schema Tool](usage.mdx) will also generate a mutable version of the structure, +suitable for providing the parameters when calling this smart contract function from any [Call Context](../../explanations/context.mdx). diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/post.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/post.mdx new file mode 100644 index 00000000000..e4ef8b23b4d --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/post.mdx @@ -0,0 +1,99 @@ +--- +tags: + - function descriptor + - return values + - request + - post + - smart contract chain + - Asynchronous function +description: Asynchronous function calls between smart contracts are posted as requests on the Tangle. They allow you to invoke any smart contract function that is not a View on any smart contract chain. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Post Asynchronous Requests + +Asynchronous requests enable interactions between different contracts. +Learn how to navigate the subtleties of posting asynchronous requests on the Tangle, +and how to effectively manage tokens and delays in execution. + +## Overview of Asynchronous Function Calls + +### Posting Requests on the Tangle + +Asynchronous function calls occur through requests posted on the Tangle. +These calls can invoke any function that is not a [View](views.mdx) on any smart contract chain. + +### Function Descriptor Methods + +To post a request, use the following methods from the function descriptor: + +- `post()`: Posts to the current chain. +- `postToChain()`: Allows specifying the chain through the chain ID parameter. + +### Delayed Execution + +You can set a delay in the execution using the `delay()` method, +enhancing smart contracts with timed actions or time-lock functionalities. + + + + + +```go +eor := ScFuncs.EndOfRound(ctx) +eor.Func.Delay(3600).Post() +``` + + + + +```rust +let eor = ScFuncs::end_of_round(ctx); +eor.func.delay(3600).post(); +``` + + + + +```ts +let eor = sc.ScFuncs.endOfRound(ctx); +eor.func.delay(3600).post(); +``` + + + + +## Managing Tokens in Asynchronous Calls + +### Mandatory Token Transfer + +Asynchronous requests require a minimum token transfer to cover the gas for function call execution. +Unused tokens return to the caller's account on the chain. + +### Specifying Tokens + +You can specify tokens: + +- Explicitly, as in to synchronous calls. +- Automatically, letting WasmLib determine the minimum requisite amount. + +### Prohibited `delay()` with [`call()`](call.mdx) + +Using `delay()` before a [`call()`](call.mdx) will cause a panic due to indeterminate user intentions at compile-time +without substantial overhead. + +## Handling Return Values + +If you need some return values, +you will have to create a mechanism that can do so. +For example, +you can provide a callback chain/contract/function combination as part of the input parameters of the requested function so that upon completion, +that function can asynchronously post the results to the indicated function. +It will require a certain degree of cooperation between both smart contracts. + +### Future Prospects + +Future developments aim to facilitate a generic mechanism for seamless return value communication in asynchronous function calls. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/results.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/results.mdx new file mode 100644 index 00000000000..d80691a6888 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/results.mdx @@ -0,0 +1,85 @@ +--- +image: /img/logo/WASP_logo_dark.png +description: "Understand how to outline function results using the 'results' subsection and how the Schema Tool aids in this process." +tags: + - Function Results + - Schema Tool + - Results Subsection + - Mutable Structure + - Result Variables +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define Function Results + +You can use the optional `results` subsection to detail the results a function can produce. +This setup aligns with the field definitions seen in the [Params](params.mdx) subsection. + +## Schema Tool Features + +The [Schema Tool](usage.mdx) assists in this setup by: + +- Creating a mutable structure that includes proxies for each result variable found in the [Results](results.mdx) map. +- Enabling users to assign values to result variables via this generated structure during the function call. + +:::note + +If the `results` subsection is not used, no structure will be created or conveyed to the function. + +::: + +For example, here is the structure generated for the mutable results for the `getFactor` +function: + + + + + +```go +type MutableGetFactorResults struct { + proxy wasmtypes.Proxy +} + +// relative division factor +func (s MutableGetFactorResults) Factor() wasmtypes.ScMutableUint64 { + return wasmtypes.NewScMutableUint64(s.proxy.Root(ResultFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct MutableGetFactorResults { + pub(crate) proxy: Proxy, +} + +impl MutableGetFactorResults { + // relative division factor + pub fn factor(&self) -> ScMutableUint64 { + ScMutableUint64::new(self.proxy.root(RESULT_FACTOR)) + } +} +``` + + + + +```ts +export class MutableGetFactorResults extends wasmtypes.ScProxy { + // relative division factor + factor(): wasmtypes.ScMutableUint64 { + return new wasmtypes.ScMutableUint64(this.proxy.root(sc.ResultFactor)); + } +} +``` + + + + +Note that the [Schema Tool](usage.mdx) will also generate an immutable version of the +structure, suitable for accessing the results after by the caller of this smart contract +function. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/spec.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/spec.mdx new file mode 100644 index 00000000000..1c8c35fee58 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/spec.mdx @@ -0,0 +1,460 @@ +--- +tags: + - spec + - meta-programming + - compile +description: The spec of schema tool and how to develop schema tool. +image: /img/logo/WASP_logo_dark.png +--- + +# Spec + +## Workflow + +1. YAML file would be converted to a tree of `wasp_yaml.Node` +2. Convert the tree to a `model.SchemaDef` object +3. Compile the `model.SchemaDef` object to `model.Schema` object by calling `Compile()` +4. Convert `model.Schema` object to the Smart Contract of targeting languages + +## Types + +### model.SchemaDef + +`model.SchemaDef` is a intermediate object during the Smart Contract generation. An YAML file will be converted to `model.SchemaDef` object. +During the conversion, each YAML attribute except the top-level ones (`name`, `description`, `events`, `structs`, `typedefs`, `state`, `funcs`, `views`) will be converted into `DefElt`. + +Therefore, for YAML tags `name`, `description`, the values of them will be converted into 2 independent `DefElt`. + +``` +name: TestName +description: This is test description +``` + +For keywords that can have multiple values can be seen as either a one layer map (i.e., `typedefs` and `state`) +or two layer map (i.e., `typedefs` and `state`). A one layer map will be converted into `DefMap` which +is a map whose key and value are both `DefElt`. And a two layer map will be converted into `DefMapMap` which +is a map whose key is `DefElt` and value is `DefMap`. + +The definition of `DefElt` is shown as following, + +```go +type DefElt struct { + Val string + Comment string + Line int +} +``` + +It contains the raw value of the YAML attributes (without extracting the information), the comment belongs to the +YAML attribute, and the line number of the YAML attribute. + +Here is an example of one layer map + +```yaml +typedefs: + TestTypedef1: String + TestTypedef2: String +state: + TestState1: Int64[] + TestState2: Int64[] +``` + +And an example of two layer map + +```yaml +structs: + point: + x: Int32 + y: Int32 +funcs: + testFunc: + params: + testFuncParam: Uint64 + results: + testFuncResult: Uint64 +views: + testView: + params: + testViewParam: Uint64 + results: + testViewResult: Uint64 +``` + +Next, schema tool will set each fields in `SchemaDef` variable. + +```go +type SchemaDef struct { + Copyright string + Name DefElt + Description DefElt + Events DefMapMap + Structs DefMapMap + Typedefs DefMap + State DefMap + Funcs FuncDefMap + Views FuncDefMap +} +``` + +### model.Schema + +By calling `Schema.Compile()`, `model.SchemaDef` object will be compiled into `model.Schema`. +During the compilation, schema tool will extract the rules from the YAML attributes. + +Here is the definition of a `Schema` object. + +```go +type Schema struct { + ContractName string + Copyright string + PackageName string + Description string + CoreContracts bool + SchemaTime time.Time + Events []*Struct + Funcs []*Func + Params []*Field + Results []*Field + StateVars []*Field + Structs []*Struct + Typedefs []*Field +} +``` + +And let's take a close look at `Field` object. + +```go +type Field struct { + Name string // external name for this field + Alias string // internal name alias, can be different from Name + Array bool + FldComment string + MapKey string + Optional bool + Type string + BaseType bool + Comment string + Line int // the line number originally in yaml/json file +} +``` + +As you can see `typedefs` was a simple `DefMap`, which consists a map whose key and value are both `DefElt`, +and `DefElt` a simple object contains only raw string of the YAML attribute, comment and line number. +However, after the compilation, information is extracted from the raw string, so do some checks are conducted in this step. + +### Compile + +An emitter is used for filling corresponding values into templates under `tools/schema/generator`. +For how to do meta-programming with emitter, see section [Emitter](#emitter) + +```go +type ( + FieldMap map[string]*Field + FieldMapMap map[string]FieldMap + StringMap map[string]string + StringMapMap map[string]StringMap +) +``` + +## Comments + +### Header Comment and Line Comment + +Header comment has higher priority than the line comment. If there are both header comment and line comment presented at +same YAML attribute, then schema tool will keep only the header comment. + +### Comment Block + +A comment block is a chunk of comment that doesn't have a line break to separate it. Schema tool would take the +header comment that immediately followed by the YAML attribute or the line comment block if header comment block is not +presented. + +Therefore, for the following case + +```yaml +typedefs: + # header comment 1 + # header comment 2 + + # header comment 3 + # header comment 4 + TestTypedef: + String # line comment 1 + # line comment 2 +``` + +only these 2 lines + +```yaml +# header comment 3 +# header comment 4 +``` + +will be kept and presented in the final Smart Contract. + +And the next case + +```yaml +typedefs: + TestTypedef: + String # line comment 1 + # line comment 2 + + # line comment 3 + # line comment 4 +``` + +only these 2 lines + +```yaml +# line comment 1 +# line comment 2 +``` + +will be kept and presented in the final Smart Contract. + +## Emitter + +### Access Keys + +With `$` prepending a key (keys are set in `GenBase.setCommonKeys()`, `GenBase.setFieldKeys()`, `GenBase.setFuncKeys()`), schema tool can access the value of the key in `GenBase.keys` according to the current context. For example, if you want to access lower case package name, you can access it with `$package`. +To dynamically add a new key in templates (under gotemplates, rstemplates, and tstemplates), you can call `$#set` instruction, see section [set](#set) for more information. + +### Key And Plain String Concatenation + +To concatenate a value from accessing key and a plain string, you should use `$+` operator. +For example, here `FuncName` is a key that preserves the name of the function under current context, and we want to concatenate the function name with "Mutable" and "Results". +In other words, we want to do the same task as the following python code and get the result in `result` variable. + +```python +func_name = "..." # function name under current context +result = "Mutable" + func_name + "Results" # concatenate the strings into the result +``` + +In the schema template language, we should call `Mutable$FuncName$+Results`. + +### Instructions + +Keywords follows `$#` are the instructions defined in our schema template language. One thing you should aware, now, all the instruction should be presented at the beginning of each line. In other words, no spaces and characters are allowed to exist ahead of an instruction. +Here is the list of all the instruction keywords. + +- emit +- each +- func +- if +- set + +We are going to introduce how to use each instruction as follows. Or you can check the implementation of `GenBase.emit()` to know how are they implemented in detailed. + +#### emit + +`emit` is using for expanding templates. The syntax of `emit` instruction is + +``` +$#emit template +``` + +Here, `template` is any template which defined under gotemplates,rstemplates). +Templates are defined in `model.StringMap`. In the instruction call of `emit` just simply use the name of the template (the key in `model.StringMap`). +If you want to insert the `copyright` template to a assigned location, then you should call + +``` +$#emit copyright +``` + +#### each + +`each` processes the template for each item in the array. The syntax of `each` instruction is + +``` +$#each array template +``` + +Here `array` is either a predefined keyword (we are going to introduce each of them as follow) or a multi-lines string. +If a multi-lines string is presented, then the multi-lines string will be expanded and append newline escape character of targeting languages in the end of each line. + +##### event + +Iterate the fields in a event. + +##### events + +Iterate all the `events` in the contract. + +##### func + +Iterate all the `funcs` in the contract. + +##### mandatory + +Iterate all the mandatory fields in the current processed function. The mandatory field must be basetype and not an array or a map. + +##### param + +Iterate all the `params` fields in the current processed function. + +##### params + +Iterate all the `params` fields in the current contract. + +##### result + +Iterate all the `results` fields in the current processed function. + +##### results + +Iterate all the `results` fields in the current contract. + +##### state + +Iterate all the `state` in the contract. + +##### struct + +Iterate the fields in a struct. + +##### structs + +Iterate all the `structs` in the contract. + +##### typedef + +Iterate all the typedefs in the contract. + +#### func + +Currently not used. + +#### if + +The syntax of `if` is + +``` +$#if condition template [elseTemplate] +``` + +`if` processes template when the named condition is true, and it processes the optional `elseTemplate` when the named condition is false + +`condition` is either the predefined conditions (explained as following) or a key that may exist in `keys`. +If a key is presented, then `if` instruction would be used for check whether this key exists in `keys` or not. If the key exists, then `if` will return true, otherwise it will return false. + +And here are the predefined conditions. + +##### array + +Is the current processed field an array? + +##### basetype + +Is the current processed field in basetype? `basetype`s are defined in the map `FieldTypes` in `tools/schema/model/field.go`. + +##### core + +Is the current processed contract a core contract? + +##### event + +Does the current processed event have any field? + +##### events + +Is there any event in the current processed contract? + +##### exist + +Does the value of key `proxy` exist? + +##### func + +Is the current processed function a `func` or a `view`? Return true if it is a `func`. + +##### funcs + +Is there any function in the current processed contract? + +##### init + +Is the current function an init function? An init function will automatically be called immediately after the first time the contract has been deployed to the VM. + +##### mandatory + +Is current field a mandatory field? + +##### map + +Is current processed field a map (check if the `currentField.MapKey` is empty)? + +##### mut + +Is the value in key `mut` Mutable? + +##### param + +Does the current processed function have any parameter? + +##### params + +Does the current contract have any `params` field? + +##### ptrs + +Does the current processed function have either `params` or `results`. +This is used for implementing function object in Rust and TypeScript. + +##### result + +Does the current processed function have any return value? + +##### results + +Does the current contract have any `results` field? + +##### state + +Does the current contract have any `state` field? + +##### structs + +Does the current contract have any `structs` field? + +##### this + +Is the alias name of the current processed field `this`? + +##### typedef + +Is the current processed field a `typedef`? + +##### typedefs + +Does the current contract have any `typedefs` field? + +##### view + +Is the current processed function a `view` or a `func`? Return true if it is a `view`. + +##### else + +If you want to process a template under negate condition, then you can call + +``` +$#if condition else elseTemplate +``` + +Here `else` is a predefined empty template, which is defined at[`tools/schema/generator/templates.go`. + +#### set + +`set` is used for To dynamically specify a value to a certain key. The syntax is + +``` +$#set key value +``` + +For example, if you want to dynamically add a new key `initFunc` with the value in key `nil` you can call + +``` +$#set initFunc $nil +``` + +A special key `exist` is used to add a newly generated type. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/state.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/state.mdx new file mode 100644 index 00000000000..70252bfb4a1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/state.mdx @@ -0,0 +1,187 @@ +--- +tags: + - state + - access + - storage + - key + - data + - value + +description: The smart contract state storage on the host consists of a single key/value map, as long as you access the data in the same way that you used to store it, you will always get valid data back. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Define the State + +In smart contract state storage, there is only a single key/value map, +where both the key and value are constituted of raw data bytes. +To ensure the retrieval of valid data, access it in the manner it was stored. + +The [Schema Tool](usage.mdx) facilitates this by generating a type-safe layer +that oversees the consistent utilization of the expected data type during _data storage_ and retrieval. + +## State Section in Schema Definition File + +In the schema definition file the `state` section hosts field definitions, +delineating the variables stored in the state storage. +Each field is defined with a YAML key/value pair, indicating its name and data type. +This pair can optionally be followed by a descriptive comment. + +With these details, the [Schema Tool](usage.mdx) creates specific code to type-safely access state variables. +Take a closer look at the `state` section in the `dividend` example to understand this better: + + + + +```yaml +state: + memberList: Address[] # array with all the recipients of this dividend + + # factors per member + + members: map[Address]Uint64 # map with all the recipient factors of this dividend + owner: AgentID # owner of contract, the only one who can call 'member' func + totalFactor: Uint64 # sum of all recipient factors +``` + + + + +### Simple Variables + +Starting with straightforward state variables, `totalFactor`, +and `owner` are characterized as Uint64 and AgentID, respectively. +These represent predefined [WasmLib value types](../../reference/wasm-lib-data-types.mdx). + +### Arrays and Maps + +Next, the `memberList` variable denoted by empty brackets `[]`, symbolizing an array. +This array accommodates elements of a homogenous predefined Address value type. + +Lastly, the `members` variable, signified as a map with `map[]`, houses keys of a uniform predefined Address type. +Following the brackets, the homogenous value type, here `Uint64`, is mentioned. + + + + + +```go +type MutableDividendState struct { + proxy wasmtypes.Proxy +} + +func (s MutableDividendState) AsImmutable() ImmutableDividendState { + return ImmutableDividendState(s) +} + +// array with all the recipients of this dividend +func (s MutableDividendState) MemberList() ArrayOfMutableAddress { + return ArrayOfMutableAddress{proxy: s.proxy.Root(StateMemberList)} +} + +// map with all the recipient factors of this dividend +func (s MutableDividendState) Members() MapAddressToMutableUint64 { + return MapAddressToMutableUint64{proxy: s.proxy.Root(StateMembers)} +} + +// owner of contract, the only one who can call 'member' func +func (s MutableDividendState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} + +// sum of all recipient factors +func (s MutableDividendState) TotalFactor() wasmtypes.ScMutableUint64 { + return wasmtypes.NewScMutableUint64(s.proxy.Root(StateTotalFactor)) +} +``` + + + + +```rust +#[derive(Clone)] +pub struct MutableDividendState { + pub(crate) proxy: Proxy, +} + +impl MutableDividendState { + pub fn as_immutable(&self) -> ImmutableDividendState { + ImmutableDividendState { proxy: self.proxy.root("") } + } + + // array with all the recipients of this dividend + pub fn member_list(&self) -> ArrayOfMutableAddress { + ArrayOfMutableAddress { proxy: self.proxy.root(STATE_MEMBER_LIST) } + } + + // map with all the recipient factors of this dividend + pub fn members(&self) -> MapAddressToMutableUint64 { + MapAddressToMutableUint64 { proxy: self.proxy.root(STATE_MEMBERS) } + } + + // owner of contract, the only one who can call 'member' func + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + // sum of all recipient factors + pub fn total_factor(&self) -> ScMutableUint64 { + ScMutableUint64::new(self.proxy.root(STATE_TOTAL_FACTOR)) + } +} +``` + + + + +```ts +export class MutableDividendState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableDividendState { + return new sc.ImmutableDividendState(this.proxy); + } + + // array with all the recipients of this dividend + memberList(): sc.ArrayOfMutableAddress { + return new sc.ArrayOfMutableAddress(this.proxy.root(sc.StateMemberList)); + } + + // map with all the recipient factors of this dividend + members(): sc.MapAddressToMutableUint64 { + return new sc.MapAddressToMutableUint64(this.proxy.root(sc.StateMembers)); + } + + // owner of contract, the only one who can call 'member' func + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } + + // sum of all recipient factors + totalFactor(): wasmtypes.ScMutableUint64 { + return new wasmtypes.ScMutableUint64(this.proxy.root(sc.StateTotalFactor)); + } +} +``` + + + + +## Generated Code Overview + +Examining the `state.xx`code, generated by the [Schema Tool](usage.mdx), +you can find the `MutableDividendState` struct. +This interface allows type-safe access to each state variable through mutable [proxies](../../schema/proxies.mdx), +establishing a one-to-one relationship with the `state` section in the schema definition file. + +### Proxy Interfaces + +Note the generated proxy interface named `MutableDividendState` for mutable `dividend` state. +It enables type-safe proxy object access for each corresponding variable. +Moreover, the tool auto-generates intermediate map and array proxy types, +such as `ArrayOfMutableAddress` and `MapAddressToMutableUint64`, +enforcing the utilization of respective homogenous types. + +See the full `state.xx` for more details. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/structs.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/structs.mdx new file mode 100644 index 00000000000..810c2f398b2 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/structs.mdx @@ -0,0 +1,513 @@ +--- +tags: + - functions + - state + - structures + - storage + - named fields + +description: You can use structs directly as a type in state storage definitions and the schema tool will automatically generate the proxy code to access it properly. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Structured Data Types + +The [Schema Tool](usage.mdx) allows you to define your structured data types that are +composed of the predefined WasmLib value data types. The tool will generate a struct with +named fields according to the definition in the schema definition file and also will +generate code to serialize and deserialize the structure to a byte array so that it can +be saved as a single unit of data bytes, for example in state storage. + +You can use structs directly as a type in state storage definitions, and the +[Schema Tool](usage.mdx) will automatically generate the proxy code to access and +(de)serialize it properly. + +For example, let's say you are creating a `betting` smart contract. Then, you would want to +store information for each bet. The Bet structure could consist of the bet amount and +time, the number of the item that was bet on, and the agent ID of the one who placed the +bet. And you would keep track of all bets in state storage in an array of Bet structs. To +do so, you would insert the following into the schema definition file: + + + + +```yaml +structs: + Bet: + amount: Int64 # bet amount + better: AgentID # who placed this bet + number: Int32 # number of item we bet on + time: Int64 # timestamp of this bet +state: + bets: Bet[] # all bets that were made in this round +``` + + + + +The [Schema Tool](usage.mdx) will generate the following code in `structs.xx` for the Bet +struct: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type Bet struct { + // bet amount + Amount int64 + // who placed this bet + Better wasmtypes.ScAgentID + // number of item we bet on + Number int32 + // timestamp of this bet + Time int64 +} + +func NewBetFromBytes(buf []byte) *Bet { + dec := wasmtypes.NewWasmDecoder(buf) + data := &Bet{} + data.Amount = wasmtypes.Int64Decode(dec) + data.Better = wasmtypes.AgentIDDecode(dec) + data.Number = wasmtypes.Int32Decode(dec) + data.Time = wasmtypes.Int64Decode(dec) + dec.Close() + return data +} + +func (o *Bet) Bytes() []byte { + enc := wasmtypes.NewWasmEncoder() + wasmtypes.Int64Encode(enc, o.Amount) + wasmtypes.AgentIDEncode(enc, o.Better) + wasmtypes.Int32Encode(enc, o.Number) + wasmtypes.Int64Encode(enc, o.Time) + return enc.Buf() +} + +type ImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (o ImmutableBet) Exists() bool { + return o.proxy.Exists() +} + +func (o ImmutableBet) Value() *Bet { + return NewBetFromBytes(o.proxy.Get()) +} + +type MutableBet struct { + proxy wasmtypes.Proxy +} + +func (o MutableBet) Delete() { + o.proxy.Delete() +} + +func (o MutableBet) Exists() bool { + return o.proxy.Exists() +} + +func (o MutableBet) SetValue(value *Bet) { + o.proxy.Set(value.Bytes()) +} + +func (o MutableBet) Value() *Bet { + return NewBetFromBytes(o.proxy.Get()) +} +``` + + + + +```rust +use wasmlib::*; + +#[derive(Clone)] +pub struct Bet { + // bet amount + pub amount : i64, + // who placed this bet + pub better : ScAgentID, + // number of item we bet on + pub number : i32, + // timestamp of this bet + pub time : i64, +} + +impl Bet { + pub fn from_bytes(bytes: &[u8]) -> Bet { + let mut dec = WasmDecoder::new(bytes); + Bet { + amount : int64_decode(&mut dec), + better : agent_id_decode(&mut dec), + number : int32_decode(&mut dec), + time : int64_decode(&mut dec), + } + } + + pub fn to_bytes(&self) -> Vec { + let mut enc = WasmEncoder::new(); + int64_encode(&mut enc, self.amount); + agent_id_encode(&mut enc, &self.better); + int32_encode(&mut enc, self.number); + int64_encode(&mut enc, self.time); + enc.buf() + } +} + +#[derive(Clone)] +pub struct ImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ImmutableBet { + pub fn exists(&self) -> bool { + self.proxy.exists() + } + + pub fn value(&self) -> Bet { + Bet::from_bytes(&self.proxy.get()) + } +} + +#[derive(Clone)] +pub struct MutableBet { + pub(crate) proxy: Proxy, +} + +impl MutableBet { + pub fn delete(&self) { + self.proxy.delete(); + } + + pub fn exists(&self) -> bool { + self.proxy.exists() + } + + pub fn set_value(&self, value: &Bet) { + self.proxy.set(&value.to_bytes()); + } + + pub fn value(&self) -> Bet { + Bet::from_bytes(&self.proxy.get()) + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; + +export class Bet { + // bet amount + amount: i64 = 0; + // who placed this bet + better: wasmtypes.ScAgentID = wasmtypes.agentIDFromBytes([]); + // number of item we bet on + number: i32 = 0; + // timestamp of this bet + time: i64 = 0; + + static fromBytes(buf: u8[]): Bet { + const dec = new wasmtypes.WasmDecoder(buf); + const data = new Bet(); + data.amount = wasmtypes.int64Decode(dec); + data.better = wasmtypes.agentIDDecode(dec); + data.number = wasmtypes.int32Decode(dec); + data.time = wasmtypes.int64Decode(dec); + dec.close(); + return data; + } + + bytes(): u8[] { + const enc = new wasmtypes.WasmEncoder(); + wasmtypes.int64Encode(enc, this.amount); + wasmtypes.agentIDEncode(enc, this.better); + wasmtypes.int32Encode(enc, this.number); + wasmtypes.int64Encode(enc, this.time); + return enc.buf(); + } +} + +export class ImmutableBet extends wasmtypes.ScProxy { + exists(): bool { + return this.proxy.exists(); + } + + value(): Bet { + return Bet.fromBytes(this.proxy.get()); + } +} + +export class MutableBet extends wasmtypes.ScProxy { + delete(): void { + this.proxy.delete(); + } + + exists(): bool { + return this.proxy.exists(); + } + + setValue(value: Bet): void { + this.proxy.set(value.bytes()); + } + + value(): Bet { + return Bet.fromBytes(this.proxy.get()); + } +} +``` + + + + +Notice how the generated ImmutableBet and MutableBet proxies use the fromBytes() and +toBytes() (de)serialization code to automatically transform byte arrays into Bet structs. + +The generated code in `state.xx` that implements the state interface is shown here: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBet) GetBet(index uint32) ImmutableBet { + return ImmutableBet{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingState struct { + proxy wasmtypes.Proxy +} + +// all bets that were made in this round +func (s ImmutableBettingState) Bets() ArrayOfImmutableBet { + return ArrayOfImmutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s ImmutableBettingState) Owner() wasmtypes.ScImmutableAgentID { + return wasmtypes.NewScImmutableAgentID(s.proxy.Root(StateOwner)) +} + +type ArrayOfMutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBet) AppendBet() MutableBet { + return MutableBet{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBet) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBet) GetBet(index uint32) MutableBet { + return MutableBet{proxy: a.proxy.Index(index)} +} + +type MutableBettingState struct { + proxy wasmtypes.Proxy +} + +func (s MutableBettingState) AsImmutable() ImmutableBettingState { + return ImmutableBettingState(s) +} + +// all bets that were made in this round +func (s MutableBettingState) Bets() ArrayOfMutableBet { + return ArrayOfMutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s MutableBettingState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBet { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> ImmutableBet { + ImmutableBet { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct ImmutableBettingState { + pub(crate) proxy: Proxy, +} + +impl ImmutableBettingState { + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfImmutableBet { + ArrayOfImmutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScImmutableAgentID { + ScImmutableAgentID::new(self.proxy.root(STATE_OWNER)) + } +} + +#[derive(Clone)] +pub struct ArrayOfMutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBet { + + pub fn append_bet(&self) -> MutableBet { + MutableBet { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> MutableBet { + MutableBet { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct MutableBettingState { + pub(crate) proxy: Proxy, +} + +impl MutableBettingState { + pub fn as_immutable(&self) -> ImmutableBettingState { + ImmutableBettingState { proxy: self.proxy.root("") } + } + + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfMutableBet { + ArrayOfMutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBet extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.ImmutableBet { + return new sc.ImmutableBet(this.proxy.index(index)); + } +} + +export class ImmutableBettingState extends wasmtypes.ScProxy { + // all bets that were made in this round + bets(): sc.ArrayOfImmutableBet { + return new sc.ArrayOfImmutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScImmutableAgentID { + return new wasmtypes.ScImmutableAgentID(this.proxy.root(sc.StateOwner)); + } +} + +export class ArrayOfMutableBet extends wasmtypes.ScProxy { + appendBet(): sc.MutableBet { + return new sc.MutableBet(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.MutableBet { + return new sc.MutableBet(this.proxy.index(index)); + } +} + +export class MutableBettingState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableBettingState { + return new sc.ImmutableBettingState(this.proxy); + } + + // all bets that were made in this round + bets(): sc.ArrayOfMutableBet { + return new sc.ArrayOfMutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } +} +``` + + + + +The results are ImmutableBettingState and MutableBettingState structures that can +directly interface to the state of the betting contract. + +Note how the comments from the schema definition file have been copied to the code's structure definition and access +functions for the fields. This will allow your development environment to pop up context - sensitive help +for those fields and access functions. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/thunks.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/thunks.mdx new file mode 100644 index 00000000000..76531cd30a1 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/thunks.mdx @@ -0,0 +1,379 @@ +--- +description: 'Learn about thunk functions and how the Schema Tool uses them to facilitate smart contract function calls.' +tags: + - Thunk Functions + - Schema Tool + - Wrapper Function + - Smart Contract Functions + - Type-Safe + - Function Signature + - Code Injection +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Thunk Functions + +In software development, thunk functions are a crucial part of setting up smart contracts correctly, +facilitating type-safety and easy mapping of function names to their actual implementations. + +## Overview + +A thunk is a wrapper function employed to inject code before and/or after a function call. +It helps in adapting functions to meet changing demands. +Through the [Schema Tool](usage.mdx), +thunks are generated to establish correct calls to smart contract functions and to ensure type-safety. +They share a common function signature, fostering a straightforward creation of a function table for generic calls. + +## Role in Wasm + +Working hand in hand with the WebAssembly (Wasm) format, +thunks play a pivotal role in the `lib.xx` component. +Below is how a chunk of a `dividend` smart contract would look (the detailed thunk function content is omitted): + + + + + +```go +var exportMap = wasmlib.ScExportMap{ + Names: []string{ + FuncDivide, + FuncInit, + FuncMember, + FuncSetOwner, + ViewGetFactor, + ViewGetOwner, + }, + Funcs: []wasmlib.ScFuncContextFunction{ + funcDivideThunk, + funcInitThunk, + funcMemberThunk, + funcSetOwnerThunk, + }, + Views: []wasmlib.ScViewContextFunction{ + viewGetFactorThunk, + viewGetOwnerThunk, + }, +} + +func OnDispatch(index int32) { + exportMap.Dispatch(index) +} + +func funcDivideThunk(ctx wasmlib.ScFuncContext) {} +func funcInitThunk(ctx wasmlib.ScFuncContext) {} +func funcMemberThunk(ctx wasmlib.ScFuncContext) {} +func funcSetOwnerThunk(ctx wasmlib.ScFuncContext) {} +func viewGetFactorThunk(ctx wasmlib.ScViewContext) {} +func viewGetOwnerThunk(ctx wasmlib.ScViewContext) {} +``` + + + + +```rust +const EXPORT_MAP: ScExportMap = ScExportMap { + names: &[ + FUNC_DIVIDE, + FUNC_INIT, + FUNC_MEMBER, + FUNC_SET_OWNER, + VIEW_GET_FACTOR, + VIEW_GET_OWNER, + ], + funcs: &[ + func_divide_thunk, + func_init_thunk, + func_member_thunk, + func_set_owner_thunk, + ], + views: &[ + view_get_factor_thunk, + view_get_owner_thunk, + ], +}; + +pub fn on_dispatch(index: i32) { + EXPORT_MAP.dispatch(index); +} + +fn func_divide_thunk(ctx: &ScFuncContext) {} +fn func_init_thunk(ctx: &ScFuncContext) {} +fn func_member_thunk(ctx: &ScFuncContext) {} +fn func_set_owner_thunk(ctx: &ScFuncContext) {} +fn view_get_factor_thunk(ctx: &ScViewContext) {} +fn view_get_owner_thunk(ctx: &ScViewContext) {} +``` + + + + +```ts +const exportMap: wasmlib.ScExportMap = { + names: [ + sc.FuncDivide, + sc.FuncInit, + sc.FuncMember, + sc.FuncSetOwner, + sc.ViewGetFactor, + sc.ViewGetOwner, + ], + funcs: [funcDivideThunk, funcInitThunk, funcMemberThunk, funcSetOwnerThunk], + views: [viewGetFactorThunk, viewGetOwnerThunk], +}; + +export function on_dispatch(index: i32): void { + exportMap.dispatch(index); +} + +function funcDivideThunk(ctx: ScFuncContext) {} +function funcInitThunk(ctx: ScFuncContext) {} +function funcMemberThunk(ctx: ScFuncContext) {} +function funcSetOwnerThunk(ctx: ScFuncContext) {} +function viewGetFactorThunk(ctx: ScViewContext) {} +function viewGetOwnerThunk(ctx: ScViewContext) {} +``` + + + + +## The Dispatch Process + +The central player here is the `OnDispatch()` function, +called by the primary Wasm file, essentially a dynamic link library. +This mechanism keeps the smart contract (SC) code self-contained and versatile, +fitting for both Wasm requirements and direct client-side executions. + +To meet Wasm's demands, we implement `on_load()` and `on_call()` callbacks that collaborate with `OnDispatch()` in the `lib.xx`, +orchestrating a seamless dispatch process. + +### `on_load()` + +The `on_load()` Wasm function will be called by the Wasm VM host upon loading of the Wasm +code. It will inform the host of all the function ids and types (Func or View) that this +smart contract provides. + +### `on_call()` + +When the host needs to call a function of the smart contract it will call the `on_call()` +callback function with the corresponding function id, and then the `on_call()` function +will dispatch the call via the `ScExportMap` mapping table that was generated by the +[Schema Tool](usage.mdx) to the proper associated thunk function. + +## Generated Main Entry Point + +Here is the generated `main.xx` that forms the main entry point for the Wasm code: + + + + + +```go +//go:build wasm +// +build wasm + +package main + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmvmhost/go/wasmvmhost" + +import "github.com/iotaledger/wasp/contracts/wasm/dividend/go/dividend" + +func main() { +} + +func init() { + wasmvmhost.ConnectWasmHost() +} + +//export on_call +func onCall(index int32) { + dividend.OnDispatch(index) +} + +//export on_load +func onLoad() { + dividend.OnDispatch(-1) +} +``` + + + + +```rust +use dividend::*; +use wasmvmhost::*; + +#[no_mangle] +fn on_call(index: i32) { + WasmVmHost::connect(); + on_dispatch(index); +} + +#[no_mangle] +fn on_load() { + WasmVmHost::connect(); + on_dispatch(-1); +} +``` + + + + +```ts +import * as wasmvmhost from 'wasmvmhost'; +import * as sc from './dividend'; + +export function on_call(index: i32): void { + wasmvmhost.WasmVMHost.connect(); + sc.onDispatch(index); +} + +export function on_load(): void { + wasmvmhost.WasmVMHost.connect(); + sc.onDispatch(-1); +} +``` + + + + +Finally, here is an example implementation of a thunk function for the `setOwner()` +contract function. You can examine the other thunk functions that all follow the same +pattern in the generated `lib.xx`: + + + + + +```go +type SetOwnerContext struct { + Params ImmutableSetOwnerParams + State MutableDividendState +} + +func funcSetOwnerThunk(ctx wasmlib.ScFuncContext) { + ctx.Log("dividend.funcSetOwner") + f := &SetOwnerContext{ + Params: ImmutableSetOwnerParams{ + proxy: wasmlib.NewParamsProxy(), + }, + State: MutableDividendState{ + proxy: wasmlib.NewStateProxy(), + }, + } + + // only defined owner of contract can change owner + access := f.State.Owner() + ctx.Require(access.Exists(), "access not set: owner") + ctx.Require(ctx.Caller() == access.Value(), "no permission") + + ctx.Require(f.Params.Owner().Exists(), "missing mandatory owner") + funcSetOwner(ctx, f) + ctx.Log("dividend.funcSetOwner ok") +} +``` + + + + +```rust +pub struct SetOwnerContext { + params: ImmutableSetOwnerParams, + state: MutableDividendState, +} + +fn func_set_owner_thunk(ctx: &ScFuncContext) { + ctx.log("dividend.funcSetOwner"); + let f = SetOwnerContext { + params: ImmutableSetOwnerParams { proxy: params_proxy() }, + state: MutableDividendState { proxy: state_proxy() }, + }; + + // only defined owner of contract can change owner + let access = f.state.owner(); + ctx.require(access.exists(), "access not set: owner"); + ctx.require(ctx.caller() == access.value(), "no permission"); + + ctx.require(f.params.owner().exists(), "missing mandatory owner"); + func_set_owner(ctx, &f); + ctx.log("dividend.funcSetOwner ok"); +} +``` + + + + +```ts +// this class is actually defined in contract.ts +export class SetOwnerContext { + params: sc.ImmutableSetOwnerParams = new sc.ImmutableSetOwnerParams( + wasmlib.paramsProxy(), + ); + state: sc.MutableDividendState = new sc.MutableDividendState( + wasmlib.ScState.proxy(), + ); +} + +function funcSetOwnerThunk(ctx: wasmlib.ScFuncContext): void { + ctx.log('dividend.funcSetOwner'); + let f = new sc.SetOwnerContext(); + + // only defined owner of contract can change owner + const access = f.state.owner(); + ctx.require(access.exists(), 'access not set: owner'); + ctx.require(ctx.caller().equals(access.value()), 'no permission'); + + ctx.require(f.params.owner().exists(), 'missing mandatory owner'); + sc.funcSetOwner(ctx, f); + ctx.log('dividend.funcSetOwner ok'); +} +``` + + + + +## The Thunk Function in Action + +### Log the Contract and Function Name + +First, the thunk logs the contract and function name to show that the call has started. + +### Set Up Strongly Typed Context + +Then it sets up a strongly typed function-specific context structure. First, we add the +function-specific immutable [Params](params.mdx) interface structure, which is only +present when the function can have parameters. Then we add the contract-specific +[State](state.mdx) interface structure. In this case, it is mutable because setOwner is a +[Func](funcs.mdx). For [Views](views.mdx), this would be an immutable state interface. +Finally, we would add the function-specific mutable [Results](results.mdx) interface +structure, which is only present when the function returns results. +This is not the case for this `setOwner()` function. + +### Set Up Access Control + +Next, it sets up access control for the function according to the schema definition file. +In this case, it retrieves the `owner` state variable through the function context, +requires that the variable exists, and then requires that the function's `caller()` +equals that value. Any failing requirement will panic out of the thunk function with an +error message. So, this code ensures that only the contract owner can call this +function. + +### Verify Function Parameters + +Now we get to the point where we can use the function-specific [Params](params.mdx) +interface to check for mandatory parameters. Each mandatory parameter is required to +exist, or else we will panic out of the thunk function with an error message. + +### Call the Smart Contract Function + +With the setup and automated checks completed, we now call the actual smart contract +function implementation the user maintains. +After this function has been completed, +we would process the returned results for those functions that have any (in this case, we +don't have results). +Finally, we log that the contract function has been completed +successfully. Remember that any error within the user function will cause a panic, so this +logging will never occur in case that happens. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/transfers.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/transfers.mdx new file mode 100644 index 00000000000..8e9e2447797 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/transfers.mdx @@ -0,0 +1,242 @@ +--- +description: 'Explore methods in the Call Context that facilitate the handling and transfer of asset balances in smart contracts using the `dividend` example.' +tags: + - Call Context + - Asset Balances + - ScBalances Proxy + - ScTransfer Proxy + - Dividend Smart Contract +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Transfer Tokens + +The [Call Context](../../explanations/context.mdx) in smart contracts introduces two vital methods - +`balances()` and `allowance()` - to manage token balances efficiently. +Understanding how to use these can be foundational in setting up smart contracts, +as demonstrated in the `dividend` smart contract example. + +## Methods Overview + +### 1. **`balances()` Method**: + +- **Functionality**: Fetch the present asset balances regulated by the smart contract. +- **Access**: Through the `ScBalances` proxy. + +### 2. **`allowance()` Method**: + +- **Functionality**: Verify the caller assets that the current smart contract function can use. +- **Transfer Requirement**: Assets are not automatically transferred; + the function must instigate the transfer explicitly within the allowed limit. +- **Access**: Through the `ScBalances` proxy. + +### 3. **`transfer_allowed()` Method**: + +- **Functionality**: Facilitate asset transfers from the caller's on-chain account to another on-chain account. +- **Proxy**: uses the `ScTransfer` proxy, a mutable variant of `ScBalances`. +- **Application**: In the `dividend` contract, it aids in distributing iotas to member accounts. + +## Dividend Smart Contract Example + +The `dividend` smart contract operates on a principle of equitable asset distribution to its members based on predefined factors. +Here's how it works: + +1. **Setup**: Establish a list of members with associated address/factor pairs and calculate the total factor sum. +2. **Function**: The `divide()` function manages the dividend distribution. +3. **Dividend Allocation**: + - **Input**: Iotas sent to the `divide()` function. + - **Distribution**: Proportional to the individual's factor. + - **Example**: For factors A:50, B:30, and C:20 (total 100): + - **A receives**: 50/100 of the input iotas. + - **B receives**: 30/100 of the input iotas. + - **C receives**: 20/100 of the input iotas. + +In this system, asset distribution is transparent, fair, and automated, ensuring a streamlined division process. + +Here is the `divide` function: + + + + + +```go +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in the sender account. +func funcDivide(ctx wasmlib.ScFuncContext, f *DivideContext) { + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + var allowance *wasmlib.ScBalances = ctx.Allowance() + + // Retrieve the amount of plain iota tokens from the account balance. + var amount uint64 = allowance.BaseTokens() + + // Retrieve the pre-calculated totalFactor value from the state storage. + var totalFactor uint64 = f.State.TotalFactor().Value() + + // Get the proxy to the 'members' map in the state storage. + var members MapAddressToMutableUint64 = f.State.Members() + + // Get the proxy to the 'memberList' array in the state storage. + var memberList ArrayOfMutableAddress = f.State.MemberList() + + // Determine the current length of the memberList array. + var size uint32 = memberList.Length() + + // Loop through all indexes of the memberList array. + for i := uint32(0); i < size; i++ { + // Retrieve the next indexed address from the memberList array. + var address wasmtypes.ScAddress = memberList.GetAddress(i).Value() + + // Retrieve the factor associated with the address from the members map. + var factor uint64 = members.GetUint64(address).Value() + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will been truncated. + var share uint64 = amount * factor / totalFactor + + // Is there anything to disperse to this member? + if share > 0 { + // Yes, so let's set up an ScTransfer map proxy that transfers the + // calculated amount of tokens. + var transfer *wasmlib.ScTransfer = wasmlib.NewScTransferBaseTokens(share) + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.TransferAllowed(address.AsAgentID(), transfer) + } + } +} +``` + + + + +```rust +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in its own account. They will be added +// to any next round of tokens received prior to calculation of the new +// dividend amounts. +pub fn func_divide(ctx: &ScFuncContext, f: &DivideContext) { + + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + let allowance: ScBalances = ctx.allowance(); + + // Retrieve the amount of plain iota tokens from the account balance. + let amount: u64 = allowance.base_tokens(); + + // Retrieve the pre-calculated totalFactor value from the state storage. + let total_factor: u64 = f.state.total_factor().value(); + + // Get the proxy to the 'members' map in the state storage. + let members: MapAddressToMutableUint64 = f.state.members(); + + // Get the proxy to the 'memberList' array in the state storage. + let member_list: ArrayOfMutableAddress = f.state.member_list(); + + // Determine the current length of the memberList array. + let size: u32 = member_list.length(); + + // Loop through all indexes of the memberList array. + for i in 0..size { + // Retrieve the next indexed address from the memberList array. + let address: ScAddress = member_list.get_address(i).value(); + + // Retrieve the factor associated with the address from the members map. + let factor: u64 = members.get_uint64(&address).value(); + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will be truncated. + let share: u64 = amount * factor / total_factor; + + // Is there anything to disperse to this member? + if share > 0 { + // Yes, so let's set up an ScTransfer map proxy that transfers the + // calculated amount of tokens. + let transfers: ScTransfer = ScTransfer::base_tokens(share); + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.transfer_allowed(&address.as_agent_id(), &transfers, true); + } + } +} +``` + + + + +```ts +// 'divide' is a function that will take any iotas it receives and properly +// disperse them to the accounts in the member list according to the dispersion +// factors associated with these accounts. +// Anyone can send iotas to this function and they will automatically be +// divided over the member list. Note that this function does not deal with +// fractions. It simply truncates the calculated amount to the nearest lower +// integer and keeps any remaining tokens in its own account. They will be added +// to any next round of tokens received prior to calculation of the new +// dividend amounts. +export function funcDivide( + ctx: wasmlib.ScFuncContext, + f: sc.DivideContext, +): void { + // Create an ScBalances proxy to the allowance balances for this + // smart contract. + let allowance: wasmlib.ScBalances = ctx.allowance(); + + // Retrieve the allowed amount of plain iota tokens from the account balance. + let amount: u64 = allowance.baseTokens(); + + // Retrieve the pre-calculated totalFactor value from the state storage. + let totalFactor: u64 = f.state.totalFactor().value(); + + // Get the proxy to the 'members' map in the state storage. + let members: sc.MapAddressToMutableUint64 = f.state.members(); + + // Get the proxy to the 'memberList' array in the state storage. + let memberList: sc.ArrayOfMutableAddress = f.state.memberList(); + + // Determine the current length of the memberList array. + let size: u32 = memberList.length(); + + // Loop through all indexes of the memberList array. + for (let i: u32 = 0; i < size; i++) { + // Retrieve the next indexed address from the memberList array. + let address: wasmlib.ScAddress = memberList.getAddress(i).value(); + + // Retrieve the factor associated with the address from the members map. + let factor: u64 = members.getUint64(address).value(); + + // Calculate the fair share of tokens to disperse to this member based on the + // factor we just retrieved. Note that the result will be truncated. + let share: u64 = (amount * factor) / totalFactor; + + // Is there anything to disperse to this member? + if (share > 0) { + // Yes, so let's set up an ScTransfer proxy that transfers the + // calculated amount of tokens. + let transfers: wasmlib.ScTransfer = wasmlib.ScTransfer.baseTokens(share); + + // Perform the actual transfer of tokens from the caller allowance + // to the member account. + ctx.transferAllowed(address.asAgentID(), transfers); + } + } +} +``` + + + diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/typedefs.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/typedefs.mdx new file mode 100644 index 00000000000..2d55e859696 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/typedefs.mdx @@ -0,0 +1,456 @@ +--- +tags: + - containers + - types + - container types + - single type + - array + - schema definition file + +description: You can add a typedefs section to the schema definition file, where you can define a single type name for a container type. This way you can easily create containers that contain container types. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Type Definitions + +:::note WasmLib Types + +You can find the complete list of [WasmLib Data Types](../../reference/wasm-lib-data-types.mdx) in the reference section. + +::: + +The WasmLib allows of [container types](../../schema/proxies.mdx#container-proxies), but it +is not possible to specify these types directly because the type name syntax only allows +you to specify a single container type. + +There is a simple solution to this problem. You can add a `typedefs` section to the schema +definition file, where you can define a single type name for a container type. That way +you can easily create containers that contain such container types. The +[Schema Tool](usage.mdx) will automatically generate the in-between proxy types necessary +to make this work. + +To keep it at the `betting` smart contract from [the previous section](structs.mdx), +imagine you want to keep track of all betting rounds. Since a betting round contains an +array of all bets in a round, if it weren't for typedefs you could not define it easily. + +Instead, now you add the following to your schema definition file: + + + + +```yaml +typedefs: + BettingRound: Bet[] // one round of bets +state: + rounds: BettingRound[] // keep track of all betting rounds +``` + + + + +The [Schema Tool](usage.mdx) will generate the following code in `typedefs.xx` for the +`BettingRound` type: + + + + + +```go +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBet) GetBet(index uint32) ImmutableBet { + return ImmutableBet{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingRound = ArrayOfImmutableBet + +type ArrayOfMutableBet struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBet) AppendBet() MutableBet { + return MutableBet{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBet) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBet) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBet) GetBet(index uint32) MutableBet { + return MutableBet{proxy: a.proxy.Index(index)} +} + +type MutableBettingRound = ArrayOfMutableBet +``` + + + + +```rust +use wasmlib::*; +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBet { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> ImmutableBet { + ImmutableBet { proxy: self.proxy.index(index) } + } +} + +pub type ImmutableBettingRound = ArrayOfImmutableBet; + +#[derive(Clone)] +pub struct ArrayOfMutableBet { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBet { + + pub fn append_bet(&self) -> MutableBet { + MutableBet { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_bet(&self, index: u32) -> MutableBet { + MutableBet { proxy: self.proxy.index(index) } + } +} + +pub type MutableBettingRound = ArrayOfMutableBet; +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBet extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.ImmutableBet { + return new sc.ImmutableBet(this.proxy.index(index)); + } +} + +export class ImmutableBettingRound extends ArrayOfImmutableBet {} + +export class ArrayOfMutableBet extends wasmtypes.ScProxy { + appendBet(): sc.MutableBet { + return new sc.MutableBet(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBet(index: u32): sc.MutableBet { + return new sc.MutableBet(this.proxy.index(index)); + } +} + +export class MutableBettingRound extends ArrayOfMutableBet {} +``` + + + + +Note how `ImmutableBettingRound` and `MutableBettingRound` type aliases are created +for the types `ArrayOfImmutableBet` and `ArrayOfMutableBet`. These are subsequently used +in the state definition that is generated in `state.xx`: + + + + + +```go +package betting + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes" + +type ArrayOfImmutableBettingRound struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfImmutableBettingRound) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfImmutableBettingRound) GetBettingRound(index uint32) ImmutableBettingRound { + return ImmutableBettingRound{proxy: a.proxy.Index(index)} +} + +type ImmutableBettingState struct { + proxy wasmtypes.Proxy +} + +// all bets that were made in this round +func (s ImmutableBettingState) Bets() ArrayOfImmutableBet { + return ArrayOfImmutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s ImmutableBettingState) Owner() wasmtypes.ScImmutableAgentID { + return wasmtypes.NewScImmutableAgentID(s.proxy.Root(StateOwner)) +} + +func (s ImmutableBettingState) Rounds() ArrayOfImmutableBettingRound { + return ArrayOfImmutableBettingRound{proxy: s.proxy.Root(StateRounds)} +} + +type ArrayOfMutableBettingRound struct { + proxy wasmtypes.Proxy +} + +func (a ArrayOfMutableBettingRound) AppendBettingRound() MutableBettingRound { + return MutableBettingRound{proxy: a.proxy.Append()} +} + +func (a ArrayOfMutableBettingRound) Clear() { + a.proxy.ClearArray() +} + +func (a ArrayOfMutableBettingRound) Length() uint32 { + return a.proxy.Length() +} + +func (a ArrayOfMutableBettingRound) GetBettingRound(index uint32) MutableBettingRound { + return MutableBettingRound{proxy: a.proxy.Index(index)} +} + +type MutableBettingState struct { + proxy wasmtypes.Proxy +} + +func (s MutableBettingState) AsImmutable() ImmutableBettingState { + return ImmutableBettingState(s) +} + +// all bets that were made in this round +func (s MutableBettingState) Bets() ArrayOfMutableBet { + return ArrayOfMutableBet{proxy: s.proxy.Root(StateBets)} +} + +// current owner of this smart contract +func (s MutableBettingState) Owner() wasmtypes.ScMutableAgentID { + return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner)) +} + +func (s MutableBettingState) Rounds() ArrayOfMutableBettingRound { + return ArrayOfMutableBettingRound{proxy: s.proxy.Root(StateRounds)} +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +#[derive(Clone)] +pub struct ArrayOfImmutableBettingRound { + pub(crate) proxy: Proxy, +} + +impl ArrayOfImmutableBettingRound { + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_betting_round(&self, index: u32) -> ImmutableBettingRound { + ImmutableBettingRound { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct ImmutableBettingState { + pub(crate) proxy: Proxy, +} + +impl ImmutableBettingState { + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfImmutableBet { + ArrayOfImmutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScImmutableAgentID { + ScImmutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + pub fn rounds(&self) -> ArrayOfImmutableBettingRound { + ArrayOfImmutableBettingRound { proxy: self.proxy.root(STATE_ROUNDS) } + } +} + +#[derive(Clone)] +pub struct ArrayOfMutableBettingRound { + pub(crate) proxy: Proxy, +} + +impl ArrayOfMutableBettingRound { + + pub fn append_betting_round(&self) -> MutableBettingRound { + MutableBettingRound { proxy: self.proxy.append() } + } + pub fn clear(&self) { + self.proxy.clear_array(); + } + + pub fn length(&self) -> u32 { + self.proxy.length() + } + + + pub fn get_betting_round(&self, index: u32) -> MutableBettingRound { + MutableBettingRound { proxy: self.proxy.index(index) } + } +} + +#[derive(Clone)] +pub struct MutableBettingState { + pub(crate) proxy: Proxy, +} + +impl MutableBettingState { + pub fn as_immutable(&self) -> ImmutableBettingState { + ImmutableBettingState { proxy: self.proxy.root("") } + } + + // all bets that were made in this round + pub fn bets(&self) -> ArrayOfMutableBet { + ArrayOfMutableBet { proxy: self.proxy.root(STATE_BETS) } + } + + // current owner of this smart contract + pub fn owner(&self) -> ScMutableAgentID { + ScMutableAgentID::new(self.proxy.root(STATE_OWNER)) + } + + pub fn rounds(&self) -> ArrayOfMutableBettingRound { + ArrayOfMutableBettingRound { proxy: self.proxy.root(STATE_ROUNDS) } + } +} +``` + + + + +```ts +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export class ArrayOfImmutableBettingRound extends wasmtypes.ScProxy { + length(): u32 { + return this.proxy.length(); + } + + getBettingRound(index: u32): sc.ImmutableBettingRound { + return new sc.ImmutableBettingRound(this.proxy.index(index)); + } +} + +export class ImmutableBettingState extends wasmtypes.ScProxy { + // all bets that were made in this round + bets(): sc.ArrayOfImmutableBet { + return new sc.ArrayOfImmutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScImmutableAgentID { + return new wasmtypes.ScImmutableAgentID(this.proxy.root(sc.StateOwner)); + } + + rounds(): sc.ArrayOfImmutableBettingRound { + return new sc.ArrayOfImmutableBettingRound(this.proxy.root(sc.StateRounds)); + } +} + +export class ArrayOfMutableBettingRound extends wasmtypes.ScProxy { + appendBettingRound(): sc.MutableBettingRound { + return new sc.MutableBettingRound(this.proxy.append()); + } + + clear(): void { + this.proxy.clearArray(); + } + + length(): u32 { + return this.proxy.length(); + } + + getBettingRound(index: u32): sc.MutableBettingRound { + return new sc.MutableBettingRound(this.proxy.index(index)); + } +} + +export class MutableBettingState extends wasmtypes.ScProxy { + asImmutable(): sc.ImmutableBettingState { + return new sc.ImmutableBettingState(this.proxy); + } + + // all bets that were made in this round + bets(): sc.ArrayOfMutableBet { + return new sc.ArrayOfMutableBet(this.proxy.root(sc.StateBets)); + } + + // current owner of this smart contract + owner(): wasmtypes.ScMutableAgentID { + return new wasmtypes.ScMutableAgentID(this.proxy.root(sc.StateOwner)); + } + + rounds(): sc.ArrayOfMutableBettingRound { + return new sc.ArrayOfMutableBettingRound(this.proxy.root(sc.StateRounds)); + } +} +``` + + + + +Notice how the `rounds()` member function returns a proxy to an array of `BettingRound`. +Which in turn is an array of `Bet`. So, the desired result has been achieved. And every +access step only allows you to take the path laid out, which is checked at +compile-time. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/usage.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/usage.mdx new file mode 100644 index 00000000000..4114e328ccc --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/usage.mdx @@ -0,0 +1,302 @@ +--- +tags: + - functions + - schema tool + - definition file + - Rust + - Go + - init + - json + - yml + +description: The `schema` tool will assist in creating a smart contract as unobtrusively as possible. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Use the Schema Tool + +Creating smart contracts is simplified using the _Schema Tool_. +This guide outlines the initial steps to set up a new smart contract from scratch. + +## Step 1: Establish a Central Folder + +Select a central folder to house all your smart contracts. +You'll create a separate subfolder for each contract within this central repository. + +Next, choose a descriptive, capitalized camel case name for your contract, like `MySmartContract`. + +## Step 2: Create a Subfolder + +After naming your smart contract, you should create a corresponding subfolder. +Open your terminal, navigate to the central folder, +and initialize your project with the Schema Tool using the following command: + +```shell +schema -init MySmartContract +``` + +This command will create a subfolder named `mysmartcontract` and generate an initial YAML +schema definition file inside this subfolder. Note that the generated subfolder name is +all lower-case. This is to conform to best practices for package names in most languages. +The generated schema definition file looks like this: + + + + +```yaml +name: MySmartContract +description: MySmartContract description +events: {} +structs: {} +typedefs: {} +state: + owner: AgentID // current owner of this smart contract +funcs: + init: + params: + owner: AgentID? // optional owner of this smart contract + setOwner: + access: owner // current owner of this smart contract + params: + owner: AgentID // new owner of this smart contract +views: + getOwner: + results: + owner: AgentID // current owner of this smart contract +``` + + + + +After initializing your project with the Schema Tool, +a pre-populated schema definition file will be generated in the `mysmartcontract` subfolder. +This file contains the necessary sections and functions to manage your smart contract's ownership. + +## Naming Conventions + +Ensure to follow the _camel case_ naming convention in the schema definition file. Here is how to use it: + +- Function and variable names: start with a lowercase letter (e.g., `myFunction`) +- Type names: start with an uppercase letter (e.g., `MyType`) + +## Customizing Fields + +Begin by updating the `description` field with a relevant description of your smart contract. +It is the perfect time to add any known definitions to the necessary sections. + +## Generating Initial Code + +Navigate to your `mysmartcontract` subfolder to generate the initial code for your preferred programming language using +the Schema Tool. + + + + + +If you want to generate Go code, you should run the schema tool with the `-go` option like +this: + +```shell +schema -go +``` + + + + +If you want to generate Rust code, you should run the schema tool with the `-rs` option +like this: + +```shell +schema -rs +``` + + + + +If you want to generate TypeScript code, you should run the schema tool with the `-ts` +option like this: + +```shell +schema -ts +``` + + + + +If you want to generate more than one language your can simply specify multiple options. +For example, to generate both Rust and Go code you would specify both options like this: + +```shell +schema -rs -go +``` + +The schema tool will generate a complete set of source files for the desired language(s), +that will compile successfully into a Wasm code file. You compile these as follows: + + + + + +```shell +tinygo build -target wasm go/main.go +``` + +This will use the Go source files in the go/mysmartcontract subfolder. The only file in +this folder that you should edit manually is `mysmartcontract.go`. All other source files +will be regenerated and overwritten whenever the schema tool is run again. + +See the [TinyGo](https://tinygo.org/) documentation for more build options. + + + + +After generating the Rust code, you should first modify the Cargo.toml file to your +liking, and potentially add the new project to a Rust workspace. Cargo.toml will not be +regenerated once it already exists. Then build the code as follows: + +```shell +wasm-pack build +``` + +This will use Rust source files in the `src` subfolder. The only file in this folder that +you should edit manually is `mysmartcontract.rs`. All other source files will be +regenerated and overwritten whenever the schema tool is run again. + +See the [wasm-pack](https://rustwasm.github.io/wasm-pack/) documentation for more build +options. + + + + +```shell +npx asc ts/mysmartcontract/lib.ts --outFile mysmartcontract_ts.wasm --lib path/to/node_modules +``` + +This will use the TypeScript source files in the ts/mysmartcontract subfolder. The only +file in this folder that you should edit manually is `mysmartcontract.ts`. All other +source files will be regenerated and overwritten whenever the schema tool is run again. + +See the [AssemblyScript](https://www.assemblyscript.org/) documentation for more build +options. + + + + +The generated code is essentially identical for each language, barring some language +idiosyncrasy differences. Just view different language files with the same name next to, +each other, and you will see what we mean. + +Here is an example of the initially generated code, `mysmartcontract.xx` looks like this +before you even start modifying it: + + + + + +```go +package mysmartcontract + +import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib" + + +func funcInit(ctx wasmlib.ScFuncContext, f *InitContext) { + if f.Params.Owner().Exists() { + f.State.Owner().SetValue(f.Params.Owner().Value()) + return + } + f.State.Owner().SetValue(ctx.RequestSender()) +} + +func funcSetOwner(ctx wasmlib.ScFuncContext, f *SetOwnerContext) { + f.State.Owner().SetValue(f.Params.Owner().Value()) +} + +func viewGetOwner(ctx wasmlib.ScViewContext, f *GetOwnerContext) { + f.Results.Owner().SetValue(f.State.Owner().Value()) +} +``` + + + + +```rust +use wasmlib::*; + +use crate::*; + +pub fn func_init(ctx: &ScFuncContext, f: &InitContext) { + if f.params.owner().exists() { + f.state.owner().set_value(&f.params.owner().value()); + return; + } + f.state.owner().set_value(&ctx.request_sender()); +} + +pub fn func_set_owner(_ctx: &ScFuncContext, f: &SetOwnerContext) { + f.state.owner().set_value(&f.params.owner().value()); +} + +pub fn view_get_owner(_ctx: &ScViewContext, f: &GetOwnerContext) { + f.results.owner().set_value(&f.state.owner().value()); +} +``` + + + + +```ts +import * as wasmlib from 'wasmlib'; +import * as wasmtypes from 'wasmlib/wasmtypes'; +import * as sc from './index'; + +export function funcInit(ctx: wasmlib.ScFuncContext, f: sc.InitContext): void { + if (f.params.owner().exists()) { + f.state.owner().setValue(f.params.owner().value()); + return; + } + f.state.owner().setValue(ctx.requestSender()); +} + +export function funcSetOwner( + ctx: wasmlib.ScFuncContext, + f: sc.SetOwnerContext, +): void { + f.state.owner().setValue(f.params.owner().value()); +} + +export function viewGetOwner( + ctx: wasmlib.ScViewContext, + f: sc.GetOwnerContext, +): void { + f.results.owner().setValue(f.state.owner().value()); +} +``` + + + + +The schema tool automatically generates an initial working version of the functions to maintain the smart contract owner, +catering to most use cases. + +To streamline the building process, configure a build rule in your environment. +This rule should trigger the schema tool with the necessary parameters +whenever there are changes in the schema definition file. +This setup ensures automatic file regeneration, +eliminating the need to run the schema tool manually after each modification. +The tool regenerates code only if it detects alterations since its last operation. +To override this and force regeneration, include the `-force` flag in the command line parameter. + +### Creating Smart Contracts using AssemblyScript + + diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/views.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/views.mdx new file mode 100644 index 00000000000..b9aef699f09 --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/views.mdx @@ -0,0 +1,133 @@ +--- +description: "Explore the characteristics and constraints of view-only functions in smart contracts, +illustrated through a 'getFactor' function example." +tags: +- View-Only Functions +- Smart Contracts +- Call Context +- Immutable Proxies +- Cross-Chain Requests +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Use View-Only Functions + +View-only functions, also known as "views", +are smart contract functions specialized in retrieving state information without altering the smart contract's state. + +## Characteristics + +### Immutable Proxies + +All state storage accesses occur through immutable proxies, ensuring the state remains unchanged. + +### Restricted Functionalities + +Views have a limited [Call Context](../../explanations/context.mdx), +disabling any function that might induce state changes, including token transactions. + +### Intra-chain Calls + +While they can [`call()`](call.mdx) other views within the same chain, +they cannot initiate non-view functions or [`post()`](post.mdx) cross-chain requests. + +### Return Data + +These functions are designed to return data to the caller, as they can't induce any other external effects. + +## Use Case: 'getFactor' Function + +To illustrate the use of view-only functions, consider the `getFactor()` function integrated in the `dividend` smart contract: + + + + + +```go + +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +func viewGetFactor(_ wasmlib.ScViewContext, f *GetFactorContext) { + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + var address wasmtypes.ScAddress = f.Params.Address().Value() + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + var members MapAddressToImmutableUint64 = f.State.Members() + + // Retrieve the factor associated with the address parameter. + var factor uint64 = members.GetUint64(address).Value() + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.Results.Factor().SetValue(factor) +} +``` + + + + +```rust +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +pub fn view_get_factor(_ctx: &ScViewContext, f: &GetFactorContext) { + + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + let address: ScAddress = f.params.address().value(); + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + let members: MapAddressToImmutableUint64 = f.state.members(); + + // Retrieve the factor associated with the address parameter. + let factor: u64 = members.get_uint64(&address).value(); + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.results.factor().set_value(factor); +} +``` + + + + +```ts +// 'getFactor' is a simple View function. It will retrieve the factor +// associated with the (mandatory) address parameter it was provided with. +export function viewGetFactor( + ctx: wasmlib.ScViewContext, + f: sc.GetFactorContext, +): void { + // Since we are sure that the 'address' parameter actually exists we can + // retrieve its actual value into an ScAddress value type. + let address: wasmlib.ScAddress = f.params.address().value(); + + // Create an ScImmutableMap proxy to the 'members' map in the state storage. + // Note that for views this is an *immutable* map as opposed to the *mutable* + // map we can access from the *mutable* state that gets passed to funcs. + let members: sc.MapAddressToImmutableUint64 = f.state.members(); + + // Retrieve the factor associated with the address parameter. + let factor: u64 = members.getUint64(address).value(); + + // Set the factor in the results map of the function context. + // The contents of this results map is returned to the caller of the function. + f.results.factor().setValue(factor); +} +``` + + + + +The return values are passed to the caller through the predefined [Results](results.mdx) map +associated with the [Call Context](../../explanations/context.mdx). +Again, this works the same as for Funcs, although Funcs do not necessarily return values to the caller. The +[Schema Tool](usage.mdx) will generate a function-specific [Results](results.mdx) +structure with type-safe proxies to the result fields in this map. diff --git a/docs/build/isc/v1.3/docs/schema/how-tos/yaml.mdx b/docs/build/isc/v1.3/docs/schema/how-tos/yaml.mdx new file mode 100644 index 00000000000..c812b5d6cea --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/how-tos/yaml.mdx @@ -0,0 +1,69 @@ +--- +tags: + - definition + - yaml + - smart contract creator + - one-time + - contract generation + - datatypes +description: the syntax of a schema definition file will be described here. +image: /img/logo/WASP_logo_dark.png +--- + +# YAML Schema Definition: Level 1 Attributes + +The schema definition file can have the following level 1 attributes: + +## name + +- **Type**: Single string +- **Usage**: Dictates the package name for the smart contract + +## description + +- **Type**: Single string +- **Usage**: Describes the smart contract's functionality (currently not utilized in the final smart contract) + +## events + +- **Type**: Map of strings +- **Usage**: Define structured events ([more info](./events.mdx)) +- **Restriction**: Field data types must be primitive; arrays, maps, or typedefs are not allowed + +## structs + +- **Type**: Map of string maps +- **Usage**: Declare structs for future development, usable in schema definitions +- **Restriction**: Fields must hold primitive types; arrays, maps, or typedef aliases are prohibited + +## typedefs + +- **Type**: Map of strings +- **Usage**: Create aliases for primitive values; supports primitive values, maps of primitive values, or arrays of primitive values +- **Restriction**: Nested typedefs are not permissible + +## state + +- **Type**: Map of strings +- **Usage**: Contains key/value pairs for use-case specific data ([details](../../explanations/states.md)) +- **Note**: To employ nested types, create a typedef alias for arrays or maps, but ensure map keys are primitive + +## funcs & views + +Describe functions and views sharing the same parameter and result names, ensuring they adhere to identical data types. The attributes common to both are: + +- **`access`** +- **Requirement**: Must be a state variable +- **Details**: Defines access permissions ([read more](./access.mdx#limiting-access)) + +- **`params`** +- **Type**: Can vary — array, map, or typedef alias +- **Usage**: Specifies input parameters + +- **`results`** +- **Type**: Can vary — array, map, or typedef alias +- **Usage**: Designates return values + +### Special Note on `funcs` + +- **Reserved Keyword**: `init` — relates to a distinct function ([explore](./init.mdx)) diff --git a/docs/build/isc/v1.3/docs/schema/introduction.mdx b/docs/build/isc/v1.3/docs/schema/introduction.mdx new file mode 100644 index 00000000000..de35b4c364a --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/introduction.mdx @@ -0,0 +1,62 @@ +# The Schema Tool + +Smart contracts need robustness, combining both flexibility and stringent regulation to prevent mistakes and foster efficiency. +Using the Schema Tool ensures consistency, and simplifies smart contract development. + +## Why Use the Schema Tool? + +### Ensure Robustness and Consistency + +By employing a code generator rooted in a schema definition file, you achieve: + +- **Reliability**: Through debugged, trustworthy generated code. +- **Adaptability**: Facilitating modifications in the smart contract interface. +- **Intent Reflection**: Enforcing defined smart contract behavior at compile-time. +- **Multilingual Support**: Accommodating various programming languages. + +### Prevent Repetitive Coding + +Initial experiences illustrated repetitive coding in: + +- `on_load` function setup and maintenance. +- Function access rights verification. +- Function parameter type and presence confirmation. +- Establishing access to State, Params, and Results maps. +- Common string constant definitions. + +The schema tool diminishes redundancy and ensures up-to-date functionalities. + +## The Schema Definition File + +### Defining a Clear Interface + +The schema definition file serves as a single source of truth, encompassing crucial details like: + +- State Storage Variables. +- [Funcs and Views](../../explanations/context). +- [Access rights](how-tos/access.mdx). +- [Input parameters](how-tos/params.mdx) and [output results](how-tos/results.mdx) . +- Additional Data Structures. + +### Automation with Schema Tool + +Using the [Schema Tool](how-tos/usage.mdx), the file facilitates: + +- **Skeleton Generation**: Crafting a smart contract framework that needs function implementations. +- **Interface Generation**: Creating interfaces to functions with stringent compile-time type-checking, thereby reducing errors. + +## Benefits of Schema Tool in Smart Contracts + +### Centralized Information + +Having all pertinent details in one place allows: + +- **Uniform Function Calls**: Through a generated interface used by client-side code. +- **Error Minimization**: Via compile-time type-checking. + +### Efficiency and Simplicity + +Knowledge of all essential aspects leads to: + +- **Constant Generation**: Avoiding typo-prone key strings repetition and precalculating essential values like `Hnames`. +- **Informative Code**: Generating code to correctly notify the host about available `Funcs` and `Views`. diff --git a/docs/build/isc/v1.3/docs/schema/proxies.mdx b/docs/build/isc/v1.3/docs/schema/proxies.mdx new file mode 100644 index 00000000000..0459da5c0bf --- /dev/null +++ b/docs/build/isc/v1.3/docs/schema/proxies.mdx @@ -0,0 +1,76 @@ +--- +tags: + - proxies + - sandbox + - wasm + - value proxies + - container proxies + - array proxies + - map proxies + - explanation +description: As there is no way for the Wasm code to access any memory outside its own memory space, the WasmLib interface provides a number of proxies to make accessing data within the ISC sandbox as seamless as possible. +image: /img/wasm_vm/Proxies.png +--- +# Data Access Proxies + +To interact seamlessly with the ISC sandbox's regulated environment and facilitate smart contract data access, +the WasmLib introduces data access proxies. +Proxies are objects that can perform the underlying data transfers between the +separate systems. + +## Overview + +The restrictive ISC sandbox environment requires an intermediary, or a library, to access sandbox functionalities — a role that the WasmLib fulfills through data access `proxies`. +These entities stand as bridges, enabling data transfers between segregated systems, providing a streamlined pathway to interact with smart contract data stored on the ISC host. + +## The Role of Proxies + +Proxies refer to actual objects or values housed in the ISC host, +essentially acting as data references that understand how to manipulate the data they represent. +At the core, data is secured in maps on the ISC host with byte strings serving as both keys and values. + +The WasmLib recognizes three predefined maps: + +- **[State Map](../schema/how-tos/state.mdx):** A repository for all state storage values. +- **[Params Map](../schema/how-tos/params.mdx):** Holds the parameter values of the current function call. +- **[Results Map](../schema/how-tos/results.mdx):** Returns the result values of the function call. + +Through these maps, a complex, +JSON-like data structure can be created with the aid of the [Schema Tool](../schema/how-tos/usage.mdx), +although, fundamentally, this structure is rooted in simple key-value access on the underlying map. + +## Proxy Varieties + +Proxies are segmented into various categories to facilitate different functionalities, including value proxies and container proxies. + +### Value Proxies + +Representing a single instance of a predetermined data type, +value proxies are basic entities facilitating type conversion of the byte string representing the stored value. + +The [Schema Tool](../schema/how-tos/usage.mdx) ensures type-safe code generation, always selecting the suitable proxy type. + +### Container Proxies + +Container proxies offer a virtual nesting system on the underlying map, +creating paths leading to value proxies housed in a virtual container. +They use JSON and YAML nesting patterns, and there are two primary types: + +#### 1. Map Proxies + +- **Root Maps:** Encase any element type but restrict keys to human-readable strings, which are defined in the schema definition file. +- **Virtual Maps:** Resides under a root map and accommodates values of a single associated data type. + +#### 2. Array Proxies + +- Operate as a specialized map where the key is an Int32 value, forming a sequence from 0 to N-1 for an array harboring N elements. + +## Proxies in Action + +![Proxies in WasmLib](/img/wasm_vm/Proxies.png) + +In the illustration, we see the key-value combinations (Key 1 to Key 4) in the ISC state storage map. Key 4 directs us to an array containing indexed values ranging from 0 to N. + +Notice the precise reflection of these elements in the WasmLib proxies, +which maintain a container proxy for every container and a value proxy for each stored value. +However, it is not obligatory for a smart contract function to define a proxy for every value or container in the ISC state storage. diff --git a/docs/build/isc/v1.3/docs/solo/getting-started.md b/docs/build/isc/v1.3/docs/solo/getting-started.md new file mode 100644 index 00000000000..6fe73a027ce --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/getting-started.md @@ -0,0 +1,80 @@ +--- +description: 'Solo is a testing framework that allows developers to validate real smart contracts and entire inter-chain +protocols.' +image: /img/logo/WASP_logo_dark.png +tags: + +- testing framework +- golang +- rust +- inter-chain protocols +- validate smart contracts +- install +- how-tos +--- + +# Testing Smart Contracts with Solo + +## What is Solo? + +[_Solo_](https://github.com/iotaledger/wasp/tree/develop/packages/solo) is a testing framework that allows developers to +validate real smart contracts and entire inter-chain protocols before deploying them on the distributed network. + +## Installation + +### Prerequisites + +[Go (version 1.20)](https://tip.golang.org/doc/go1.20). As _Solo_ tests are written in Go, you must +[install Go](https://go.dev/doc/install). + +### Access the Solo Framework + +You can access the Solo package by cloning the [Wasp repository](#clone-the-wasp-repository) +or [installing the Solo package](#install-the-solo-package). + +#### Clone the Wasp Repository + +_Solo_ is part of the [_Wasp_ codebase repository](https://github.com/iotaledger/wasp.git). You can access the Solo +framework by cloning the repository with the following command: + +```shell +git clone https://github.com/iotaledger/wasp.git +``` + +After you have cloned the repository, you can access the Solo package in the `/packages/solo` folder. + +#### Install the Solo Package + +You can install the Solo package separately using the following command: + +```shell +go get github.com/iotaledger/wasp/packages/solo +``` + +:::tip Go Docs + +You can browse the Solo Go API reference (updated to the `master` branch) in +[go-docs](https://pkg.go.dev/github.com/iotaledger/wasp/packages/solo). + +::: + +### Example Contracts + +You will need a smart contract to test along with Solo. +You can find example implementations of Wasm smart contracts, including source code and tests, in the Wasp +repository’s [contracts/wasm folder](https://github.com/iotaledger/wasp/tree/develop/contracts/wasm). + +The following sections will present some Solo usage examples. You can find the example code in +the [Wasp repository](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples). + +### Run `*_test` Files + +You can run `*_test` files by moving to their directory and running the following command: + +```shell +go test +``` + +If you run this command from the `/documentation/tutorial-examples` folder, you will run the +[Tutorial Test](https://github.com/iotaledger/wasp/blob/develop/documentation/tutorial-examples/test/tutorial_test.go), +which contains all the examples explained in the following sections. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/deploying-sc.md b/docs/build/isc/v1.3/docs/solo/how-tos/deploying-sc.md new file mode 100644 index 00000000000..387e4d18235 --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/deploying-sc.md @@ -0,0 +1,70 @@ +--- +description: Deploying Wasm smart contracts with Solo. +image: /img/tutorial/send_request.png +tags: + - testing + - PostRequestSync + - PostRequestOffLedger + - send + - requests + - post + - solo + - on-ledger + - off-ledger + - how-tos +--- + +# Deploying Wasm Smart Contracts + +:::note WASM VM + +For more information about how to create Wasm smart contracts, refer to the [Wasm VM chapter](../../getting-started/languages-and-vms.md#wasm-vm-for-isc). + +::: + +## Deploy the Solo Tutorial + +The following examples will make use of the +[`solotutorial` Rust/Wasm smart contract](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples). + +In order to test the smart contract using Solo, first you need to deploy it. You can use the following code to +deploy `solotutorial_bg.wasm`: + +```go +func TestTutorialDeploySC(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) +} +``` + +This will work as long as the `solotutorial_bg.wasm` file is in the same directory as the Go test code. + +### Create a Default Wallet and Chain + +You can use the `NewChain()` function to create a new wallet and deploys a new chain using said wallet, and other +default parameters. You can access the wallet calling `chain.OriginatorPrivateKey`. + +### DeployWasmContract Parameters + +#### Deployer's Key Pair + +The first parameter to `DeployWasmContract` is the key pair of the deployer of the smart contract. You can pass `nil` +to use a default wallet, which can be accessed as `chain.OriginatorPrivateKey`. + +#### Smart Contract Name + +The second parameter to `DeployWasmContract` (`"solotutorial"`), is the name assigned to the smart contract instance. +Smart contract instance names must be unique across each chain. + +### AutoAdjustStorageDeposit + +In the example above we enabled the `AutoAdjustStorageDeposit` option. +This is necessary in order to automatically adjust all sent L1 transactions to include the storage deposit if +necessary (provided that the sender owns the funds). + +It is possible to disable the option and have manual control of the storage deposit, but in that case the deployment +of the smart contract will have to be done "by hand". + +In most cases it is recommended to leave it enabled. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/error-handling.md b/docs/build/isc/v1.3/docs/solo/how-tos/error-handling.md new file mode 100644 index 00000000000..40b414feedc --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/error-handling.md @@ -0,0 +1,51 @@ +--- +description: What happens when a smart contract invocation fails? +image: /img/logo/WASP_logo_dark.png +tags: + - testing + - solo + - error handling + - panic + - state + - transition +--- + +# Error Handling + +The following test posts a request to the `solotutorial` smart contract without the expected parameter `"str"`, causing +the smart contract call to panic: + +```go +func TestTutorialInvokeSCError(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) + + // missing the required parameter "str" + req := solo.NewCallParams("solotutorial", "storeString"). + WithMaxAffordableGasBudget() + + _, err = chain.PostRequestSync(req, nil) + require.Error(t, err) + require.True(t, err.Error() == "WASM: panic in VM: missing mandatory string") +} +``` + +The `_, err = chain.PostRequestSync(req, nil)` will return an error containing `WASM: panic in VM: missing mandatory string`. + +This shows that the request resulted in a panic. +The Solo test passes because of the `require.Error(t, err)` line. + +Note that this test still ends with the state `#4`, although the last request to the smart contract failed: + +```log +20:09.974258867 INFO TestTutorialInvokeSCError.ch1 solo/run.go:156 state transition --> #4. Requests in the block: 1. Outputs: 1 +``` + +This shows that a chain block is always generated, regardless of whether the smart contract call succeeds or not. The +result of the request is stored in the chain's [`blocklog`](../../reference/core-contracts/blocklog.md) in the form of +a receipt. In fact, the received Go error `err` in the test above is just generated from the request receipt. + +If a panic occurs during a smart contract call, it is recovered by the VM context, and the request is marked as failed. +Any state changes made prior to the panic are rolled back. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/examples.mdx b/docs/build/isc/v1.3/docs/solo/how-tos/examples.mdx new file mode 100644 index 00000000000..c924b0b67fe --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/examples.mdx @@ -0,0 +1,282 @@ +--- +tags: + - solo + - testing + - errors + - member function + - post + - ctx + - divide function + - error message + +description: Use the SoloContext to create full-blown tests for the dividend example smart contract. + +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Example Tests + +In the previous sections we showed how you can [`call()`](../../schema/how-tos/call.mdx) or +[`post()`](../../schema/how-tos/post.mdx) smart contract function requests. We also created a few wrapper +functions to simplify calling these functions even further. Now we will look at how to use +the SoloContext to create full-blown tests for the `dividend` example smart contract. + +Let's start with a simple test. We are going to use the `member` function to add a valid +new member/factor combination to the member group. + + + + + +```go +func TestAddMemberOk(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + dividendMember(ctx, member1, 100) + require.NoError(t, ctx.Err) +} +``` + + + + +The above test first deploys the `dividend` smart contract to a new chain, and returns a +SoloContext `ctx`. Then it uses `ctx` to create a new SoloAgent `member1`. When creating a +SoloAgent a new _Tangle_ address is created for that agent and its on-chain account is +pre-seeded with 10M base tokens so that it is ready to be used in tests. The SoloAgent can +be used whenever an address or agent ID needs to be provided, it can be used to sign a +request to identify it as the sender, and it can be used to inspect the asset balances on +its Tangle address and its on-chain account. + +In this case, we simply create `member1`, and pass it to the dividend contract's `member` +function, which will receive the address of `member1` and a dispersal factor of 100. +Finally, we check if ctx has received an error during the execution of the call. Remember +that the only way to pass an error from a WasmLib function call is through a `panic()` +call. The code that handles the actual call will intercept any `panic()` that was raised, +and return an error. The SoloContext saves this error for later inspection, because the +function descriptor used in the call itself has no way of passing back this error. + +The next two example tests each call the contract's `member` function in the exact same +way, but in both cases one required parameter is omitted. The idea is to test that the +function properly panics by checking the ctx.Err value is not nil after the call. Finally, +the error message text is checked to see if it contains the expected error message. + + + + + +```go +func TestAddMemberFailMissingAddress(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member := dividend.ScFuncs.Member(ctx) + member.Params.Factor().SetValue(100) + member.Func.Post() + require.Error(t, ctx.Err) + require.Contains(t, ctx.Err.Error(), "missing mandatory address") +} + +func TestAddMemberFailMissingFactor(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + member := dividend.ScFuncs.Member(ctx) + member.Params.Address().SetValue(member1.ScAgentID().Address()) + member.Func.Post() + require.Error(t, ctx.Err) + require.Contains(t, ctx.Err.Error(), "missing mandatory factor") +} +``` + + + + +Each test has to set up the chain/contract/context from scratch. We will often use a +specific setupTest() function to do all setup work that is shared by many tests. + +We cannot use the `dividendMember` wrapper function in these two tests because of the +missing required function parameters. So we have simply copy/pasted the code, and removed +the `Params` proxy initialization lines that we wanted to be detected as missing. + +Now let's see a more complex example: + + + + + +```go +func TestDivide1Member(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + bal := ctx.Balances(member1) + + dividendMember(ctx, member1, 100) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + const dividendToDivide = 1*isc.Million + 1 + dividendDivide(ctx, dividendToDivide) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator -= ctx.GasFee + bal.Add(member1, dividendToDivide) + bal.VerifyBalances(t) +} +``` + + + + +The first half of the code is almost identical to our first test above. We set up the +test, create an agent, set the factor for that agent to 100, and verify that no error +occurred. Notice how we additionally call `ctx.Balances()` to make a snapshot of all the +original asset balances including those of the agent. + +Then in the next lines we update the asset balances with the changes we expect to happen +because of the call to the `member` function. And then we verify these changes against the +actual asset balances by calling `bal.VerifyBalances(t)`. + +Next we transfer 1M + 1 tokens as part of the post request to the `divide` function. We +subsequently check that no error has occurred. Finally, we again modify the asset balances +to reflect the expected changes and verify these changes against the actual asset +balances. + +Now let's skip to the most complex test of all: + + + + + +```go + func TestDivide3Members(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + bal := ctx.Balances(member1) + + dividendMember(ctx, member1, 25) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + member2 := ctx.NewSoloAgent("member2") + bal = ctx.Balances(member1, member2) + + dividendMember(ctx, member2, 50) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + member3 := ctx.NewSoloAgent() + bal = ctx.Balances(member1, member2, member3) + + dividendMember(ctx, member3, 75) + require.NoError(t, ctx.Err) + + bal.Chain += ctx.GasFee + bal.Originator += ctx.StorageDeposit - ctx.GasFee + bal.VerifyBalances(t) + + const dividendToDivide = 2*isc.Million - 1 + dividendDivide(ctx, dividendToDivide) + require.NoError(t, ctx.Err) + + remain := dividendToDivide - dividendToDivide*25/150 - dividendToDivide*50/150 - dividendToDivide*75/150 + bal.Chain += ctx.GasFee + bal.Originator += remain - ctx.GasFee + bal.Add(member1, dividendToDivide*25/150) + bal.Add(member2, dividendToDivide*50/150) + bal.Add(member3, dividendToDivide*75/150) + bal.VerifyBalances(t) + + const dividendToDivide2 = 2*isc.Million + 234 + dividendDivide(ctx, dividendToDivide2) + require.NoError(t, ctx.Err) + + remain = dividendToDivide2 - dividendToDivide2*25/150 - dividendToDivide2*50/150 - dividendToDivide2*75/150 + bal.Chain += ctx.GasFee + bal.Originator += remain - ctx.GasFee + bal.Add(member1, dividendToDivide2*25/150) + bal.Add(member2, dividendToDivide2*50/150) + bal.Add(member3, dividendToDivide2*75/150) + bal.VerifyBalances(t) +} +``` + + + + +This function creates 3 agents, and associates factors of 25, 50, and 75 respectively to +them. That required 3 `member` requests, and we verify the expected balance changes after +each request. Next the `divide` function is called, with 2M-1 tokens passed to it. + +After this we verify that each agent has been distributed tokens according to its relative +factor. Those factors are 25/150th, 50/150th, and 75/150th, respectively. Note that we +cannot transfer fractional tokens, so we truncate to the nearest integer and ultimately +any remaining tokens are not transferred, but remain in the sender's account. + +Finally, we call `divide` again with 2M+234 tokens and again verify the asset balances +afterwards. + +Next we will show how to test [Views](../../schema/how-tos/views.mdx) and/or [Funcs](../../schema/how-tos/funcs.mdx) that return +a result. Note that even though Funcs are usually invoked through a [`post()`](../../schema/how-tos/post.mdx) +request, in which case any return values are inaccessible, they still can be invoked +through a [call()](../../schema/how-tos/call.mdx) from within another Func, in which these return values can +be used normally. Since solo executes [`post()`](../../schema/how-tos/post.mdx) requests synchronously, it is +possible to have a Func return a result and test for certain result values. + + + + + +```go +func TestGetFactor(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + + member1 := ctx.NewSoloAgent("member1") + dividendMember(ctx, member1, 25) + require.NoError(t, ctx.Err) + + member2 := ctx.NewSoloAgent("member2") + dividendMember(ctx, member2, 50) + require.NoError(t, ctx.Err) + + member3 := ctx.NewSoloAgent() + dividendMember(ctx, member3, 75) + require.NoError(t, ctx.Err) + + value := dividendGetFactor(ctx, member3) + require.NoError(t, ctx.Err) + require.EqualValues(t, 75, value) + + value = dividendGetFactor(ctx, member2) + require.NoError(t, ctx.Err) + require.EqualValues(t, 50, value) + + value = dividendGetFactor(ctx, member1) + require.NoError(t, ctx.Err) + require.EqualValues(t, 25, value) +} +``` + + + + +Here we first set up the same 3 dispersion factors, and then we retrieve the dispersion +factors for each member in reverse order and verify their values. + +In the [next section](timelock.mdx) we will describe a few more helper member functions +of the SoloContext. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/first-example.md b/docs/build/isc/v1.3/docs/solo/how-tos/first-example.md new file mode 100644 index 00000000000..f4189cee840 --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/first-example.md @@ -0,0 +1,94 @@ +--- +description: Example of a _Solo_ test. It deploys a new chain and invokes some view calls. +image: /img/logo/WASP_logo_dark.png +tags: + - testing framework + - golang + - solo + - example + - new chain + - how-tos +--- + +# First Example + +The following is an example of a _Solo_ test. It deploys a new chain and invokes some view calls in the +[`root`](../../reference/core-contracts/root.md) and [`governance`](../../reference/core-contracts/governance.md) +[core contracts](../../reference/core-contracts/overview.md). + +```go +import ( + "testing" + + "github.com/iotaledger/wasp/packages/solo" + "github.com/iotaledger/wasp/packages/vm/core/corecontracts" + "github.com/stretchr/testify/require" +) + +func TestTutorialFirst(t *testing.T) { + env := solo.New(t) + chain := env.NewChain() + + // calls views governance::ViewGetChainInfo and root:: ViewGetContractRecords + chainID, chainOwnerID, coreContracts := chain.GetInfo() + // assert that all core contracts are deployed + require.EqualValues(t, len(corecontracts.All), len(coreContracts)) + + t.Logf("chain ID: %s", chainID.String()) + t.Logf("chain owner ID: %s", chainOwnerID.String()) + for hname, rec := range coreContracts { + t.Logf(" Core contract %q: %s", rec.Name, hname) + } +} +``` + +The output of the test will be something like this: + +```log +=== RUN TestTutorialFirst +29:43.383770108 INFO TestTutorialFirst.db dbmanager/dbmanager.go:64 creating new in-memory database for: CHAIN_REGISTRY +29:43.383957435 INFO TestTutorialFirst solo/solo.go:162 Solo environment has been created: logical time: 00:01.001000000, time step: 1ms +29:43.384671943 INFO TestTutorialFirst solo/solo.go:236 deploying new chain 'tutorial1'. ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd, state controller address: tgl1qpk70349ftcpvlt6lnn0437p63wt7w2ejvlkw93wkkt0kc39f2wpvuv73ea +29:43.384686865 INFO TestTutorialFirst solo/solo.go:238 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. state controller address: tgl1qpk70349ftcpvlt6lnn0437p63wt7w2ejvlkw93wkkt0kc39f2wpvuv73ea +29:43.384698704 INFO TestTutorialFirst solo/solo.go:239 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. originator address: tgl1qq93jh7dsxq3lznajgtq33v26rt0pz0rs0rwar4jahahp6h2hh9jy4nc52k +29:43.384709967 INFO TestTutorialFirst.db dbmanager/dbmanager.go:64 creating new in-memory database for: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd +29:43.384771911 INFO TestTutorialFirst solo/solo.go:244 chain 'tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd'. origin state commitment: c4f09061cd63ea506f89b7cbb3c6e0984f124158 +29:43.417023624 INFO TestTutorialFirst solo/solo.go:171 solo publisher: state [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 1 1 0-6c7ff6bc5aaa3af12f9b6b7c43dcf557175ac251418df562f7ec4ff092e84d4f 0000000000000000000000000000000000000000000000000000000000000000] +29:43.417050354 INFO TestTutorialFirst solo/solo.go:171 solo publisher: request_out [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 0-11232aa47639429b83faf79547c6bf615bd65aa461f243c89e4073b792ac89b7 1 1] +29:43.417056290 INFO TestTutorialFirst.tutorial1 solo/run.go:156 state transition --> #1. Requests in the block: 1. Outputs: 1 +29:43.417179099 INFO TestTutorialFirst.tutorial1 solo/run.go:176 REQ: 'tx/0-11232aa47639429b83faf79547c6bf615bd65aa461f243c89e4073b792ac89b7' +29:43.417196814 INFO TestTutorialFirst.tutorial1 solo/solo.go:301 chain 'tutorial1' deployed. Chain ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd + tutorial_test.go:20: chain ID: tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd + tutorial_test.go:21: chain owner ID: tgl1qq93jh7dsxq3lznajgtq33v26rt0pz0rs0rwar4jahahp6h2hh9jy4nc52k + tutorial_test.go:23: Core contract "blob": fd91bc63 + tutorial_test.go:23: Core contract "governance": 17cf909f + tutorial_test.go:23: Core contract "errors": 8f3a8bb3 + tutorial_test.go:23: Core contract "evm": 07cb02c1 + tutorial_test.go:23: Core contract "accounts": 3c4b5e02 + tutorial_test.go:23: Core contract "root": cebf5908 + tutorial_test.go:23: Core contract "blocklog": f538ef2b +--- PASS: TestTutorialFirst (0.03s) +``` + +:::note + +- The example uses [`stretchr/testify`](https://github.com/stretchr/testify) for assertions, but it is not strictly + required. +- Addresses, chain IDs and other hashes should be the same on each run of the test because Solo uses a constant seed by + default. +- The timestamps shown in the log come from the computer's timer, but the Solo environment operates on its own logical + time. + +::: + +The [core contracts](../../reference/core-contracts/overview.md) listed in the log are automatically deployed on each +new chain. The log also shows their _contract IDs_. + +The output fragment in the log `state transition --> #1` means that the state of the chain has changed from block index +0 (the origin index of the empty state) to block index 1. State #0 is the empty origin state, and #1 always contains all +core smart contracts deployed on the chain, as well as other data internal to the chain itself, such as the _chainID_ +and the _chain owner ID_. + +The _chain ID_ and _chain owner ID_ are, respectively, the ID of the deployed chain, and the address of the L1 account +that triggered the deployment of the chain (which is automatically generated by Solo in our example, but it can be +overridden when calling `env.NewChain`). diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/invoking-sc.md b/docs/build/isc/v1.3/docs/solo/how-tos/invoking-sc.md new file mode 100644 index 00000000000..ec60f2d2cbe --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/invoking-sc.md @@ -0,0 +1,116 @@ +--- +description: Invoking smart contracts with on-ledger and off-ledger requests with Solo. +image: /img/tutorial/send_request.png +tags: + - how-to + - explanation + - testing + - PostRequestSync + - PostRequestOffLedger + - send + - requests + - post + - solo + - on-ledger + - off-ledger +--- + +# Invoking Smart Contracts + +After deploying +the [`solotutorial`](https://github.com/iotaledger/wasp/tree/develop/documentation/tutorial-examples) +smart contract, you can invoke the `storeString` function: + +```go +func TestTutorialInvokeSC(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + err := chain.DeployWasmContract(nil, "solotutorial", "solotutorial_bg.wasm") + require.NoError(t, err) + + // invoke the `storeString` function + req := solo.NewCallParams("solotutorial", "storeString", "str", "Hello, world!"). + WithMaxAffordableGasBudget() + _, err = chain.PostRequestSync(req, nil) + require.NoError(t, err) + + // invoke the `getString` view + res, err := chain.CallView("solotutorial", "getString") + require.NoError(t, err) + require.Equal(t, "Hello, world!", codec.MustDecodeString(res.MustGet("str"))) +} +``` + +## Parameters + +### `NewCallParams()` + +The above example uses `NewCallParams` to set up the parameters of the request that it will send to the contract. +It specifies that it wants to invoke the `storeString` entry point of the `solotutorial` smart contract, passing the +parameter named `str` with the string value `"Hello, world!"`. + +### `WithMaxAffordableGasBudget()` + +`WithMaxAffordableGasBudget()` assigns the gas budget of the request to the maximum that the sender can afford with the +funds they own on L2 (including any funds attached in the request itself). +In this case the funds attached automatically for the storage deposit will be enough to cover for the gas fee, so it is +not necessary to manually deposit more funds for gas. + +## `PostRequestSync()` + +`PostRequestSync` sends an on-ledger request to the chain. + +## On-Ledger Requests + +[![Generic process of posting an on-ledger request to the smart contract](/img/tutorial/send_request.png)](/img/tutorial/send_request.png) + +The diagram above depicts the generic process of posting an _on-ledger_ request to the smart contract. +The same diagram is valid for the Solo environment and any other requester that sends an on-ledger request, e.g., the +IOTA Smart Contracts wallet or another chain. + +Posting an on-ledger request always consists of the steps below. +Note that in Solo, all seven steps are carried out by a single call to `PostRequestSync`. + +1. Create the L1 transaction, which wraps the L2 request and moves tokens. + + Each on-ledger request must be contained in a transaction on the ledger. + Therefore, it must be signed by the sender’s private key. + This securely identifies each requester in IOTA Smart Contracts. + In Solo, the transaction is signed by the private key provided in the second parameter of the `PostRequestSync` call + (`chain.OriginatorPrivateKey()` by default). + +2. Post and confirm the transaction to the L1 ledger. + + In Solo, it is just adding the transaction to the emulated L1 ledger, so it is confirmed immediately and + synchronously. + The confirmed transaction on the ledger becomes part of the backlog of requests to be processed by the chain. + In the real L1 ledger, the sender must wait until the ledger confirms the transaction. + +3. The chain picks the request from the backlog and runs the request on the VM. +4. The _VM_ calls the target entry point of the smart contract program. The program updates the state. +5. The VM produces a state update transaction (the _anchor_). +6. The chain signs the transaction with its private key (the `chain.StateControllerKeyPair()` in Solo). +7. The chain posts the resulting transaction to the L1 ledger and, after confirmation, commits the corresponding state. + +The following lines in the test log correspond to step 7: + +```log +49:37.771863573 INFO TestTutorialInvokeSC solo/solo.go:171 solo publisher: state [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 4 1 0-177c8a62feb7d434608215a179dd6637b8038d1237dd264 +d8feaf4d9a851b808 0000000000000000000000000000000000000000000000000000000000000000] +49:37.771878833 INFO TestTutorialInvokeSC solo/solo.go:171 solo publisher: request_out [tgl1pzehtgythywhnhnz26s2vtpe2wy4y64pfcwkp9qvzhpwghzxhwkps2tk0nd 0-c55b41b07687c644b7f7a1b9fb5da86f2d40195f39885 +bc348767e2dd285ca15 4 1] +49:37.771884127 INFO TestTutorialInvokeSC.ch1 solo/run.go:156 state transition --> #4. Requests in the block: 1. Outputs: 1 +``` + +## Off-ledger Requests + +Alternatively, you could send an off-ledger request by using `chain.PostRequestOffLedger` instead of `PostRequestSync`. +However, since off-ledger requests cannot have tokens attached, in order to cover the gas fee, you must deposit funds to +the chain beforehand: + +```go +user, _ := env.NewKeyPairWithFunds(env.NewSeedFromIndex(1)) +chain.DepositBaseTokensToL2(10_000, user) // to cover gas fees +_, err = chain.PostRequestOffLedger(req, user) +require.NoError(t, err) +``` diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/test.mdx b/docs/build/isc/v1.3/docs/solo/how-tos/test.mdx new file mode 100644 index 00000000000..aedbaab2e19 --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/test.mdx @@ -0,0 +1,123 @@ +--- +tags: + - testing + - solo testing environment + - call context + - smart contract functionalities + - data types + - type conversions + - Go + +description: Testing of smart contracts happens in the Solo testing environment. This enables synchronous, deterministic testing of smart contract functionality without the overhead of having to start nodes, set up a committee, and send transactions over the _Tangle_. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Testing Smart Contracts + +Testing of smart contracts happens in the [Solo](../getting-started.md) testing +environment. This enables synchronous, deterministic testing of smart contract +functionalities without the overhead of having to start nodes, set up a committee, and +send transactions over the _Tangle_. Instead, you can use Go's built-in test environment in +combination with Solo to deploy chains and smart contracts and simulate transactions. + +Solo directly interacts with the ISC code, and therfore uses all the ISC-specific data +types directly. Our Wasm smart contracts cannot access these types directly, because they +run in a separate, sandboxed environment. Therefore, WasmLib implements its +[own versions](../../reference/wasm-lib-data-types.mdx) of these data types, and the _VM_ layer acts as a data type +translator between both systems. + +The impact of this type transformation used to be that to be able to write tests in the +solo environment the user also needed to know about the ISC-specific data types and type +conversion functions, and exactly how to properly pass such data in and out of smart +contract function calls. This burdened the user with an unnecessary increased learning +curve and countless unnecessary type conversions. + +With the introduction of the [Schema Tool](../../schema/how-tos/usage.mdx), we were able to remove this +impedance mismatch and allow the users to test smart contract functionality in terms of +the WasmLib data types and functions that they are already familiar with. To that end, we +introduced `SoloContext`, a new [Call Context](../../explanations/context.mdx) that specifically works with +the Solo testing environment. We aimed to simplify the testing of smart contracts as much +as possible, keeping the full Solo interface hidden as much as possible, but still +available when necessary. + +The only concession we still have to make is to the language used. Because Solo only works +in the Go language environment, we have to use the Go language version of the interface +code that the [Schema Tool](../../schema/how-tos/usage.mdx) generates when testing our smart contracts. Because +WasmLib programming for Go, Rust, and TypeScript are practically identical, we feel that +this is not unsurmountable. The WasmLib interfaces only differ slightly if language +idiosyncrasies force differences in syntax or naming conventions. This hurdle used to be a +lot bigger, when direct programming of Solo had to be used, and most type conversions had +to be done manually. Now we get to use the generated compile-time type-checked interface +to our smart contract functions that we are already familiar with. + +Let's look at the simplest way of initializing a smart contract by using the new +`SoloContext` in a test function: + + + + + +```go +func TestDeploy(t *testing.T) { + ctx := wasmsolo.NewSoloContext(t, dividend.ScName, dividend.OnDispatch) + require.NoError(t, ctx.ContractExists(dividend.ScName)) +} +``` + + + + +The first line will automatically create a new chain, and upload and deploy the provided +example `dividend` contract to this chain. It returns a `SoloContext` for further use. The +second line verifies the existence of the deployed contract on the chain associated with +that [Call Context](../../explanations/context.mdx). + +Here is another part of the `dividend` test code, where you can see how we wrap repetitive +calls to smart contract functions that are used in multiple tests: + + + + + +```go +func dividendMember(ctx *wasmsolo.SoloContext, agent *wasmsolo.SoloAgent, factor uint64) { + member := dividend.ScFuncs.Member(ctx) + member.Params.Address().SetValue(agent.ScAgentID().Address()) + member.Params.Factor().SetValue(factor) + member.Func.Post() +} + +func dividendDivide(ctx *wasmsolo.SoloContext, amount uint64) { + divide := dividend.ScFuncs.Divide(ctx) + divide.Func.TransferBaseTokens(amount).Post() +} + +func dividendGetFactor(ctx *wasmsolo.SoloContext, member *wasmsolo.SoloAgent) uint64 { + getFactor := dividend.ScFuncs.GetFactor(ctx) + getFactor.Params.Address().SetValue(member.ScAgentID().Address()) + getFactor.Func.Call() + value := getFactor.Results.Factor().Value() + return value +} +``` + + + + +As you can see, we pass the `SoloContext` and the parameters to the wrapper functions, +then use the `SoloContext` to create a [Function Descriptor](../../schema/how-tos/funcdesc.mdx) for the wrapped +function, pass any parameters through the [Params](../../schema/how-tos/params.mdx) proxy, and then either +[`post()`](../../schema/how-tos/post.mdx) the function request or [`call`](../../schema/how-tos/call.mdx) the function. Any +results returned are extracted through the descriptor's [Results](../../schema/how-tos/results.mdx) proxy, and +returned by the wrapper function. + +There is hardly any difference in the way the function interface is used within Wasm code +or within Solo test code. The [Call Context](../../explanations/context.mdx) knows how to properly +[`call()`](../../schema/how-tos/call.mdx) or [`post()`](../../schema/how-tos/post.mdx) the function call through the function +descriptor. This makes for seamless testing of smart contracts. + +In the [next section](examples.mdx) we will go deeper into how the helper member functions +of the SoloContext are used to simplify tests. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/the-l1-ledger.md b/docs/build/isc/v1.3/docs/solo/how-tos/the-l1-ledger.md new file mode 100644 index 00000000000..ed3c5b84c53 --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/the-l1-ledger.md @@ -0,0 +1,71 @@ +--- +description: How to interact with the L1 ledger in Solo. +image: /img/logo/WASP_logo_dark.png +tags: + - testing + - solo + - UTXO + - tokens + - ledger + - l1 + - how-tos +--- + +# The L1 Ledger + +IOTA Smart Contracts work as a **layer 2** (**L2**) extension of the _IOTA Multi-Asset Ledger_, **layer 1** (**L1**). +The specifics of the ledger is outside the scope of this documentation; for now it is sufficient to know that the ledger +contains balances of different kinds of assets (base tokens, native tokens, foundries and _NFT_s) locked in addresses. +Assets can only be moved on the ledger by unlocking the corresponding address with its private key. + +For example: + +```log +Address: iota1pr7vescn4nqc9lpvv37unzryqc43vw5wuf2zx8tlq2wud0369hjjugg54mf + IOTA: 4012720 + Native token 0x08fcccc313acc182fc2c647dc98864062b163a8ee254231d7f029dc6be3a2de52e0100000000: 100 + NFT 0x94cd51b79d9608ed6e38780d48e9fc8c295b893077739b28ce591c45b33dec44 +``` + +In this example, the address owns some base tokens (IOTA), 100 units of a native token with ID `0x08fc...`, and an NFT +with ID `0x94cd...`. + +You can find more information about the ledger in the +[Multi-Asset Ledger TIP](https://github.com/lzpap/tips/blob/master/tips/TIP-0018/tip-0018.md). + +In normal operation, the L2 state is maintained by a committee of Wasp _nodes_. The L1 ledger is provided and +maintained by a network of [Hornet](https://github.com/iotaledger/hornet) nodes, which is a distributed implementation +of the IOTA Multi-Asset Ledger. + +The Solo environment implements a standalone in-memory ledger, simulating the behavior of a real L1 ledger without the +need to run a network of Hornet nodes. + +The following example creates a new wallet (private/public key pair) and requests some base tokens from the faucet: + +```go +func TestTutorialL1(t *testing.T) { + env := solo.New(t) + _, userAddress := env.NewKeyPairWithFunds(env.NewSeedFromIndex(1)) + t.Logf("address of the user is: %s", userAddress.Bech32(parameters.L1.Protocol.Bech32HRP)) + numBaseTokens := env.L1BaseTokens(userAddress) + t.Logf("balance of the user is: %d base tokens", numBaseTokens) + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount) +} +``` + +The _output_ of the test is: + +```log +=== RUN TestTutorialL1 +47:49.136622566 INFO TestTutorialL1.db dbmanager/dbmanager.go:64 creating new in-memory database for: CHAIN_REGISTRY +47:49.136781104 INFO TestTutorialL1 solo/solo.go:162 Solo environment has been created: logical time: 00:01.001000000, time step: 1ms + tutorial_test.go:32: address of the user is: tgl1qp5d8zm9rr9rcae2hq95plx0rquy5gu2mpedurm2kze238neuhh5csjngz0 + tutorial_test.go:34: balance of the user is: 1000000000 base tokens +--- PASS: TestTutorialL1 (0.00s) +``` + +The L1 ledger in Solo can be accessed via the Solo instance called `env`. +The ledger is unique for the lifetime of the Solo environment. +Even if several L2 chains are deployed during the test, all of them will live on the same L1 ledger; this way Solo makes +it possible to test cross-chain transactions. +(Note that in the test above we did not deploy any chains: the L1 ledger exists independently of any chains.) diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/the-l2-ledger.md b/docs/build/isc/v1.3/docs/solo/how-tos/the-l2-ledger.md new file mode 100644 index 00000000000..ed737dbeaed --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/the-l2-ledger.md @@ -0,0 +1,176 @@ +--- +description: 'Smart contracts can exchange assets between themselves on the same chain and between different chains, as +well as with addresses on the L1 ledger.' +image: /img/logo/WASP_logo_dark.png +tags: + +- testing +- solo +- account +- address +- wallet +- balances +- ledger + +--- + +# The L2 Ledger + +Each chain in IOTA Smart Contracts contains its own L2 ledger, independent of the L1 ledger. +Smart contracts can exchange assets between themselves on the same chain, between different chains, and with addresses +on the L1 Ledger. + +Imagine that you have a wallet with some tokens on the L1 ledger, and you want to send those tokens to a smart contract +on a chain and later receive these tokens back on L1. + +On the L1 ledger, your wallet's private key is represented by an address, which holds some tokens. +Those tokens are _controlled_ by the private key. + +In IOTA Smart Contracts the L2 ledger is a collection of _on-chain accounts_ (sometimes also called just _accounts_). +Each L2 account is controlled by the same private key as its associated address and can hold tokens on the chain's +ledger, just like an address can hold tokens on L1. +This way, the chain is essentially a custodian of the tokens deposited in its accounts. + +## Deposit and Withdraw Tokens + +The following test demonstrates how a wallet can deposit tokens in a chain +account and then withdraw them. + +Note that the math is made somewhat more complex by the gas fees and storage deposit. +You could ignore them, but we include them in the example to show you exactly how you can handle them. + +```go +func TestTutorialAccounts(t *testing.T) { + env := solo.New(t, &solo.InitOptions{AutoAdjustStorageDeposit: true}) + chain := env.NewChain() + + // create a wallet with some base tokens on L1: + userWallet, userAddress := env.NewKeyPairWithFunds(env.NewSeedFromIndex(0)) + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount) + + // the wallet can we identified on L2 by an AgentID: + userAgentID := isc.NewAgentID(userAddress) + // for now our on-chain account is empty: + chain.AssertL2BaseTokens(userAgentID, 0) + + // send 1 Mi from the L1 wallet to own account on-chain, controlled by the same wallet + req := solo.NewCallParams(accounts.Contract.Name, accounts.FuncDeposit.Name). + AddBaseTokens(1 * isc.Million) + + // estimate the gas fee and storage deposit + gas1, gasFee1, err := chain.EstimateGasOnLedger(req, userWallet, true) + require.NoError(t, err) + storageDeposit1 := chain.EstimateNeededStorageDeposit(req, userWallet) + require.Zero(t, storageDeposit1) // since 1 Mi is enough + + // send the deposit request + req.WithGasBudget(gas1). + AddBaseTokens(gasFee1) // including base tokens for gas fee + _, err = chain.PostRequestSync(req, userWallet) + require.NoError(t, err) + + // our L1 balance is 1 Mi + gas fee short + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-1*isc.Million-gasFee1) + // our L2 balance is 1 Mi + chain.AssertL2BaseTokens(userAgentID, 1*isc.Million) + // (the gas fee went to the chain's private account) + + // withdraw all base tokens back to L1 + req = solo.NewCallParams(accounts.Contract.Name, accounts.FuncWithdraw.Name). + WithAllowance(isc.NewAssetsBaseTokens(1 * isc.Million)) + + // estimate the gas fee and storage deposit + gas2, gasFee2, err := chain.EstimateGasOnLedger(req, userWallet, true) + require.NoError(t, err) + storageDeposit2 := chain.EstimateNeededStorageDeposit(req, userWallet) + + // send the withdraw request + req.WithGasBudget(gas2). + AddBaseTokens(gasFee2 + storageDeposit2). // including base tokens for gas fee and storage + AddAllowanceBaseTokens(storageDeposit2) // and withdrawing the storage as well + _, err = chain.PostRequestSync(req, userWallet) + require.NoError(t, err) + + // we are back to the initial situation, having been charged some gas fees + // in the process: + env.AssertL1BaseTokens(userAddress, utxodb.FundsFromFaucetAmount-gasFee1-gasFee2) + chain.AssertL2BaseTokens(userAgentID, 0) +} +``` + +The example above creates a chain and a wallet with `utxodb.FundsFromFaucetAmount` base tokens on L1. +Then, it sends 1 million tokens to the corresponding on-chain account by posting a +[`deposit`](../../reference/core-contracts/accounts.md#deposit) request to the +[`accounts` core contract](../../reference/core-contracts/accounts.md) on the chain. + +Finally, it sends a [`withdraw`](../../reference/core-contracts/accounts.md#withdraw) request to the `accounts` core +contract to get the tokens back to L1. + +Both requests are affected by the gas fees and the storage deposit. +In some cases, it is possible to ignore these amounts if they are negligible compared to the transferred amounts. +In this case, however, we want to be very precise. + +### Deposit Requests + +#### 1. Request to Deposit Funds + +The first step in the deposit request is to create a request to deposit the funds with `solo.NewCallParams`. + +#### 2. Add Base Tokens + +In the example above we want to deposit 1 Mi, so we call `AddBaseTokens(1 * isc.Million)`. + +This instructs Solo to take that amount from the L1 balance and add it to the transaction. This is only possible for +on-ledger requests. + +#### 3. Calculate Gas Fees + +Once the chain executes the request, it will be charged a gas fee. + +We use `chain.EstimateGasOnLedger` before actually sending the request to estimate this fee. + +#### 4. Estimate Storage Deposit + +On-ledger requests also require a storage deposit. We use `EstimateNeededStorageDeposit` for this. As the 1 Mi already +included is enough for the storage deposit there’s no need to add more. + +#### 5. Add Gas Budget to the Request + +We adjust the request with the gas budget and the gas fee with `WithGasBudget` and `AddBaseTokens`, respectively. + +#### 6. Send the On-Ledger Request + +Finally, we send the on-ledger request with `PostRequestSync`. + +#### 7. The Chain Picks Up the Request + +Any attached base tokens (1 Mi + gas fee) are automatically credited to the sender's L2 account. + +#### 8. The chain executes the request + +The gas fee is deducted from the sender's L2 account. + +#### 9. The Transfer is Complete + +We have exactly 1 Mi on our L2 balance. + +### Withdraw Request + +The process for the `withdraw` request is similar to the [deposit process](#deposit-requests), with two main +differences: + +#### 1. Ensure the L1 Transaction Can Cover the Storage Deposit + +As the storage deposit is larger than the gas fee, we must ensure that the L1 transaction contains enough funds for the +storage deposit. These tokens are automatically deposited in our L2 account, and we immediately withdraw them. + +#### 2.Set the Request's Allowance + +We use `AddAllowanceBaseTokens` to set the _allowance_ of our request. The allowance specifies the maximum amount of +tokens the smart contract can debit from the sender's L2 account. + +It would fail if we posted the same `deposit` request from another user wallet (another private key). +Try it! Only the address owner can move those funds from the on-chain account. + +You can also try removing the `AddAllowanceBaseTokens` call. It will fail because a smart contract cannot deduct funds from the +sender's L2 balance unless explicitly authorized by the allowance. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/timelock.mdx b/docs/build/isc/v1.3/docs/solo/how-tos/timelock.mdx new file mode 100644 index 00000000000..d30cfade07b --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/timelock.mdx @@ -0,0 +1,131 @@ +--- +tags: + - testing + - colored tokens + - time locks + - solo + - plain iotas + - balance + - mint + - delay + +description: You can post a time-locked request by using the Delay() method. You can mint NFTs by using the MintNFT() method. +image: /img/logo/WASP_logo_dark.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Minting NFTs and Time Locks + +Let's examine some less commonly used member functions of the SoloContext. We will switch +to the `fairauction` example to show their usage. Here is the `startAuction()` function of +the `fairauction` test suite: + + + + + +```go +const ( + description = "Cool NFTs for sale!" + deposit = uint64(1000) + minBid = uint64(500) +) + +func startAuction(t *testing.T) (*wasmsolo.SoloContext, *wasmsolo.SoloAgent, wasmtypes.ScNftID) { + ctx := wasmsolo.NewSoloContext(t, fairauction.ScName, fairauction.OnDispatch) + auctioneer := ctx.NewSoloAgent() + nftID := ctx.MintNFT(auctioneer, []byte("NFT metadata")) + require.NoError(t, ctx.Err) + + // start the auction + sa := fairauction.ScFuncs.StartAuction(ctx.Sign(auctioneer)) + sa.Params.MinimumBid().SetValue(minBid) + sa.Params.Description().SetValue(description) + transfer := wasmlib.NewScTransferBaseTokens(deposit) // deposit, must be >=minimum*margin + transfer.AddNFT(&nftID) + sa.Func.Transfer(transfer).Post() + require.NoError(t, ctx.Err) + + return ctx, auctioneer, nftID +} +``` + + + + +The function first sets up the SoloContext as usual, and then it performs quite a bit of +extra work. This is because we want the startAuction() function to start an auction, so +that the tests that subsequently use startAuction() can then focus on testing all kinds of +bidding and auction results. + +First, we are going to need an agent that functions as the `auctioneer`. This auctioneer +will auction off an NFT. To provide the auctioneer with this NFT we use the `MintNFT()` +method to mint a fresh NFT into his account. The minting process will assign a unique NFT +ID. Of course, we check that no error occurred during the minting process. + +Now we are going to start the auction by calling the `startAuction` function of the +`fairauction` contract. We get the function descriptor in the usual way, but we also call +the `Sign()` method of the SoloContext to make sure that the transaction we are about to +post takes its assets from the auctioneer address, and the transaction will be signed with +the corresponding private key. Very often you won't care who posts a request, and we have +set it up in such a way that by default tokens come from the chain originator address, +which has been seeded with tokens just for this occasion. But whenever it is important +where the tokens come from, or who invokes the request, you need to specify the agent +involved by using the Sign() method. + +Next we set up the function parameters as usual. After the parameters have been set up, we +see something new happening. We create an `ScTransfer` proxy and initialize it with the +base tokens that we need to deposit, plus the freshly minted NFT that we are auctioning. +Next we use the `Transfer()` method to pass this proxy before posting the request. This is +exactly how we would do it from within the smart contract code. Note that the function +`NewScTransferBaseTokens()` is used as a shorthand to immediately initialize the new +`ScTransfer` proxy with the desired amount of base tokens. + +Finally, we make sure there was no error after posting the request and return the +SoloContext, `auctioneer` and `nftID`. That concludes the startAuction() function. + +Here is the first test function that uses our startAuction() function: + + + + + +```go +func TestStartAuction(t *testing.T) { + ctx, auctioneer, nftID := startAuction(t) + + nfts := ctx.Chain.L2NFTs(auctioneer.AgentID()) + require.Len(t, nfts, 0) + nfts = ctx.Chain.L2NFTs(ctx.Account().AgentID()) + require.Len(t, nfts, 1) + require.Equal(t, nftID, ctx.Cvt.ScNftID(&nfts[0])) + + // remove pending finalize_auction from backlog + ctx.AdvanceClockBy(61 * time.Minute) + require.True(t, ctx.WaitForPendingRequests(1)) +} +``` + + + + +This test function checks that the NFT was moved by `startAuction` from the auctioneer's +on-chain account to the chain's on-chain account. + +The `startAuction` function of the smart contract will also have posted a time-locked +request to the `finalizeAuction` function by using the `Delay()` method. Therefore, we +need to remove the pending `finalizeAuction` request from the backlog. + +First we move the logical clock forward to a point in time when that request is supposed +to have been triggered. Then we wait for this request to actually be processed. Note that +this will happen in a separate goroutine in the background, so we explicitly wait for the +request counters to catch up with the one request that is pending. + +The `WaitForPendingRequests()` method can also be used whenever a smart contract function +is known to [`post()`](../../schema/how-tos/post.mdx) a request to itself. Such requests are not immediately +executed, but added to the backlog, so you need to wait for these pending requests to +actually be processed. The advantage of having to explicitly wait for those requests is +that you can inspect the in-between state, which means that you can test even a function +that posts a request in isolation. diff --git a/docs/build/isc/v1.3/docs/solo/how-tos/view-sc.md b/docs/build/isc/v1.3/docs/solo/how-tos/view-sc.md new file mode 100644 index 00000000000..2bac649b39e --- /dev/null +++ b/docs/build/isc/v1.3/docs/solo/how-tos/view-sc.md @@ -0,0 +1,74 @@ +--- +description: Calling smart contract view functions with Solo. +image: /img/tutorial/call_view.png +tags: + - how to + - testing + - solo + - views + - call + - synchronous + - entry points +--- + +# Calling a View + +The following snippet shows how you can call the view function `getString` of the smart contract `solotutorial` without +parameters: + +```go +res, err := chain.CallView("example1", "getString") +``` + +The call returns a collection of key/value pairs `res` and an error result `err` in the typical Go fashion. + +[![Calling a view process](/img/tutorial/call_view.png)](/img/tutorial/call_view.png) + +The basic principle of calling a view is similar to sending a request to the smart contract. The essential difference is +that calling a view does not constitute an asynchronous transaction; it is just a direct synchronous call to the view +entry point exposed by the smart contract. + +Therefore, calling a view does not involve any token transfers. Sending a request (either on-ledger or off-ledger) to a +view entry point will result in an exception, returning all attached tokens to the sender minus fees (iif any). + +Views are used to retrieve information about the smart contract's state, for example, to display on a website. Certain +Solo methods such as `chain.GetInfo`, `chain.GetGasFeePolicy`, and `chain.L2Assets` call views of +the [core smart contracts](../../reference/core-contracts/overview.md) behind the scenes to retrieve the information +about the chain or a specific smart contract. + +## Decoding Results Returned by _PostRequestSync_ and _CallView_ + +The following is a specific technicality of the Go environment of _Solo_. + +The result returned by the call to an entry point from the Solo environment is an instance of +the [`dict.Dict`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/dict/dict.go) type, which is essentially a +map of `[]byte` key/value pairs, defined as: + +```go +type Dict map[kv.Key][]byte +``` + +`Dict` is also an implementation of +the [`kv.KVStore`](https://github.com/iotaledger/wasp/blob/develop/packages/kv/kv.go) interface. The `kv` package and +subpackages provide many useful functions to work with the `Dict` type. + +:::note + +Both view and non-view entry points can produce results. +In normal operation, retrieving the result of an on-ledger request is impossible since it is an asynchronous operation. + +However, in the Solo environment, the call to `PostRequestSync` is synchronous, allowing the caller to inspect the +result. +This is a convenient difference between the mocked Solo environment and the distributed ledger used by Wasp nodes. +You can use it to make assertions about the results of a call in the tests. + +::: + +In the example above, `res` is a dictionary where keys and values are binary slices. The `getString` view returns the +value under the `"str"` key, and the value is a `string` encoded as a byte slice. The `codec` package provides functions +to encode/decode frequently used data types, including `string`. The following is a commonly used pattern to get a value +from the `Dict` and decode it: + +```go +var value string = codec.MustDecodeString(res["str"]) +``` diff --git a/docs/build/isc/v1.3/sidebars.js b/docs/build/isc/v1.3/sidebars.js new file mode 100644 index 00000000000..675779b89b5 --- /dev/null +++ b/docs/build/isc/v1.3/sidebars.js @@ -0,0 +1,524 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +const { directoryExists } = require('../../../../src/utils/config'); + +var iscutils_references = {}; +if (directoryExists(__dirname + '/docs/reference/iscutils')) { + iscutils_references = { + type: 'category', + label: 'ISC Utilities', + items: [ + { + type: 'autogenerated', + dirName: 'reference/iscutils', + }, + ], + }; +} + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + //tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + ISCSidebar: [ + { + type: 'doc', + label: 'Introduction', + id: 'introduction', + }, + { + type: 'category', + label: 'Getting Started', + items: [ + { + type: 'doc', + label: 'Languages & VMs', + id: 'getting-started/languages-and-vms', + }, + 'getting-started/quick-start', + 'getting-started/compatibility', + { + type: 'doc', + label: 'Networks & Chains', + id: 'getting-started/networks-and-chains', + }, + { + type: 'doc', + label: 'Tools', + id: 'getting-started/tools', + }, + ], + }, + { + type: 'category', + label: 'How To', + items: [ + 'how-tos/introduction', + { + type: 'doc', + label: 'Send Funds from L1 to L2', + id: 'how-tos/send-funds-from-L1-to-L2', + }, + { + type: 'doc', + label: 'Create a Basic Contract', + id: 'how-tos/create-a-basic-contract', + }, + { + type: 'doc', + label: 'Deploy a Smart Contract', + id: 'how-tos/deploy-a-smart-contract', + }, + { + type: 'doc', + label: 'Create Custom Tokens - ERC20', + id: 'how-tos/ERC20', + }, + { + type: 'doc', + label: 'Send ERC20 Tokens Across Chains', + id: 'how-tos/send-ERC20-across-chains', + }, + { + type: 'doc', + label: 'Create NFTs - ERC721', + id: 'how-tos/ERC721', + }, + { + type: 'doc', + label: 'Send NFTs Across Chains', + id: 'how-tos/send-NFTs-across-chains', + }, + { + type: 'doc', + label: 'Test Smart Contracts', + id: 'how-tos/test-smart-contracts', + }, + { + type: 'category', + label: 'Interact with the Core Contracts', + items: [ + { + type: 'doc', + label: 'Introduction', + id: 'how-tos/core-contracts/introduction', + }, + { + type: 'category', + label: 'Basics', + items: [ + { + type: 'doc', + label: 'Get Native Assets Balance', + id: 'how-tos/core-contracts/basics/get-balance', + }, + { + type: 'category', + label: 'Allowance', + items: [ + { + type: 'doc', + label: 'Allow', + id: 'how-tos/core-contracts/basics/allowance/allow', + }, + { + type: 'doc', + label: 'Get Allowance', + id: 'how-tos/core-contracts/basics/allowance/get-allowance', + }, + { + type: 'doc', + label: 'Take Allowance', + id: 'how-tos/core-contracts/basics/allowance/take-allowance', + }, + ], + }, + { + type: 'doc', + label: 'Send Assets to L1', + id: 'how-tos/core-contracts/basics/send-assets-to-l1', + }, + ], + }, + { + type: 'category', + label: 'Token', + items: [ + { + label: 'Introduction', + type: 'doc', + id: 'how-tos/core-contracts/token/introduction', + }, + { + type: 'doc', + label: 'Create a Native Token', + id: 'how-tos/core-contracts/token/create-native-token', + }, + { + type: 'doc', + label: 'Mint Native Tokens', + id: 'how-tos/core-contracts/token/mint-token', + }, + { + type: 'doc', + label: 'Custom ERC20 Functions', + id: 'how-tos/core-contracts/token/erc20-native-token', + }, + { + type: 'doc', + label: 'Create a Foundry', + id: 'how-tos/core-contracts/token/create-foundry', + }, + { + type: 'doc', + label: 'Register Token as ERC20', + id: 'how-tos/core-contracts/token/register-token', + }, + { + type: 'doc', + label: 'Send Token Across Chains', + id: 'how-tos/core-contracts/token/send-token-across-chains', + }, + ], + }, + { + type: 'category', + label: 'NFT', + items: [ + { + label: 'Introduction', + type: 'doc', + id: 'how-tos/core-contracts/nft/introduction', + }, + { + type: 'doc', + label: 'Mint an NFT', + id: 'how-tos/core-contracts/nft/mint-nft', + }, + { + type: 'doc', + label: 'Use as ERC721', + id: 'how-tos/core-contracts/nft/use-as-erc721', + }, + { + type: 'doc', + label: 'Get NFT Metadata', + id: 'how-tos/core-contracts/nft/get-nft-metadata', + }, + ], + }, + { + type: 'doc', + label: 'Get Randomness on L2', + id: 'how-tos/core-contracts/get-randomness-on-l2', + }, + { + type: 'doc', + label: 'Call and Call View', + id: 'how-tos/core-contracts/call-view', + }, + ], + }, + ], + }, + { + type: 'category', + label: 'Explanations', + items: [ + { + type: 'doc', + label: 'Anatomy of a Smart Contract', + id: 'explanations/smart-contract-anatomy', + }, + { + type: 'doc', + label: 'Sandbox Interface', + id: 'explanations/sandbox', + }, + { + type: 'doc', + label: 'Calling a Smart Contract', + id: 'explanations/invocation', + }, + { + type: 'doc', + label: 'State, Transitions and State Anchoring', + id: 'explanations/states', + }, + { + type: 'doc', + label: 'State manager', + id: 'explanations/state_manager', + }, + { + type: 'doc', + label: 'Validators and Access Nodes', + id: 'explanations/validators', + }, + { + type: 'doc', + label: 'Consensus', + id: 'explanations/consensus', + }, + { + type: 'doc', + label: 'How Accounts Work', + id: 'explanations/how-accounts-work', + }, + { + type: 'link', + label: 'Core Contracts', + href: '/isc/reference/core-contracts/overview', + }, + ], + }, + { + type: 'category', + label: 'Reference', + items: [ + 'reference/json-rpc-spec', + { + type: 'category', + label: 'Magic Contract', + items: [ + { + type: 'autogenerated', + dirName: 'reference/magic-contract', + }, + ], + }, + { + type: 'category', + label: 'Core Contracts', + items: [ + { + type: 'doc', + label: 'Overview', + id: 'reference/core-contracts/overview', + }, + { + type: 'doc', + label: 'root', + id: 'reference/core-contracts/root', + }, + { + type: 'doc', + label: 'accounts', + id: 'reference/core-contracts/accounts', + }, + { + type: 'doc', + label: 'blob', + id: 'reference/core-contracts/blob', + }, + { + type: 'doc', + label: 'blocklog', + id: 'reference/core-contracts/blocklog', + }, + { + type: 'doc', + label: 'governance', + id: 'reference/core-contracts/governance', + }, + { + type: 'doc', + label: 'errors', + id: 'reference/core-contracts/errors', + }, + { + type: 'doc', + label: 'EVM', + id: 'reference/core-contracts/evm', + }, + ], + }, + iscutils_references, + { + type: 'doc', + label: 'WasmLib Data Types', + id: 'reference/wasm-lib-data-types', + }, + ], + }, + { + type: 'category', + label: 'Test with Solo', + items: [ + { + label: 'Getting Started', + id: 'solo/getting-started', + type: 'doc', + }, + { + type: 'category', + label: 'How To', + items: [ + { + type: 'doc', + label: 'First Example', + id: 'solo/how-tos/first-example', + }, + { + type: 'doc', + label: 'The L1 Ledger', + id: 'solo/how-tos/the-l1-ledger', + }, + { + type: 'doc', + label: 'Deploy a Smart Contract', + id: 'solo/how-tos/deploying-sc', + }, + { + type: 'doc', + label: 'Invoke a Smart Contract', + id: 'solo/how-tos/invoking-sc', + }, + { + type: 'doc', + label: 'Call a View', + id: 'solo/how-tos/view-sc', + }, + { + type: 'doc', + label: 'Error Handling', + id: 'solo/how-tos/error-handling', + }, + { + type: 'doc', + label: 'Accounts', + id: 'solo/how-tos/the-l2-ledger', + }, + { + type: 'doc', + label: 'Test Smart Contracts', + id: 'solo/how-tos/test', + }, + { + type: 'doc', + label: 'Example Tests', + id: 'solo/how-tos/examples', + }, + { + type: 'doc', + label: 'Colored Tokens and Time Locks', + id: 'solo/how-tos/timelock', + }, + ], + }, + ], + }, + { + type: 'category', + label: 'Wasm - Schema Tool', + items: [ + { + type: 'doc', + label: 'The Schema Tool', + id: 'schema/introduction', + }, + { + type: 'doc', + label: 'Data Access Proxies', + id: 'schema/proxies', + }, + { + type: 'category', + label: 'How To', + items: [ + { + type: 'doc', + label: 'Create a Schema', + id: 'schema/how-tos/usage', + }, + { + type: 'doc', + label: 'Define the State', + id: 'schema/how-tos/state', + }, + { + type: 'doc', + label: 'Use Structured Data Types', + id: 'schema/how-tos/structs', + }, + { + type: 'doc', + label: 'Generate Type Definitions', + id: 'schema/how-tos/typedefs', + }, + { + type: 'doc', + label: 'Trigger Events', + id: 'schema/how-tos/events', + }, + { + type: 'doc', + label: 'Define Functions', + id: 'schema/how-tos/funcs', + }, + { + type: 'doc', + label: 'Limit Access', + id: 'schema/how-tos/access', + }, + { + type: 'doc', + label: 'Define Function Parameters', + id: 'schema/how-tos/params', + }, + { + type: 'doc', + label: 'Define Function Results', + id: 'schema/how-tos/results', + }, + { + type: 'doc', + label: 'Use Thunk Functions', + id: 'schema/how-tos/thunks', + }, + { + type: 'doc', + label: 'Use View-Only Functions', + id: 'schema/how-tos/views', + }, + { + type: 'doc', + label: 'Initialize a Smart Contract', + id: 'schema/how-tos/init', + }, + { + type: 'doc', + label: 'Transfer Tokens', + id: 'schema/how-tos/transfers', + }, + { + type: 'doc', + label: 'Add Function Descriptors', + id: 'schema/how-tos/funcdesc', + }, + { + type: 'doc', + label: 'Call Functions', + id: 'schema/how-tos/call', + }, + { + type: 'doc', + label: 'Post Asynchronous Requests', + id: 'schema/how-tos/post', + }, + ], + }, + ], + }, + ], +}; diff --git a/docs/external/tips b/docs/external/tips index e30ee794290..b0590b73a30 160000 --- a/docs/external/tips +++ b/docs/external/tips @@ -1 +1 @@ -Subproject commit e30ee7942900e6d9343650d3c5325673951bb159 +Subproject commit b0590b73a30a56976e82017d25cb4e757c99ae36 diff --git a/docs/get-started/introduction/iota/iota-token.md b/docs/get-started/introduction/iota/iota-token.md index ddb1d7e37d1..3b684986cd2 100644 --- a/docs/get-started/introduction/iota/iota-token.md +++ b/docs/get-started/introduction/iota/iota-token.md @@ -72,11 +72,14 @@ using so you don't get tricked into selling/buying under/over the current market IOTA is listed on most major _cryptocurrency_ exchanges: -- [Binance.US](https://www.binance.us/en/home) - [Binance](https://www.binance.com) +- [Binance.US](https://www.binance.us/en/home) - [Bitfinex](https://www.bitfinex.com/) - [Bitpanda](https://www.bitpanda.com) - [Bitvavo](https://bitvavo.com) +- [Gate.io](https://www.gate.io/) +- [HTX](https://www.htx.com/) +- [OKX](https://www.okx.com/) - [Coinmerce](https://coinmerce.io/) - [Indodax](https://indodax.com/) - [KuCoin](https://www.kucoin.com/) diff --git a/docs/get-started/introduction/iota/staking.md b/docs/get-started/introduction/iota/staking.md deleted file mode 100644 index 30ada856fc9..00000000000 --- a/docs/get-started/introduction/iota/staking.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Staking IOTA -description: Everything you need to know about the different staking opportunities in the IOTA and Shimmer networks. -tags: - - staking IOTA - - Shimmer network - - staking rewards ---- - -# Staking in the IOTA Network Ecosystem - -In 2022, IOTA introduced a new staging network and battlefield for IOTA's core technological innovations: Shimmer. This marked a vast increase in the utility of the IOTA token. -Shimmer launched with its native tokens: SMR. With the _tokenomics_ and incentive structure around this network, it is possible to stake tokens. - -:::info - -Find the blog post introducing IOTA _staking_ [here](https://blog.iota.org/introducing-iota-staking/). -Find the announcement of the start of IOTA staking [here](https://blog.iota.org/iota-staking-start/). - -::: - -There are several ways to stake your tokens and earn staking rewards: - -- Shimmer pre-launch staking created the initial token supply for SMR and distributed it to those who stake their IOTA tokens. -- SMR token staking helps testing on the Shimmer network and supports the network. - -## Shimmer Pre-launch Staking - -The Pre-launch staking period rewarded IOTA token holders for their participation and distributed SMR tokens to them. In the case of Shimmer, it also created the total initial supply of the network. - -Starting from 28th December 2021, IOTA holders who possess IOTA tokens in the Firefly wallet and who had chosen to participate in the staking period generated Shimmer tokens for 90 days. - -The Shimmer staking period was limited to these initial 90 days. - -### IOTA Staking for SMR Rewards - -The Shimmer network was bootstrapped purely from IOTA token stakers. The initial token supply of the Shimmer network only relied on the amount of IOTA tokens staked for Shimmer in the 90-day staking period, and 80% of the initial supply was distributed to IOTA token holders, while the remaining 20% was distributed equally between the Community DAO and the Tangle Ecosystem. - -- The staking functionality in the Firefly Wallet was used for Shimmer. -- Shimmer tokens were distributed at a fixed rate of `1 SMR per 1 MIOTA per milestone`. - -![shimmer staking](/img/learn/iota-token/shimmer-staking.png) - -- With the launch of the Shimmer network, the generated Shimmer tokens were distributed to the IOTA stakers. This distribution was implemented as a functionality within the Firefly wallet. diff --git a/docs/get-started/introduction/shimmer/shimmer-token.md b/docs/get-started/introduction/shimmer/shimmer-token.md index 8f7d8cb8939..d9e577039c9 100644 --- a/docs/get-started/introduction/shimmer/shimmer-token.md +++ b/docs/get-started/introduction/shimmer/shimmer-token.md @@ -38,7 +38,7 @@ participation, community engagement, and innovation within the Shimmer ecosystem ### IOTA Stakers Allocation A significant portion of the Shimmer tokens, accounting for 80% of the total supply, is allocated to IOTA stakers. This -amounts to 1,450,896,407 SMR tokens. IOTA token holders who [staked their tokens had the opportunity](/get-started/introduction/iota/staking#iota-staking-for-smr-rewards) to receive SMR tokens as rewards for participating in the IOTA mainnet. +amounts to 1,450,896,407 SMR tokens. IOTA token holders who staked their tokens had the opportunity to receive SMR tokens as rewards for participating in the IOTA mainnet. ### Community DAO Allocation diff --git a/docs/get-started/programs/bug-bounties.md b/docs/get-started/programs/bug-bounties.md deleted file mode 100644 index 24fc881201e..00000000000 --- a/docs/get-started/programs/bug-bounties.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -image: /img/shimmer-wiki.png -description: Learn about the bug bounty programs in IOTA and Shimmer networks, incentivizing security researchers to identify and report vulnerabilities. -tags: - - bug bounties - - security researchers - - vulnerability identification - - IOTA network - - Shimmer network ---- - -# Bug Bounties - -Bug bounties are programs the IOTA and Shimmer networks implement to encourage security researchers and ethical -hackers to discover and report potential vulnerabilities in their respective systems. These programs play a crucial role -in maintaining the security and _integrity_ of the networks by proactively identifying and addressing security weaknesses. - -By offering financial rewards or other incentives, bug bounty programs attract skilled individuals who thoroughly -analyze the networks' codebase, infrastructure, and protocols. These researchers aim to identify any loopholes, -vulnerabilities, or potential _exploits_ that malicious actors could exploit. Once a vulnerability is found, it is -reported to the development teams, who can take the necessary steps to mitigate the issue and enhance the overall -security of the networks. - -Bug bounty programs enhance the security of the IOTA and Shimmer networks and foster a collaborative and -inclusive environment where security researchers and developers work together to build robust and resilient systems. By -incentivizing vulnerability identification and responsible disclosure, these programs contribute to the ongoing -improvement and evolution of the networks, ensuring they remain trustworthy and secure for all participants. - -If you are a security researcher interested in contributing to the security of the IOTA or Shimmer networks, check the official bug bounty programs and guidelines the respective projects provide. Your expertise and -discoveries can significantly impact the security and reliability of these innovative technologies. - -## Active Bug Bounties - -There are currently no active bug bounties. diff --git a/docs/get-started/sidebars.ts b/docs/get-started/sidebars.ts index 6eed4e55b74..25abaef5cb2 100644 --- a/docs/get-started/sidebars.ts +++ b/docs/get-started/sidebars.ts @@ -20,7 +20,6 @@ module.exports = { items: [ 'introduction/iota/introduction', 'introduction/iota/iota-token', - 'introduction/iota/staking', ], }, { @@ -52,11 +51,7 @@ module.exports = { { type: 'category', label: 'Programs & Funding', - items: [ - 'programs/touchpoint', - 'programs/bug-bounties', - 'programs/community-treasury', - ], + items: ['programs/touchpoint', 'programs/community-treasury'], }, { type: 'category', diff --git a/docs/get-started/tools/legacy-migration-tool.mdx b/docs/get-started/tools/legacy-migration-tool.mdx index 04051f80f75..66672900915 100644 --- a/docs/get-started/tools/legacy-migration-tool.mdx +++ b/docs/get-started/tools/legacy-migration-tool.mdx @@ -6,7 +6,7 @@ import ThemedImage from '@theme/ThemedImage'; The [IOTA Legacy Migration Tool](https://github.com/iotaledger/legacy-migration-tool/releases) is a standalone app to help you migrate your tokens from the legacy IOTA network to the -current [IOTA Mainnet](/build/networks-endpoints/#iota-mainnet) running the Stardust protocol. +current [IOTA Mainnet](/build/networks-endpoints/#iota) running the Stardust protocol. The new tool allows users to migrate from an [81-character seed](#restore-a-text-backup), [a Trinity seed vault file](#restore-a-file-backup), or a [Ledger device](#users-with-ledger-devices). diff --git a/docs/get-started/wallets/bloom.md b/docs/get-started/wallets/bloom.md index cfdb2de997d..bd2f7a9e3d9 100644 --- a/docs/get-started/wallets/bloom.md +++ b/docs/get-started/wallets/bloom.md @@ -12,7 +12,7 @@ tags: --- Bloom is a desktop wallet with first-class security developed by former members of the Firefly team. -Bloom supports the [IOTA](https://wiki.iota.org/build/networks-endpoints/#iota-mainnet) and +Bloom supports the [IOTA](https://wiki.iota.org/build/networks-endpoints/#iota) and [Shimmer](https://wiki.iota.org/build/networks-endpoints/#shimmer) networks, as well as [ShimmerEVM](https://wiki.iota.org/build/networks-endpoints/#shimmerevm) in the same application. This means you can seamlessly transfer assets back and forth between Shimmer and ShimmerEVM without other tooling. diff --git a/docs/learn/glossary.mdx b/docs/learn/glossary.mdx index e1068d4ebae..d49dc688a33 100644 --- a/docs/learn/glossary.mdx +++ b/docs/learn/glossary.mdx @@ -3,6 +3,6 @@ title: Glossary description: Glossary of all specialized names and phrases used in the IOTA and Shimmer networks. If you dont understand a wording you will find answers here. --- -import Glossary from '/theme/src/theme/Glossary'; +import Glossary from '@site/src/theme/Glossary'; diff --git a/docs/maintain/hornet/2.0/docs/how_tos/using_docker.md b/docs/maintain/hornet/2.0/docs/how_tos/using_docker.md index b5b9eb77645..d86cf9f35dc 100644 --- a/docs/maintain/hornet/2.0/docs/how_tos/using_docker.md +++ b/docs/maintain/hornet/2.0/docs/how_tos/using_docker.md @@ -64,6 +64,13 @@ Once you have completed all the installation [requirements](#requirements), you mkdir node-docker-setup && cd node-docker-setup && curl -L https://node-docker-setup.iota.org/iota | tar -zx ``` + + + +```sh +mkdir node-docker-setup && cd node-docker-setup && curl -L https://node-docker-setup.iota.org/iota-testnet | tar -zx +``` + @@ -72,10 +79,10 @@ mkdir node-docker-setup && cd node-docker-setup && curl -L https://node-docker-s ``` - + ```sh -mkdir node-docker-setup && cd node-docker-setup && curl -L https://node-docker-setup.iota.org/testnet | tar -zx +mkdir node-docker-setup && cd node-docker-setup && curl -L https://node-docker-setup.iota.org/shimmer-testnet | tar -zx ``` @@ -133,6 +140,13 @@ Activating a Wasp node isn't enough to fully participate in a smart contract cha https://github.com/iotaledger/node-docker-setup/blob/main/iota/env_template ``` + + + +```sh reference +https://github.com/iotaledger/node-docker-setup/blob/main/iota-testnet/env_template +``` + @@ -141,10 +155,10 @@ https://github.com/iotaledger/node-docker-setup/blob/main/shimmer/env_template ``` - + ```sh reference -https://github.com/iotaledger/node-docker-setup/blob/main/testnet/env_template +https://github.com/iotaledger/node-docker-setup/blob/main/shimmer-testnet/env_template ``` @@ -173,6 +187,12 @@ To create this directory with correct permissions run the contained script: ## Run +:::info Wasp Access Node + +If your are coming from the `Running an ISC Access Node` how-to, this guide ends here and you have to continue with the access node setup [here](/wasp/how-tos/running-an-access-node#download-the-chain-state). + +::: + ### Starting the node You can start the HORNET node and INX extensions by running: diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md b/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md deleted file mode 100755 index 77533ecb703..00000000000 --- a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/configuration.md +++ /dev/null @@ -1,490 +0,0 @@ ---- -# !!! DO NOT MODIFY !!! -# This file is auto-generated by the gendoc tool based on the source code of the app. -description: This section describes the configuration parameters and their types for WASP. -tags: - - IOTA Node - - Hornet Node - - WASP Node - - Smart Contracts - - L2 - - Configuration - - JSON - - Customize - - Config - - reference ---- - -# Core Configuration - -WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). - -You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. - -For example: - -```shell -wasp -c config_defaults.json -``` - -You can always get the most up-to-date description of the config parameters by running: - -```shell -wasp -h --full -``` - -## 1. Application - -| Name | Description | Type | Default value | -| ------------------------- | ------------------------------------------------------ | ------- | ------------- | -| checkForUpdates | Whether to check for updates of the application or not | boolean | true | -| [shutdown](#app_shutdown) | Configuration for shutdown | object | | - -### Shutdown - -| Name | Description | Type | Default value | -| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | -| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | -| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | - -### Shutdown Log - -| Name | Description | Type | Default value | -| -------- | --------------------------------------------------- | ------- | -------------- | -| enabled | Whether to store self-shutdown events to a log file | boolean | true | -| filePath | The file path to the self-shutdown log | string | "shutdown.log" | - -Example: - -```json -{ - "app": { - "checkForUpdates": true, - "shutdown": { - "stopGracePeriod": "5m", - "log": { - "enabled": true, - "filePath": "shutdown.log" - } - } - } -} -``` - -## 2. Logger - -| Name | Description | Type | Default value | -| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | -| level | The minimum enabled logging level | string | "info" | -| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | -| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | -| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | -| encoding | The logger's encoding (options: "json", "console") | string | "console" | -| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | -| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | -| disableEvents | Prevents log messages from being raced as events | boolean | true | - -### EncodingConfig - -| Name | Description | Type | Default value | -| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | -| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | - -Example: - -```json -{ - "logger": { - "level": "info", - "disableCaller": true, - "disableStacktrace": false, - "stacktraceLevel": "panic", - "encoding": "console", - "encodingConfig": { - "timeEncoder": "rfc3339" - }, - "outputPaths": ["stdout"], - "disableEvents": true - } -} -``` - -## 3. INX - -| Name | Description | Type | Default value | -| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | -| address | The INX address to which to connect to | string | "localhost:9029" | -| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | -| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | - -Example: - -```json -{ - "inx": { - "address": "localhost:9029", - "maxConnectionAttempts": 30, - "targetNetworkName": "" - } -} -``` - -## 4. Database - -| Name | Description | Type | Default value | -| ---------------------------- | ---------------------------------------- | ------- | ------------- | -| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | -| [chainState](#db_chainstate) | Configuration for chainState | object | | -| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | - -### ChainState - -| Name | Description | Type | Default value | -| ---- | -------------------------------------------- | ------ | -------------------- | -| path | The path to the chain state databases folder | string | "waspdb/chains/data" | - -Example: - -```json -{ - "db": { - "engine": "rocksdb", - "chainState": { - "path": "waspdb/chains/data" - }, - "debugSkipHealthCheck": true - } -} -``` - -## 5. P2p - -| Name | Description | Type | Default value | -| ------------------------- | -------------------------- | ------ | ------------- | -| [identity](#p2p_identity) | Configuration for identity | object | | -| [db](#p2p_db) | Configuration for Database | object | | - -### Identity - -| Name | Description | Type | Default value | -| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | -| privateKey | Private key used to derive the node identity (optional) | string | "" | -| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | - -### Database - -| Name | Description | Type | Default value | -| ---- | ---------------------------- | ------ | ----------------- | -| path | The path to the p2p database | string | "waspdb/p2pstore" | - -Example: - -```json -{ - "p2p": { - "identity": { - "privateKey": "", - "filePath": "waspdb/identity/identity.key" - }, - "db": { - "path": "waspdb/p2pstore" - } - } -} -``` - -## 6. Registries - -| Name | Description | Type | Default value | -| -------------------------------------------- | -------------------------------- | ------ | ------------- | -| [chains](#registries_chains) | Configuration for chains | object | | -| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | -| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | -| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | - -### Chains - -| Name | Description | Type | Default value | -| -------- | ----------------------------------- | ------ | ----------------------------------- | -| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | - -### DkShares - -| Name | Description | Type | Default value | -| ---- | -------------------------------------------------------- | ------ | ----------------- | -| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | - -### TrustedPeers - -| Name | Description | Type | Default value | -| -------- | ------------------------------------------- | ------ | --------------------------- | -| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | - -### ConsensusState - -| Name | Description | Type | Default value | -| ---- | ------------------------------------------------- | ------ | ------------------------- | -| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | - -Example: - -```json -{ - "registries": { - "chains": { - "filePath": "waspdb/chains/chain_registry.json" - }, - "dkShares": { - "path": "waspdb/dkshares" - }, - "trustedPeers": { - "filePath": "waspdb/trusted_peers.json" - }, - "consensusState": { - "path": "waspdb/chains/consensus" - } - } -} -``` - -## 7. Peering - -| Name | Description | Type | Default value | -| ---------- | ---------------------------------------------------- | ------ | -------------- | -| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | -| port | Port for Wasp committee connection/peering | int | 4000 | - -Example: - -```json -{ - "peering": { - "peeringURL": "0.0.0.0:4000", - "port": 4000 - } -} -``` - -## 8. Chains - -| Name | Description | Type | Default value | -| -------------------------------- | ------------------------------------------------------------------------------------------------------- | ------- | ------------- | -| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | -| broadcastInterval | Time between re-broadcast of offledger requests | string | "5s" | -| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | -| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | -| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | -| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | -| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | - -Example: - -```json -{ - "chains": { - "broadcastUpToNPeers": 2, - "broadcastInterval": "5s", - "apiCacheTTL": "5m", - "pullMissingRequestsFromCommittee": true, - "deriveAliasOutputByQuorum": true, - "pipeliningLimit": -1, - "consensusDelay": "500ms" - } -} -``` - -## 9. StateManager - -| Name | Description | Type | Default value | -| --------------------------------- | --------------------------------------------------------------------------------------------- | ------ | ------------- | -| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | -| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | -| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | -| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | -| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "1s" | -| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | -| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | -| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted | int | 1000 | - -Example: - -```json -{ - "stateManager": { - "blockCacheMaxSize": 1000, - "blockCacheBlocksInCacheDuration": "1h", - "blockCacheBlockCleaningPeriod": "1m", - "stateManagerGetBlockRetry": "3s", - "stateManagerRequestCleaningPeriod": "1s", - "stateManagerTimerTickPeriod": "1s", - "pruningMinStatesToKeep": 10000, - "pruningMaxStatesToDelete": 1000 - } -} -``` - -## 10. Validator - -| Name | Description | Type | Default value | -| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | -| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | - -Example: - -```json -{ - "validator": { - "address": "" - } -} -``` - -## 11. Write-Ahead Logging - -| Name | Description | Type | Default value | -| ------- | -------------------------------------------- | ------- | ------------- | -| enabled | Whether the "write-ahead logging" is enabled | boolean | true | -| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | - -Example: - -```json -{ - "wal": { - "enabled": true, - "path": "waspdb/wal" - } -} -``` - -## 12. Web API - -| Name | Description | Type | Default value | -| ------------------------- | -------------------------------------------------------- | ------- | -------------- | -| enabled | Whether the web api plugin is enabled | boolean | true | -| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | -| [auth](#webapi_auth) | Configuration for auth | object | | -| [limits](#webapi_limits) | Configuration for limits | object | | -| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | - -### Auth - -| Name | Description | Type | Default value | -| --------------------------- | -------------------------------------- | ------ | ------------- | -| scheme | Selects which authentication to choose | string | "jwt" | -| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | -| [basic](#webapi_auth_basic) | Configuration for Basic Auth | object | | -| [ip](#webapi_auth_ip) | Configuration for IP-based Auth | object | | - -### JWT Auth - -| Name | Description | Type | Default value | -| -------- | ------------------ | ------ | ------------- | -| duration | Jwt token lifetime | string | "24h" | - -### Basic Auth - -| Name | Description | Type | Default value | -| -------- | ----------------------------------------------- | ------ | ------------- | -| username | The username which grants access to the service | string | "wasp" | - -### IP-based Auth - -| Name | Description | Type | Default value | -| --------- | ---------------------------------------------------- | ----- | ------------- | -| whitelist | A list of ips that are allowed to access the service | array | 0.0.0.0 | - -### Limits - -| Name | Description | Type | Default value | -| ------------------------------ | ----------------------------------------------------------------------------- | ------ | ------------- | -| timeout | The timeout after which a long running operation will be canceled | string | "30s" | -| readTimeout | The read timeout for the HTTP request body | string | "10s" | -| writeTimeout | The write timeout for the HTTP response body | string | "1m" | -| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | -| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | -| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | - -Example: - -```json -{ - "webapi": { - "enabled": true, - "bindAddress": "0.0.0.0:9090", - "auth": { - "scheme": "jwt", - "jwt": { - "duration": "24h" - }, - "basic": { - "username": "wasp" - }, - "ip": { - "whitelist": ["0.0.0.0"] - } - }, - "limits": { - "timeout": "30s", - "readTimeout": "10s", - "writeTimeout": "1m", - "maxBodyLength": "2M", - "maxTopicSubscriptionsPerClient": 0, - "confirmedStateLagThreshold": 2 - }, - "debugRequestLoggerEnabled": false - } -} -``` - -## 13. Profiling - -| Name | Description | Type | Default value | -| ----------- | ------------------------------------------------- | ------- | ---------------- | -| enabled | Whether the profiling component is enabled | boolean | false | -| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | - -Example: - -```json -{ - "profiling": { - "enabled": false, - "bindAddress": "localhost:6060" - } -} -``` - -## 14. ProfilingRecorder - -| Name | Description | Type | Default value | -| ------- | ----------------------------------------------- | ------- | ------------- | -| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | - -Example: - -```json -{ - "profilingRecorder": { - "enabled": false - } -} -``` - -## 15. Prometheus - -| Name | Description | Type | Default value | -| ----------- | ------------------------------------------------------------ | ------- | -------------- | -| enabled | Whether the prometheus plugin is enabled | boolean | true | -| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | - -Example: - -```json -{ - "prometheus": { - "enabled": true, - "bindAddress": "0.0.0.0:2112" - } -} -``` diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/chain-management.md b/docs/maintain/wasp/v1.1/docs/how-tos/chain-management.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/chain-management.md rename to docs/maintain/wasp/v1.1/docs/how-tos/chain-management.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-a-node.md b/docs/maintain/wasp/v1.1/docs/how-tos/running-a-node.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/running-a-node.md rename to docs/maintain/wasp/v1.1/docs/how-tos/running-a-node.md diff --git a/docs/maintain/wasp/v1.1/docs/how-tos/running-an-access-node.md b/docs/maintain/wasp/v1.1/docs/how-tos/running-an-access-node.md new file mode 100644 index 00000000000..a12240bda0a --- /dev/null +++ b/docs/maintain/wasp/v1.1/docs/how-tos/running-an-access-node.md @@ -0,0 +1,283 @@ +--- +description: How to setup an access node. +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Running a node + - ISC +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Running an ISC Access Node + +## Set Up Wasp and Hornet + +First, you should [set up a Wasp Node](./running-a-node.md) but don't run `docker compose up` to start the docker containers yet. Continue with the following steps first: + +### Download the Chain State + +You can configure how much of the state you wish to keep on your node by uncommenting and changing the `WASP_PRUNING_MIN_STATES_TO_KEEP` environment variable in the node-docker-setup. The default value is 10000 blocks. + +### Run a Non-archive Node + +If you wish to run a non-archive node (only keep the last N blocks), you must uncomment `WASP_SNAPSHOT_NETWORK_PATHS`. + +### Run An Archive Node + +If you wish to have a full archive node, you need to set `WASP_PRUNING_MIN_STATES_TO_KEEP` to `0` and comment `WASP_SNAPSHOT_NETWORK_PATHS` out. + +You can then download the historical state using the following command (this will take a while): + + + + + +```sh +wget https://files.stardust-mainnet.iotaledger.net/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.iota-testnet.iotaledger.net/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.testnet.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +:::note Disk Space + +Operating as a full archive node requires a lot of disk space. We recommend at least 500Gb of free space to operate without issues + +::: + +### Run Everything + +```sh +docker compose up -d +``` + +It will take a few minutes until the hornet node is synced. + +You can check the sync status by following the logs with `docker logs -f hornet`, or in the web dashboard. + +## Use Wasp-Cli to configure the chain and add peers +### Download Wasp-Cli + +You can download a Wasp-Cli that matches your Wasp version from the [Wasp releases](https://github.com/iotaledger/wasp/releases). +You can use a commands like the following to for example download version 1.1.0: + +```sh +curl -sL https://github.com/iotaledger/wasp/releases/download/v1.1.0/wasp-cli_1.1.0_Linux_x86_64.tar.gz | tar xzv +``` + +Change directory into the newly-downloaded `wasp-cli` directory: + +```sh +cd wasp-cli_1.1.0_Linux_x86_64/ +``` + +### Set the L1 API Address + +Set the L1 API address. You can set it to what you configured as `NODE_HOST` in the `.env` file + +:::tip HTTP + +If you use the http setup, don't forget to replace `https` with `http` + +::: + +```sh +./wasp-cli set l1.apiaddress https://{NODE_HOST} +``` + +### Set Wasp API Address + +Set the WASP API address. It is your configured `NODE_HOST` and the `/wasp/api` path. + +```sh +./wasp-cli wasp add my-node https://{NODE_HOST}/wasp/api +``` + +### Login + +Login to wasp using your credentials. You can update your current credentials or add new ones in the wasp dashboard. + +```sh +./wasp-cli login +``` +```sh title=Output +Username: wasp +Password: (default is wasp) +Successfully authenticated +``` + +### Obtain Peering Info + +Get your peering info which you will need to share with your peers: + +```sh +./wasp-cli peering info +``` +```sh title=Output +PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 +PeeringURL: 0.0.0.0:4000 +``` + +Please note the PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 output. +Send it together with your domain/IP to node operators that you want to peer with. + +### Wait for the other party to peer + +Wait until peer added you as trusted and access peer. + +### Use wasp-cli to add nodes as peers + +Now you can add your peer as trusted peer. + +```sh +./wasp-cli peering trust peer1 : +./wasp-cli peering trust peer2 : +``` + +### Add Chain + +Add the chain with its chain id and name: + + + + +```sh +./wasp-cli chain add iota-evm iota1pzt3mstq6khgc3tl0mwuzk3eqddkryqnpdxmk4nr25re2466uxwm28qqxu5 +``` + + + + +```sh +./wasp-cli chain add iota-evm-testnet tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu +``` + + + + +```sh +./wasp-cli chain add shimmer-evm smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s +``` + + + + +```sh +./wasp-cli chain add shimmer-evm-testnet rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex +``` + + + + +### Activate + +Activate the chain using its name: + + + + + +```sh +./wasp-cli chain activate --chain iota-evm +``` + + + + +```sh +./wasp-cli chain activate --chain iota-evm-testnet +``` + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm +``` + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm-testnet +``` + + + + +### Add Peers as Access Nodes of the Chain + +Add the peers as access nodes. + +:::info + +This is normally only needed for peers that you plan to add as access nodes to your own node + +::: + +```sh +./wasp-cli chain access-nodes add --peers=peer1,peer2 +``` + +### Check if Wasp Synced + +You can follow the progress using `docker logs -f wasp`. If you chose to create a [full-archive node](#run-and-archive-node), this can take several minutes, maybe hours. + +### Test Your Endpoint + +You should have a working EVM JSON-RPC endpoint on: + + + + +``` +/wasp/api/v1/chains/iota1pzt3mstq6khgc3tl0mwuzk3eqddkryqnpdxmk4nr25re2466uxwm28qqxu5/evm +``` + + + + +``` +/wasp/api/v1/chains/tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu/evm +``` + + + + + +``` +/wasp/api/v1/chains/smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s/evm +``` + + + + +``` +/wasp/api/v1/chains/rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex/evm +``` + + + diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/setting-up-a-chain.md b/docs/maintain/wasp/v1.1/docs/how-tos/setting-up-a-chain.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/setting-up-a-chain.md rename to docs/maintain/wasp/v1.1/docs/how-tos/setting-up-a-chain.md diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/wasp-cli.md b/docs/maintain/wasp/v1.1/docs/how-tos/wasp-cli.md similarity index 100% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/how-tos/wasp-cli.md rename to docs/maintain/wasp/v1.1/docs/how-tos/wasp-cli.md diff --git a/docs/maintain/wasp/v1.1/docs/reference/configuration.md b/docs/maintain/wasp/v1.1/docs/reference/configuration.md new file mode 100755 index 00000000000..bfe1181b5b5 --- /dev/null +++ b/docs/maintain/wasp/v1.1/docs/reference/configuration.md @@ -0,0 +1,573 @@ +--- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app. +description: This section describes the configuration parameters and their types for WASP. +tags: + - IOTA Node + - Hornet Node + - WASP Node + - Smart Contracts + - L2 + - Configuration + - JSON + - Customize + - Config + - reference +--- + + +# Core Configuration + +WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). + +You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. + +For example: +```shell +wasp -c config_defaults.json +``` + +You can always get the most up-to-date description of the config parameters by running: + +```shell +wasp -h --full +``` + +## 1. Application + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------ | ------- | ------------- | +| checkForUpdates | Whether to check for updates of the application or not | boolean | true | +| [shutdown](#app_shutdown) | Configuration for shutdown | object | | + +### Shutdown + +| Name | Description | Type | Default value | +| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | +| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | + +### Shutdown Log + +| Name | Description | Type | Default value | +| -------- | --------------------------------------------------- | ------- | -------------- | +| enabled | Whether to store self-shutdown events to a log file | boolean | true | +| filePath | The file path to the self-shutdown log | string | "shutdown.log" | + +Example: + +```json + { + "app": { + "checkForUpdates": true, + "shutdown": { + "stopGracePeriod": "5m", + "log": { + "enabled": true, + "filePath": "shutdown.log" + } + } + } + } +``` + +## 2. Logger + +| Name | Description | Type | Default value | +| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | +| level | The minimum enabled logging level | string | "info" | +| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | +| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | +| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | +| encoding | The logger's encoding (options: "json", "console") | string | "console" | +| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | +| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | +| disableEvents | Prevents log messages from being raced as events | boolean | true | + +### EncodingConfig + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | + +Example: + +```json + { + "logger": { + "level": "info", + "disableCaller": true, + "disableStacktrace": false, + "stacktraceLevel": "panic", + "encoding": "console", + "encodingConfig": { + "timeEncoder": "rfc3339" + }, + "outputPaths": [ + "stdout" + ], + "disableEvents": true + } + } +``` + +## 3. INX + +| Name | Description | Type | Default value | +| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | +| address | The INX address to which to connect to | string | "localhost:9029" | +| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | +| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | + +Example: + +```json + { + "inx": { + "address": "localhost:9029", + "maxConnectionAttempts": 30, + "targetNetworkName": "" + } + } +``` + +## 4. Cache + +| Name | Description | Type | Default value | +| ------------------ | -------------------------------------- | ------- | ------------- | +| cacheSize | Cache size | string | "64MiB" | +| cacheStatsInterval | Interval for printing cache statistics | string | "30s" | +| enabled | Whether the cache plugin is enabled | boolean | true | + +Example: + +```json + { + "cache": { + "cacheSize": "64MiB", + "cacheStatsInterval": "30s", + "enabled": true + } + } +``` + +## 5. Database + +| Name | Description | Type | Default value | +| ---------------------------- | ---------------------------------------- | ------- | ------------- | +| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | +| [chainState](#db_chainstate) | Configuration for chainState | object | | +| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | + +### ChainState + +| Name | Description | Type | Default value | +| --------- | -------------------------------------------- | ------ | -------------------- | +| path | The path to the chain state databases folder | string | "waspdb/chains/data" | +| cacheSize | Size of the RocksDB block cache | uint | 33554432 | + +Example: + +```json + { + "db": { + "engine": "rocksdb", + "chainState": { + "path": "waspdb/chains/data", + "cacheSize": 33554432 + }, + "debugSkipHealthCheck": true + } + } +``` + +## 6. P2p + +| Name | Description | Type | Default value | +| ------------------------- | -------------------------- | ------ | ------------- | +| [identity](#p2p_identity) | Configuration for identity | object | | +| [db](#p2p_db) | Configuration for Database | object | | + +### Identity + +| Name | Description | Type | Default value | +| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | +| privateKey | Private key used to derive the node identity (optional) | string | "" | +| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | + +### Database + +| Name | Description | Type | Default value | +| ---- | ---------------------------- | ------ | ----------------- | +| path | The path to the p2p database | string | "waspdb/p2pstore" | + +Example: + +```json + { + "p2p": { + "identity": { + "privateKey": "", + "filePath": "waspdb/identity/identity.key" + }, + "db": { + "path": "waspdb/p2pstore" + } + } + } +``` + +## 7. Registries + +| Name | Description | Type | Default value | +| -------------------------------------------- | -------------------------------- | ------ | ------------- | +| [chains](#registries_chains) | Configuration for chains | object | | +| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | +| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | +| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | + +### Chains + +| Name | Description | Type | Default value | +| -------- | ----------------------------------- | ------ | ----------------------------------- | +| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | + +### DkShares + +| Name | Description | Type | Default value | +| ---- | -------------------------------------------------------- | ------ | ----------------- | +| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | + +### TrustedPeers + +| Name | Description | Type | Default value | +| -------- | ------------------------------------------- | ------ | --------------------------- | +| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | + +### ConsensusState + +| Name | Description | Type | Default value | +| ---- | ------------------------------------------------- | ------ | ------------------------- | +| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | + +Example: + +```json + { + "registries": { + "chains": { + "filePath": "waspdb/chains/chain_registry.json" + }, + "dkShares": { + "path": "waspdb/dkshares" + }, + "trustedPeers": { + "filePath": "waspdb/trusted_peers.json" + }, + "consensusState": { + "path": "waspdb/chains/consensus" + } + } + } +``` + +## 8. Peering + +| Name | Description | Type | Default value | +| ---------- | ---------------------------------------------------- | ------ | -------------- | +| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | +| port | Port for Wasp committee connection/peering | int | 4000 | + +Example: + +```json + { + "peering": { + "peeringURL": "0.0.0.0:4000", + "port": 4000 + } + } +``` + +## 9. Chains + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------- | +| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | +| broadcastInterval | Time between re-broadcast of offledger requests; 0 value means that re-broadcasting is disabled | string | "0s" | +| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | +| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | +| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | +| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | +| postponeRecoveryMilestones | Number of milestones to wait until a chain transition is considered as rejected | int | 3 | +| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | +| recoveryTimeout | Time after which another consensus attempt is made. | string | "20s" | +| redeliveryPeriod | The resend period for msg. | string | "2s" | +| printStatusPeriod | The period to print consensus instance status. | string | "3s" | +| consensusInstsInAdvance | | int | 3 | +| awaitReceiptCleanupEvery | For every this number AwaitReceipt will be cleaned up | int | 100 | +| mempoolTTL | Time that requests are allowed to sit in the mempool without being processed | string | "24h" | +| mempoolMaxOffledgerInPool | Maximum number of off-ledger requests kept in the mempool | int | 2000 | +| mempoolMaxOnledgerInPool | Maximum number of on-ledger requests kept in the mempool | int | 1000 | +| mempoolMaxTimedInPool | Maximum number of timed on-ledger requests kept in the mempool | int | 100 | +| mempoolMaxOffledgerToPropose | Maximum number of off-ledger requests to propose for the next block | int | 500 | +| mempoolMaxOnledgerToPropose | Maximum number of on-ledger requests to propose for the next block (includes timed requests) | int | 100 | +| mempoolOnLedgerRefreshMinInterval | Minimum interval to try to refresh the list of on-ledger requests after some have been dropped from the pool (this interval is introduced to avoid dropping/refreshing cycle if there are too many requests on L1 to process) | string | "10m" | + +Example: + +```json + { + "chains": { + "broadcastUpToNPeers": 2, + "broadcastInterval": "0s", + "apiCacheTTL": "5m", + "pullMissingRequestsFromCommittee": true, + "deriveAliasOutputByQuorum": true, + "pipeliningLimit": -1, + "postponeRecoveryMilestones": 3, + "consensusDelay": "500ms", + "recoveryTimeout": "20s", + "redeliveryPeriod": "2s", + "printStatusPeriod": "3s", + "consensusInstsInAdvance": 3, + "awaitReceiptCleanupEvery": 100, + "mempoolTTL": "24h", + "mempoolMaxOffledgerInPool": 2000, + "mempoolMaxOnledgerInPool": 1000, + "mempoolMaxTimedInPool": 100, + "mempoolMaxOffledgerToPropose": 500, + "mempoolMaxOnledgerToPropose": 100, + "mempoolOnLedgerRefreshMinInterval": "10m" + } + } +``` + +## 10. Snapshots + +| Name | Description | Type | Default value | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| snapshotsToLoad | List of snapshots to load; can be either single block hash of a snapshot (if a single chain has to be configured) or list of `:` to configure many chains | array | | +| period | How often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled" | uint | 0 | +| delay | How many states should pass before snapshot is produced | uint | 20 | +| localPath | The path to the snapshots folder in this node's disk | string | "waspdb/snap" | +| networkPaths | The list of paths to the remote (http(s)) snapshot locations; each of listed locations must contain 'INDEX' file with list of snapshot files | array | | + +Example: + +```json + { + "snapshots": { + "snapshotsToLoad": [], + "period": 0, + "delay": 20, + "localPath": "waspdb/snap", + "networkPaths": [] + } + } +``` + +## 11. StateManager + +| Name | Description | Type | Default value | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | +| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | +| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | +| stateManagerGetBlockNodeCount | How many nodes should get block request be sent to | int | 5 | +| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | +| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "5m" | +| stateManagerStatusLogPeriod | How often state manager status information should be written to log | string | "1m" | +| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | +| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | +| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted; NOTE: pruning takes considerable amount of time; setting this parameter large may seriously damage Wasp responsiveness if many blocks require pruning | int | 10 | + +Example: + +```json + { + "stateManager": { + "blockCacheMaxSize": 1000, + "blockCacheBlocksInCacheDuration": "1h", + "blockCacheBlockCleaningPeriod": "1m", + "stateManagerGetBlockNodeCount": 5, + "stateManagerGetBlockRetry": "3s", + "stateManagerRequestCleaningPeriod": "5m", + "stateManagerStatusLogPeriod": "1m", + "stateManagerTimerTickPeriod": "1s", + "pruningMinStatesToKeep": 10000, + "pruningMaxStatesToDelete": 10 + } + } +``` + +## 12. Validator + +| Name | Description | Type | Default value | +| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | + +Example: + +```json + { + "validator": { + "address": "" + } + } +``` + +## 13. Write-Ahead Logging + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------- | ------- | ------------- | +| loadToStore | Load blocks from "write-ahead log" to the store on node start-up | boolean | false | +| enabled | Whether the "write-ahead logging" is enabled | boolean | true | +| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | + +Example: + +```json + { + "wal": { + "loadToStore": false, + "enabled": true, + "path": "waspdb/wal" + } + } +``` + +## 14. Web API + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------------------------------------------ | ------- | --------------------- | +| enabled | Whether the web api plugin is enabled | boolean | true | +| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | +| [auth](#webapi_auth) | Configuration for auth | object | | +| indexDbPath | Directory for storing indexes of historical data (only archive nodes will create/use them) | string | "waspdb/chains/index" | +| [limits](#webapi_limits) | Configuration for limits | object | | +| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | + +### Auth + +| Name | Description | Type | Default value | +| ----------------------- | -------------------------------------- | ------ | ------------- | +| scheme | Selects which authentication to choose | string | "jwt" | +| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | + +### JWT Auth + +| Name | Description | Type | Default value | +| -------- | ------------------ | ------ | ------------- | +| duration | Jwt token lifetime | string | "24h" | + +### Limits + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------- | ------ | ------------- | +| timeout | The timeout after which a long running operation will be canceled | string | "30s" | +| readTimeout | The read timeout for the HTTP request body | string | "10s" | +| writeTimeout | The write timeout for the HTTP response body | string | "1m" | +| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | +| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | +| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | +| [jsonrpc](#webapi_limits_jsonrpc) | Configuration for jsonrpc | object | | + +### Jsonrpc + +| Name | Description | Type | Default value | +| ----------------------------------- | -------------------------------------------------------------- | ------ | ------------- | +| maxBlocksInLogsFilterRange | Maximum amount of blocks in eth_getLogs filter range | int | 1000 | +| maxLogsInResult | Maximum amount of logs in eth_getLogs result | int | 10000 | +| websocketRateLimitMessagesPerSecond | The websocket rate limit (messages per second) | int | 20 | +| websocketRateLimitBurst | The websocket burst limit | int | 5 | +| websocketConnectionCleanupDuration | Defines in which interval stale connections will be cleaned up | string | "5m" | +| websocketClientBlockDuration | The duration a misbehaving client will be blocked | string | "5m" | + +Example: + +```json + { + "webapi": { + "enabled": true, + "bindAddress": "0.0.0.0:9090", + "auth": { + "scheme": "jwt", + "jwt": { + "duration": "24h" + } + }, + "indexDbPath": "waspdb/chains/index", + "limits": { + "timeout": "30s", + "readTimeout": "10s", + "writeTimeout": "1m", + "maxBodyLength": "2M", + "maxTopicSubscriptionsPerClient": 0, + "confirmedStateLagThreshold": 2, + "jsonrpc": { + "maxBlocksInLogsFilterRange": 1000, + "maxLogsInResult": 10000, + "websocketRateLimitMessagesPerSecond": 20, + "websocketRateLimitBurst": 5, + "websocketConnectionCleanupDuration": "5m", + "websocketClientBlockDuration": "5m" + } + }, + "debugRequestLoggerEnabled": false + } + } +``` + +## 15. Profiling + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------- | ------- | ---------------- | +| enabled | Whether the profiling component is enabled | boolean | false | +| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | + +Example: + +```json + { + "profiling": { + "enabled": false, + "bindAddress": "localhost:6060" + } + } +``` + +## 16. ProfilingRecorder + +| Name | Description | Type | Default value | +| ------- | ----------------------------------------------- | ------- | ------------- | +| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | + +Example: + +```json + { + "profilingRecorder": { + "enabled": false + } + } +``` + +## 17. Prometheus + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------------------ | ------- | -------------- | +| enabled | Whether the prometheus plugin is enabled | boolean | true | +| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | + +Example: + +```json + { + "prometheus": { + "enabled": true, + "bindAddress": "0.0.0.0:2112" + } + } +``` + diff --git a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/metrics.md b/docs/maintain/wasp/v1.1/docs/reference/metrics.md similarity index 96% rename from docs/maintain/wasp/v1.0.0-rc.6/docs/reference/metrics.md rename to docs/maintain/wasp/v1.1/docs/reference/metrics.md index 385ec322f55..0e816a696e0 100644 --- a/docs/maintain/wasp/v1.0.0-rc.6/docs/reference/metrics.md +++ b/docs/maintain/wasp/v1.1/docs/reference/metrics.md @@ -9,7 +9,7 @@ tags: # Exposed Metrics -Refer to the [testnet endpoints description](/build/networks-endpoints/#testnet-evm) for access details. +Refer to the [testnet endpoints description](/build/networks-endpoints/#shimmerevm-testnet) for access details. | Metric | Description | | ------------------------------------------ | ---------------------------------------------------- | diff --git a/docs/maintain/wasp/v1.0.0-rc.6/sidebars.js b/docs/maintain/wasp/v1.1/sidebars.js similarity index 91% rename from docs/maintain/wasp/v1.0.0-rc.6/sidebars.js rename to docs/maintain/wasp/v1.1/sidebars.js index 2613c40e80b..9aec98e9373 100644 --- a/docs/maintain/wasp/v1.0.0-rc.6/sidebars.js +++ b/docs/maintain/wasp/v1.1/sidebars.js @@ -25,6 +25,11 @@ module.exports = { id: 'how-tos/running-a-node', label: 'Run a Node', }, + { + type: 'doc', + id: 'how-tos/running-an-access-node', + label: 'Run an Access Node', + }, { id: 'how-tos/wasp-cli', label: 'Configure wasp-cli', diff --git a/docs/maintain/wasp/v1.3/docs/how-tos/chain-management.md b/docs/maintain/wasp/v1.3/docs/how-tos/chain-management.md new file mode 100644 index 00000000000..b6273d1dd93 --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/how-tos/chain-management.md @@ -0,0 +1,74 @@ +--- +description: 'How to manage a chain using the Grafana dashboard, a client to receive published events, logging, and +validators.' +image: /img/logo/WASP_logo_dark.png +tags: + + - Smart Contracts + - Chain + - Management + - Grafana + +--- + +# Manage a Chain + +## Monitoring + +You can view the chain state using the dashboard (`/wasp/dashboard` when using `node-docker-setup`). + +## Manage Chain Configuration and Validators + +You can manage the chain configuration and committee of validators by interacting with +the [Governance contract](/isc/reference/core-contracts/governance). + +The “Chain Owner” is the only one who can perform administrative tasks. + +### Change Chain Ownership + +To change the chain ownership, the current “Chain Owner” must call `delegateChainOwnership` specifying the `agentID` of +the next owner. The next owner must call `claimChainOwnership` to finalize the process. + +### Change Access Nodes + +For new access nodes to join the network, they need to: + +- Be added as a trusted peer to at least 1 of the existing nodes. +- Be added by the administrator to the list of access nodes by calling `changeAccessNodes`. There is a helper in + wasp-cli to do so: + +```shell +wasp-cli chain gov-change-access-nodes accept +``` + +After this, new nodes should be able to sync the state and execute view queries (call view entry points). + +You can remove an access node by calling `changeAccessNodes`. + +Alternatively, you can add "non-permissioned" access nodes without the signature from the chain owner to add any node as an "access node". +You can do this by using the following command: + +```shell +wasp-cli chain access-nodes +``` + +This node won't be "officially" recognized by the committee but will still be able to sync the state and provide all regular functionality. + +### Change the Set of Validators + +You can do this in different ways, depending on who controls the [governor address](/tips/tips/TIP-0018#alias-output) +from the alias output of the chain. + +- If the chain governor address is the chain committee, you can perform the rotation by calling + `rotateStateController` after adding the next state controller via `addAllowedStateControllerAddress`. +- If the chain governor address is a regular user wallet that you control, you can issue the rotation transaction using wasp-cli: + +```shell +wasp-cli chain rotate +``` + +Or: + +```shell +wasp-cli chain rotate-with-dkg --peers=<...> +``` diff --git a/docs/maintain/wasp/v1.3/docs/how-tos/running-a-node.md b/docs/maintain/wasp/v1.3/docs/how-tos/running-a-node.md new file mode 100644 index 00000000000..79b1f5040f2 --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/how-tos/running-a-node.md @@ -0,0 +1,34 @@ +--- +description: How to run a node. Requirements, configuration parameters, dashboard configuration, and tests. +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Running a node + - Go-lang + - Hornet + - Requirements + - Configuration + - Dashboard + - Grafana + - Prometheus +--- + +# Running a Node + +As Wasp is an INX plugin, you must run the wasp node alongside your _hornet node_. You can use the simple docker-compose setup to do so. + +## Recommended Hardware Requirements + +We recommend that you run the docker image on a server with: + +* **CPU**: 8 core. +* **RAM**: 16 GB. +* **Disk space**: ~ 250 GB SSD, depending on your pruning configuration. + +## Set Up + +Clone and follow the instructions on the [node-docker-setup repo](https://github.com/iotaledger/node-docker-setup). + +:::note +This is aimed at production-ready deployment. If you're looking to spawn a local node for testing/development, please see the [local-setup](https://github.com/iotaledger/wasp/tree/develop/tools/local-setup) +::: diff --git a/docs/maintain/wasp/v1.3/docs/how-tos/running-an-access-node.md b/docs/maintain/wasp/v1.3/docs/how-tos/running-an-access-node.md new file mode 100644 index 00000000000..a12240bda0a --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/how-tos/running-an-access-node.md @@ -0,0 +1,283 @@ +--- +description: How to setup an access node. +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Running a node + - ISC +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Running an ISC Access Node + +## Set Up Wasp and Hornet + +First, you should [set up a Wasp Node](./running-a-node.md) but don't run `docker compose up` to start the docker containers yet. Continue with the following steps first: + +### Download the Chain State + +You can configure how much of the state you wish to keep on your node by uncommenting and changing the `WASP_PRUNING_MIN_STATES_TO_KEEP` environment variable in the node-docker-setup. The default value is 10000 blocks. + +### Run a Non-archive Node + +If you wish to run a non-archive node (only keep the last N blocks), you must uncomment `WASP_SNAPSHOT_NETWORK_PATHS`. + +### Run An Archive Node + +If you wish to have a full archive node, you need to set `WASP_PRUNING_MIN_STATES_TO_KEEP` to `0` and comment `WASP_SNAPSHOT_NETWORK_PATHS` out. + +You can then download the historical state using the following command (this will take a while): + + + + + +```sh +wget https://files.stardust-mainnet.iotaledger.net/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.iota-testnet.iotaledger.net/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +```sh +wget https://files.testnet.shimmer.network/dbs/wasp/latest-wasp_chains_wal.tgz -O - | tar xzv -C data/wasp +``` + + + + +:::note Disk Space + +Operating as a full archive node requires a lot of disk space. We recommend at least 500Gb of free space to operate without issues + +::: + +### Run Everything + +```sh +docker compose up -d +``` + +It will take a few minutes until the hornet node is synced. + +You can check the sync status by following the logs with `docker logs -f hornet`, or in the web dashboard. + +## Use Wasp-Cli to configure the chain and add peers +### Download Wasp-Cli + +You can download a Wasp-Cli that matches your Wasp version from the [Wasp releases](https://github.com/iotaledger/wasp/releases). +You can use a commands like the following to for example download version 1.1.0: + +```sh +curl -sL https://github.com/iotaledger/wasp/releases/download/v1.1.0/wasp-cli_1.1.0_Linux_x86_64.tar.gz | tar xzv +``` + +Change directory into the newly-downloaded `wasp-cli` directory: + +```sh +cd wasp-cli_1.1.0_Linux_x86_64/ +``` + +### Set the L1 API Address + +Set the L1 API address. You can set it to what you configured as `NODE_HOST` in the `.env` file + +:::tip HTTP + +If you use the http setup, don't forget to replace `https` with `http` + +::: + +```sh +./wasp-cli set l1.apiaddress https://{NODE_HOST} +``` + +### Set Wasp API Address + +Set the WASP API address. It is your configured `NODE_HOST` and the `/wasp/api` path. + +```sh +./wasp-cli wasp add my-node https://{NODE_HOST}/wasp/api +``` + +### Login + +Login to wasp using your credentials. You can update your current credentials or add new ones in the wasp dashboard. + +```sh +./wasp-cli login +``` +```sh title=Output +Username: wasp +Password: (default is wasp) +Successfully authenticated +``` + +### Obtain Peering Info + +Get your peering info which you will need to share with your peers: + +```sh +./wasp-cli peering info +``` +```sh title=Output +PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 +PeeringURL: 0.0.0.0:4000 +``` + +Please note the PubKey: 0x20a56daa0b5e86b196c37f802089a2b6007a655a12337d287f7313a214af2ec0 output. +Send it together with your domain/IP to node operators that you want to peer with. + +### Wait for the other party to peer + +Wait until peer added you as trusted and access peer. + +### Use wasp-cli to add nodes as peers + +Now you can add your peer as trusted peer. + +```sh +./wasp-cli peering trust peer1 : +./wasp-cli peering trust peer2 : +``` + +### Add Chain + +Add the chain with its chain id and name: + + + + +```sh +./wasp-cli chain add iota-evm iota1pzt3mstq6khgc3tl0mwuzk3eqddkryqnpdxmk4nr25re2466uxwm28qqxu5 +``` + + + + +```sh +./wasp-cli chain add iota-evm-testnet tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu +``` + + + + +```sh +./wasp-cli chain add shimmer-evm smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s +``` + + + + +```sh +./wasp-cli chain add shimmer-evm-testnet rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex +``` + + + + +### Activate + +Activate the chain using its name: + + + + + +```sh +./wasp-cli chain activate --chain iota-evm +``` + + + + +```sh +./wasp-cli chain activate --chain iota-evm-testnet +``` + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm +``` + + + + +```sh +./wasp-cli chain activate --chain shimmer-evm-testnet +``` + + + + +### Add Peers as Access Nodes of the Chain + +Add the peers as access nodes. + +:::info + +This is normally only needed for peers that you plan to add as access nodes to your own node + +::: + +```sh +./wasp-cli chain access-nodes add --peers=peer1,peer2 +``` + +### Check if Wasp Synced + +You can follow the progress using `docker logs -f wasp`. If you chose to create a [full-archive node](#run-and-archive-node), this can take several minutes, maybe hours. + +### Test Your Endpoint + +You should have a working EVM JSON-RPC endpoint on: + + + + +``` +/wasp/api/v1/chains/iota1pzt3mstq6khgc3tl0mwuzk3eqddkryqnpdxmk4nr25re2466uxwm28qqxu5/evm +``` + + + + +``` +/wasp/api/v1/chains/tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu/evm +``` + + + + + +``` +/wasp/api/v1/chains/smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s/evm +``` + + + + +``` +/wasp/api/v1/chains/rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex/evm +``` + + + diff --git a/docs/maintain/wasp/v1.3/docs/how-tos/setting-up-a-chain.md b/docs/maintain/wasp/v1.3/docs/how-tos/setting-up-a-chain.md new file mode 100644 index 00000000000..d71c78d5372 --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/how-tos/setting-up-a-chain.md @@ -0,0 +1,176 @@ +--- +description: 'Setting up a chain: requirements, configuration parameters, validators, and tests.' +image: /img/logo/WASP_logo_dark.png +tags: + - Smart Contracts + - Chain + - Set up + - Configuration + - Nodes + - Tests +--- + +# Set Up a Chain + +:::note + +It is possible to run a "committee" of a single Wasp node, which is okay for testing purposes. + +However, in normal operation, multiple Wasp _nodes_ should be used. + +::: + +## Requirements + +- [`wasp-cli` configured](wasp-cli.md) to interact with your wasp node. + +## Trust Setup + +After starting all the `wasp` nodes, you should make them trust each other. Node operators should do this manually. It's +their responsibility to accept trusted nodes only. + +The operator can read their node's public key and PeeringURL by running `wasp-cli peering info`: + +```shell +wasp-cli peering info +``` + +Example response: + +```log +PubKey: 8oQ9xHWvfnShRxB22avvjbMyAumZ7EXKujuthqrzapNM +PeeringURL: 127.0.0.1:4000 +``` + +You should provide your `PubKey` and `PeeringURL` to other node operators. +They can use this info to trust and accept communications with your node. +That's done by invoking `wasp-cli peering trust `, e.g.: + +```shell +wasp-cli peering trust another-node 8oQ9xHWvfnShRxB22avvjbMyAumZ7EXKujuthqrzapNM 127.0.0.1:4000 +``` + +You can view the list of your wasp node's trusted peers by calling: + +```shell +wasp-cli peering list-trusted +``` + +All the nodes in a committee must trust each other to run the chain. + +## Start the Chain + +### Request Test Funds (only for Testnet) + +You can request test funds to safely develop your application by calling: + +```shell +wasp-cli request-funds +``` + +### Deploy the IOTA Smart Contracts Chain + +You can deploy your IOTA Smart Contracts chain by running: + +```shell +wasp-cli chain deploy --peers=foo,bar,baz --chain=mychain --block-keep-amount=10000 +``` + +The names in `--peers=foo,bar,baz` correspond to the names of the node's trusted peers. + +The `--chain=mychain` flag sets up an alias for the chain. +From now on, all chain commands will target this chain. + +The `--quorum` flag indicates the minimum number of nodes required to form a _consensus_. +The recommended formula to obtain this number is `floor(N*2/3)+1` where `N` is the number of nodes in your committee. + +The `--block-keep-amount` parameter determines how many blocks are stored in the [`blocklog`](/isc/reference/core-contracts/blocklog) core contract. + +After deployment, the chain must be activated by the node operators of all peers. + +```shell +wasp-cli chain add # adds the chain to the wasp-cli config, can be skipped on the wasp-cli that initiated the deployment +wasp-cli chain activate --chain= +``` + +## Test If It Works + +You can check that the chain was deployed correctly in the Wasp node dashboard (`/wasp/dashboard` when using `node-docker-setup`). +Note that the chain was deployed with some [core contracts](/isc/reference/core-contracts/overview). + +You should also have an EVM-JSONRPC server opened on: + +```info +/chain//evm +``` + +### Deploying a Wasm Contract + +:::warning +The WASM _VM_ is experimental. However, similar commands can be used to interact with the core contracts +::: + +Now you can deploy a Wasm contract to the chain: + +```shell +wasp-cli chain deploy-contract wasmtime inccounter "inccounter SC" tools/cluster/tests/wasm/inccounter_bg.wasm +``` + +The `inccounter_bg.wasm` file is a precompiled Wasm contract included in the Wasp repo as an example. + +If you recheck the dashboard, you should see that the `inccounter` contract is listed in the chain. + +### Interacting With a Smart Contract + +You can interact with a contract by calling its exposed functions and views. + +For instance, the [`inccounter`](https://github.com/iotaledger/wasp/tree/master/contracts/wasm/inccounter/src) contract +exposes the `increment` function, which simply increments a counter stored in the state. It also has the `getCounter` +view that returns the current value of the counter. + +You can call the `getCounter` view by running: + +```shell +wasp-cli chain call-view inccounter getCounter | wasp-cli decode string counter int +``` + +Example response: + +```log +counter: 0 +``` + +:::note + +The part after `|` is necessary because the return value is encoded, and you need to know the _schema_ to +decode it. **The schema definition is in its early stages and will likely change in the future.** + +::: + +You can now call the `increment` function by running: + +```shell +wasp-cli chain post-request inccounter increment +``` + +After the committee has processed the request, you should get a new +counter value after calling `getCounter`: + +```shell +wasp-cli chain call-view inccounter getCounter | wasp-cli decode string counter int +``` + +Example response: + +```log +counter: 1 +``` + +### Troubleshooting + +Common issues can be caused by using an incompatible version of `wasp` / `wasp-cli`. +You can verify that `wasp-cli` and `wasp` nodes are on the same version by running: + +```shell +wasp-cli check-versions +``` diff --git a/docs/maintain/wasp/v1.3/docs/how-tos/wasp-cli.md b/docs/maintain/wasp/v1.3/docs/how-tos/wasp-cli.md new file mode 100644 index 00000000000..a09445e0aaf --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/how-tos/wasp-cli.md @@ -0,0 +1,67 @@ +--- +description: How to configure wasp-cli. Requirements and configuration parameters. +image: /img/logo/WASP_logo_dark.png +tags: + - Wasp-cli + - Configuration + - Hornet + - command line +--- + +# Configure wasp-cli + +You can use these step-by-step instructions on how to use wasp-cli to interact with Wasp nodes on the Hornet network. + +## Download wasp-cli + +Download the latest wasp-cli binary from the repo [releases page](https://github.com/iotaledger/wasp/releases). +(For ease of use, it is recommended to add `wasp-cli` to your system `PATH`). + +## Configuration + +You can create a basic default configuration by running: + +```shell +wasp-cli init +``` + +This command will create a configuration file named `wasp-cli.json` in `~/.wasp-cli/wasp-cli.json` (you can change the default with the `-c, --config` flag). + +:::info Wallet Provider + +By default wasp-cli will store the seed in your OS keychain. You can change this behavior by running + +```shell +wasp-cli wallet-provider (keychain, sdk_ledger, sdk_stronghold) [flags] +``` + +::: + +:::info Deprecated Seed storage + +If you use a version older then [1.0.3](https://github.com/iotaledger/wasp/releases/tag/v1.0.3-alpha.1) your seed is still stored as plain text. You can migrate to the keychain by using the following command: + +```shell +wasp-cli wallet-migrate (keychain) [flags] +``` + +::: + +After this, you will need to tell the `wasp-cli` the location of the _Hornet node_ and the committee of Wasp nodes: + +```shell +wasp-cli set l1.apiaddress http://localhost:14265 +# the faucet only exists for test networks +wasp-cli set l1.faucetaddress http://localhost:8091 + +# You can add as many nodes as you'd like +wasp-cli wasp add wasp-0 127.0.0.1:9090 +wasp-cli wasp add wasp-1 127.0.0.1:9091 +``` + +If you configure the Wasp node to use JWT authentication, you will need to log in +after you save the configuration. + +```shell +wasp-cli login +``` diff --git a/docs/maintain/wasp/v1.3/docs/reference/configuration.md b/docs/maintain/wasp/v1.3/docs/reference/configuration.md new file mode 100755 index 00000000000..bfe1181b5b5 --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/reference/configuration.md @@ -0,0 +1,573 @@ +--- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app. +description: This section describes the configuration parameters and their types for WASP. +tags: + - IOTA Node + - Hornet Node + - WASP Node + - Smart Contracts + - L2 + - Configuration + - JSON + - Customize + - Config + - reference +--- + + +# Core Configuration + +WASP uses a JSON standard format as a config file. If you are unsure about JSON syntax, you can find more information in the [official JSON specs](https://www.json.org). + +You can change the path of the config file by using the `-c` or `--config` argument while executing `wasp` executable. + +For example: +```shell +wasp -c config_defaults.json +``` + +You can always get the most up-to-date description of the config parameters by running: + +```shell +wasp -h --full +``` + +## 1. Application + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------ | ------- | ------------- | +| checkForUpdates | Whether to check for updates of the application or not | boolean | true | +| [shutdown](#app_shutdown) | Configuration for shutdown | object | | + +### Shutdown + +| Name | Description | Type | Default value | +| ------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| stopGracePeriod | The maximum time to wait for background processes to finish during shutdown before terminating the app | string | "5m" | +| [log](#app_shutdown_log) | Configuration for Shutdown Log | object | | + +### Shutdown Log + +| Name | Description | Type | Default value | +| -------- | --------------------------------------------------- | ------- | -------------- | +| enabled | Whether to store self-shutdown events to a log file | boolean | true | +| filePath | The file path to the self-shutdown log | string | "shutdown.log" | + +Example: + +```json + { + "app": { + "checkForUpdates": true, + "shutdown": { + "stopGracePeriod": "5m", + "log": { + "enabled": true, + "filePath": "shutdown.log" + } + } + } + } +``` + +## 2. Logger + +| Name | Description | Type | Default value | +| ---------------------------------------- | --------------------------------------------------------------------------- | ------- | ------------- | +| level | The minimum enabled logging level | string | "info" | +| disableCaller | Stops annotating logs with the calling function's file name and line number | boolean | true | +| disableStacktrace | Disables automatic stacktrace capturing | boolean | false | +| stacktraceLevel | The level stacktraces are captured and above | string | "panic" | +| encoding | The logger's encoding (options: "json", "console") | string | "console" | +| [encodingConfig](#logger_encodingconfig) | Configuration for encodingConfig | object | | +| outputPaths | A list of URLs, file paths or stdout/stderr to write logging output to | array | stdout | +| disableEvents | Prevents log messages from being raced as events | boolean | true | + +### EncodingConfig + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| timeEncoder | Sets the logger's timestamp encoding. (options: "nanos", "millis", "iso8601", "rfc3339" and "rfc3339nano") | string | "rfc3339" | + +Example: + +```json + { + "logger": { + "level": "info", + "disableCaller": true, + "disableStacktrace": false, + "stacktraceLevel": "panic", + "encoding": "console", + "encodingConfig": { + "timeEncoder": "rfc3339" + }, + "outputPaths": [ + "stdout" + ], + "disableEvents": true + } + } +``` + +## 3. INX + +| Name | Description | Type | Default value | +| --------------------- | -------------------------------------------------------------------------------------------------- | ------ | ---------------- | +| address | The INX address to which to connect to | string | "localhost:9029" | +| maxConnectionAttempts | The amount of times the connection to INX will be attempted before it fails (1 attempt per second) | uint | 30 | +| targetNetworkName | The network name on which the node should operate on (optional) | string | "" | + +Example: + +```json + { + "inx": { + "address": "localhost:9029", + "maxConnectionAttempts": 30, + "targetNetworkName": "" + } + } +``` + +## 4. Cache + +| Name | Description | Type | Default value | +| ------------------ | -------------------------------------- | ------- | ------------- | +| cacheSize | Cache size | string | "64MiB" | +| cacheStatsInterval | Interval for printing cache statistics | string | "30s" | +| enabled | Whether the cache plugin is enabled | boolean | true | + +Example: + +```json + { + "cache": { + "cacheSize": "64MiB", + "cacheStatsInterval": "30s", + "enabled": true + } + } +``` + +## 5. Database + +| Name | Description | Type | Default value | +| ---------------------------- | ---------------------------------------- | ------- | ------------- | +| engine | The used database engine (rocksdb/mapdb) | string | "rocksdb" | +| [chainState](#db_chainstate) | Configuration for chainState | object | | +| debugSkipHealthCheck | Ignore the check for corrupted databases | boolean | true | + +### ChainState + +| Name | Description | Type | Default value | +| --------- | -------------------------------------------- | ------ | -------------------- | +| path | The path to the chain state databases folder | string | "waspdb/chains/data" | +| cacheSize | Size of the RocksDB block cache | uint | 33554432 | + +Example: + +```json + { + "db": { + "engine": "rocksdb", + "chainState": { + "path": "waspdb/chains/data", + "cacheSize": 33554432 + }, + "debugSkipHealthCheck": true + } + } +``` + +## 6. P2p + +| Name | Description | Type | Default value | +| ------------------------- | -------------------------- | ------ | ------------- | +| [identity](#p2p_identity) | Configuration for identity | object | | +| [db](#p2p_db) | Configuration for Database | object | | + +### Identity + +| Name | Description | Type | Default value | +| ---------- | ------------------------------------------------------- | ------ | ------------------------------ | +| privateKey | Private key used to derive the node identity (optional) | string | "" | +| filePath | The path to the node identity PEM file | string | "waspdb/identity/identity.key" | + +### Database + +| Name | Description | Type | Default value | +| ---- | ---------------------------- | ------ | ----------------- | +| path | The path to the p2p database | string | "waspdb/p2pstore" | + +Example: + +```json + { + "p2p": { + "identity": { + "privateKey": "", + "filePath": "waspdb/identity/identity.key" + }, + "db": { + "path": "waspdb/p2pstore" + } + } + } +``` + +## 7. Registries + +| Name | Description | Type | Default value | +| -------------------------------------------- | -------------------------------- | ------ | ------------- | +| [chains](#registries_chains) | Configuration for chains | object | | +| [dkShares](#registries_dkshares) | Configuration for dkShares | object | | +| [trustedPeers](#registries_trustedpeers) | Configuration for trustedPeers | object | | +| [consensusState](#registries_consensusstate) | Configuration for consensusState | object | | + +### Chains + +| Name | Description | Type | Default value | +| -------- | ----------------------------------- | ------ | ----------------------------------- | +| filePath | The path to the chain registry file | string | "waspdb/chains/chain_registry.json" | + +### DkShares + +| Name | Description | Type | Default value | +| ---- | -------------------------------------------------------- | ------ | ----------------- | +| path | The path to the distributed key shares registries folder | string | "waspdb/dkshares" | + +### TrustedPeers + +| Name | Description | Type | Default value | +| -------- | ------------------------------------------- | ------ | --------------------------- | +| filePath | The path to the trusted peers registry file | string | "waspdb/trusted_peers.json" | + +### ConsensusState + +| Name | Description | Type | Default value | +| ---- | ------------------------------------------------- | ------ | ------------------------- | +| path | The path to the consensus state registries folder | string | "waspdb/chains/consensus" | + +Example: + +```json + { + "registries": { + "chains": { + "filePath": "waspdb/chains/chain_registry.json" + }, + "dkShares": { + "path": "waspdb/dkshares" + }, + "trustedPeers": { + "filePath": "waspdb/trusted_peers.json" + }, + "consensusState": { + "path": "waspdb/chains/consensus" + } + } + } +``` + +## 8. Peering + +| Name | Description | Type | Default value | +| ---------- | ---------------------------------------------------- | ------ | -------------- | +| peeringURL | Node host address as it is recognized by other peers | string | "0.0.0.0:4000" | +| port | Port for Wasp committee connection/peering | int | 4000 | + +Example: + +```json + { + "peering": { + "peeringURL": "0.0.0.0:4000", + "port": 4000 + } + } +``` + +## 9. Chains + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------- | +| broadcastUpToNPeers | Number of peers an offledger request is broadcasted to | int | 2 | +| broadcastInterval | Time between re-broadcast of offledger requests; 0 value means that re-broadcasting is disabled | string | "0s" | +| apiCacheTTL | Time to keep processed offledger requests in api cache | string | "5m" | +| pullMissingRequestsFromCommittee | Whether or not to pull missing requests from other committee members | boolean | true | +| deriveAliasOutputByQuorum | False means we propose own AliasOutput, true - by majority vote. | boolean | true | +| pipeliningLimit | -1 -- infinite, 0 -- disabled, X -- build the chain if there is up to X transactions unconfirmed by L1. | int | -1 | +| postponeRecoveryMilestones | Number of milestones to wait until a chain transition is considered as rejected | int | 3 | +| consensusDelay | Minimal delay between consensus runs. | string | "500ms" | +| recoveryTimeout | Time after which another consensus attempt is made. | string | "20s" | +| redeliveryPeriod | The resend period for msg. | string | "2s" | +| printStatusPeriod | The period to print consensus instance status. | string | "3s" | +| consensusInstsInAdvance | | int | 3 | +| awaitReceiptCleanupEvery | For every this number AwaitReceipt will be cleaned up | int | 100 | +| mempoolTTL | Time that requests are allowed to sit in the mempool without being processed | string | "24h" | +| mempoolMaxOffledgerInPool | Maximum number of off-ledger requests kept in the mempool | int | 2000 | +| mempoolMaxOnledgerInPool | Maximum number of on-ledger requests kept in the mempool | int | 1000 | +| mempoolMaxTimedInPool | Maximum number of timed on-ledger requests kept in the mempool | int | 100 | +| mempoolMaxOffledgerToPropose | Maximum number of off-ledger requests to propose for the next block | int | 500 | +| mempoolMaxOnledgerToPropose | Maximum number of on-ledger requests to propose for the next block (includes timed requests) | int | 100 | +| mempoolOnLedgerRefreshMinInterval | Minimum interval to try to refresh the list of on-ledger requests after some have been dropped from the pool (this interval is introduced to avoid dropping/refreshing cycle if there are too many requests on L1 to process) | string | "10m" | + +Example: + +```json + { + "chains": { + "broadcastUpToNPeers": 2, + "broadcastInterval": "0s", + "apiCacheTTL": "5m", + "pullMissingRequestsFromCommittee": true, + "deriveAliasOutputByQuorum": true, + "pipeliningLimit": -1, + "postponeRecoveryMilestones": 3, + "consensusDelay": "500ms", + "recoveryTimeout": "20s", + "redeliveryPeriod": "2s", + "printStatusPeriod": "3s", + "consensusInstsInAdvance": 3, + "awaitReceiptCleanupEvery": 100, + "mempoolTTL": "24h", + "mempoolMaxOffledgerInPool": 2000, + "mempoolMaxOnledgerInPool": 1000, + "mempoolMaxTimedInPool": 100, + "mempoolMaxOffledgerToPropose": 500, + "mempoolMaxOnledgerToPropose": 100, + "mempoolOnLedgerRefreshMinInterval": "10m" + } + } +``` + +## 10. Snapshots + +| Name | Description | Type | Default value | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | +| snapshotsToLoad | List of snapshots to load; can be either single block hash of a snapshot (if a single chain has to be configured) or list of `:` to configure many chains | array | | +| period | How often state snapshots should be made: 1000 meaning "every 1000th state", 0 meaning "making snapshots is disabled" | uint | 0 | +| delay | How many states should pass before snapshot is produced | uint | 20 | +| localPath | The path to the snapshots folder in this node's disk | string | "waspdb/snap" | +| networkPaths | The list of paths to the remote (http(s)) snapshot locations; each of listed locations must contain 'INDEX' file with list of snapshot files | array | | + +Example: + +```json + { + "snapshots": { + "snapshotsToLoad": [], + "period": 0, + "delay": 20, + "localPath": "waspdb/snap", + "networkPaths": [] + } + } +``` + +## 11. StateManager + +| Name | Description | Type | Default value | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| blockCacheMaxSize | How many blocks may be stored in cache before old ones start being deleted | int | 1000 | +| blockCacheBlocksInCacheDuration | How long should the block stay in block cache before being deleted | string | "1h" | +| blockCacheBlockCleaningPeriod | How often should the block cache be cleaned | string | "1m" | +| stateManagerGetBlockNodeCount | How many nodes should get block request be sent to | int | 5 | +| stateManagerGetBlockRetry | How often get block requests should be repeated | string | "3s" | +| stateManagerRequestCleaningPeriod | How often requests waiting for response should be checked for expired context | string | "5m" | +| stateManagerStatusLogPeriod | How often state manager status information should be written to log | string | "1m" | +| stateManagerTimerTickPeriod | How often timer tick fires in state manager | string | "1s" | +| pruningMinStatesToKeep | This number of states will always be available in the store; if 0 - store pruning is disabled | int | 10000 | +| pruningMaxStatesToDelete | On single store pruning attempt at most this number of states will be deleted; NOTE: pruning takes considerable amount of time; setting this parameter large may seriously damage Wasp responsiveness if many blocks require pruning | int | 10 | + +Example: + +```json + { + "stateManager": { + "blockCacheMaxSize": 1000, + "blockCacheBlocksInCacheDuration": "1h", + "blockCacheBlockCleaningPeriod": "1m", + "stateManagerGetBlockNodeCount": 5, + "stateManagerGetBlockRetry": "3s", + "stateManagerRequestCleaningPeriod": "5m", + "stateManagerStatusLogPeriod": "1m", + "stateManagerTimerTickPeriod": "1s", + "pruningMinStatesToKeep": 10000, + "pruningMaxStatesToDelete": 10 + } + } +``` + +## 12. Validator + +| Name | Description | Type | Default value | +| ------- | ------------------------------------------------------------------------------------------------------------------ | ------ | ------------- | +| address | Bech32 encoded address to identify the node (as access node on gov contract and to collect validator fee payments) | string | "" | + +Example: + +```json + { + "validator": { + "address": "" + } + } +``` + +## 13. Write-Ahead Logging + +| Name | Description | Type | Default value | +| ----------- | ---------------------------------------------------------------- | ------- | ------------- | +| loadToStore | Load blocks from "write-ahead log" to the store on node start-up | boolean | false | +| enabled | Whether the "write-ahead logging" is enabled | boolean | true | +| path | The path to the "write-ahead logging" folder | string | "waspdb/wal" | + +Example: + +```json + { + "wal": { + "loadToStore": false, + "enabled": true, + "path": "waspdb/wal" + } + } +``` + +## 14. Web API + +| Name | Description | Type | Default value | +| ------------------------- | ------------------------------------------------------------------------------------------ | ------- | --------------------- | +| enabled | Whether the web api plugin is enabled | boolean | true | +| bindAddress | The bind address for the node web api | string | "0.0.0.0:9090" | +| [auth](#webapi_auth) | Configuration for auth | object | | +| indexDbPath | Directory for storing indexes of historical data (only archive nodes will create/use them) | string | "waspdb/chains/index" | +| [limits](#webapi_limits) | Configuration for limits | object | | +| debugRequestLoggerEnabled | Whether the debug logging for requests should be enabled | boolean | false | + +### Auth + +| Name | Description | Type | Default value | +| ----------------------- | -------------------------------------- | ------ | ------------- | +| scheme | Selects which authentication to choose | string | "jwt" | +| [jwt](#webapi_auth_jwt) | Configuration for JWT Auth | object | | + +### JWT Auth + +| Name | Description | Type | Default value | +| -------- | ------------------ | ------ | ------------- | +| duration | Jwt token lifetime | string | "24h" | + +### Limits + +| Name | Description | Type | Default value | +| --------------------------------- | ----------------------------------------------------------------------------- | ------ | ------------- | +| timeout | The timeout after which a long running operation will be canceled | string | "30s" | +| readTimeout | The read timeout for the HTTP request body | string | "10s" | +| writeTimeout | The write timeout for the HTTP response body | string | "1m" | +| maxBodyLength | The maximum number of characters that the body of an API call may contain | string | "2M" | +| maxTopicSubscriptionsPerClient | Defines the max amount of subscriptions per client. 0 = deactivated (default) | int | 0 | +| confirmedStateLagThreshold | The threshold that define a chain is unsynchronized | uint | 2 | +| [jsonrpc](#webapi_limits_jsonrpc) | Configuration for jsonrpc | object | | + +### Jsonrpc + +| Name | Description | Type | Default value | +| ----------------------------------- | -------------------------------------------------------------- | ------ | ------------- | +| maxBlocksInLogsFilterRange | Maximum amount of blocks in eth_getLogs filter range | int | 1000 | +| maxLogsInResult | Maximum amount of logs in eth_getLogs result | int | 10000 | +| websocketRateLimitMessagesPerSecond | The websocket rate limit (messages per second) | int | 20 | +| websocketRateLimitBurst | The websocket burst limit | int | 5 | +| websocketConnectionCleanupDuration | Defines in which interval stale connections will be cleaned up | string | "5m" | +| websocketClientBlockDuration | The duration a misbehaving client will be blocked | string | "5m" | + +Example: + +```json + { + "webapi": { + "enabled": true, + "bindAddress": "0.0.0.0:9090", + "auth": { + "scheme": "jwt", + "jwt": { + "duration": "24h" + } + }, + "indexDbPath": "waspdb/chains/index", + "limits": { + "timeout": "30s", + "readTimeout": "10s", + "writeTimeout": "1m", + "maxBodyLength": "2M", + "maxTopicSubscriptionsPerClient": 0, + "confirmedStateLagThreshold": 2, + "jsonrpc": { + "maxBlocksInLogsFilterRange": 1000, + "maxLogsInResult": 10000, + "websocketRateLimitMessagesPerSecond": 20, + "websocketRateLimitBurst": 5, + "websocketConnectionCleanupDuration": "5m", + "websocketClientBlockDuration": "5m" + } + }, + "debugRequestLoggerEnabled": false + } + } +``` + +## 15. Profiling + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------- | ------- | ---------------- | +| enabled | Whether the profiling component is enabled | boolean | false | +| bindAddress | The bind address on which the profiler listens on | string | "localhost:6060" | + +Example: + +```json + { + "profiling": { + "enabled": false, + "bindAddress": "localhost:6060" + } + } +``` + +## 16. ProfilingRecorder + +| Name | Description | Type | Default value | +| ------- | ----------------------------------------------- | ------- | ------------- | +| enabled | Whether the ProfilingRecorder plugin is enabled | boolean | false | + +Example: + +```json + { + "profilingRecorder": { + "enabled": false + } + } +``` + +## 17. Prometheus + +| Name | Description | Type | Default value | +| ----------- | ------------------------------------------------------------ | ------- | -------------- | +| enabled | Whether the prometheus plugin is enabled | boolean | true | +| bindAddress | The bind address on which the Prometheus exporter listens on | string | "0.0.0.0:2112" | + +Example: + +```json + { + "prometheus": { + "enabled": true, + "bindAddress": "0.0.0.0:2112" + } + } +``` + diff --git a/docs/maintain/wasp/v1.3/docs/reference/metrics.md b/docs/maintain/wasp/v1.3/docs/reference/metrics.md new file mode 100644 index 00000000000..0e816a696e0 --- /dev/null +++ b/docs/maintain/wasp/v1.3/docs/reference/metrics.md @@ -0,0 +1,22 @@ +--- +description: IOTA Smart Contract Protocol is IOTA's solution for running smart contracts on top of the IOTA _tangle_. +image: /img/logo/WASP_logo_dark.png +tags: + - smart contracts + - metrics + - reference +--- + +# Exposed Metrics + +Refer to the [testnet endpoints description](/build/networks-endpoints/#shimmerevm-testnet) for access details. + +| Metric | Description | +| ------------------------------------------ | ---------------------------------------------------- | +| `wasp_off_ledger_requests_counter` | Off-ledger requests per chain. | +| `wasp_on_ledger_request_counter` | On-ledger requests per chain. | +| `wasp_processed_request_counter` | Total number of requests processed. | +| `messages_received_per_chain` | Number of messages received per chain. | +| `receive_requests_acknowledgement_message` | Number of request acknowledgment messages per chain. | +| `request_processing_time` | Time to process request. | +| `vm_run_time` | Time it takes to run the VM. | diff --git a/docs/maintain/wasp/v1.3/sidebars.js b/docs/maintain/wasp/v1.3/sidebars.js new file mode 100644 index 00000000000..9aec98e9373 --- /dev/null +++ b/docs/maintain/wasp/v1.3/sidebars.js @@ -0,0 +1,65 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + //tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + waspSidebar: [ + { + type: 'category', + label: 'How To', + collapsed: false, + items: [ + { + type: 'doc', + id: 'how-tos/running-a-node', + label: 'Run a Node', + }, + { + type: 'doc', + id: 'how-tos/running-an-access-node', + label: 'Run an Access Node', + }, + { + id: 'how-tos/wasp-cli', + label: 'Configure wasp-cli', + type: 'doc', + }, + { + id: 'how-tos/setting-up-a-chain', + label: 'Set Up a Chain', + type: 'doc', + }, + { + id: 'how-tos/chain-management', + label: 'Manage a Chain', + type: 'doc', + }, + ], + }, + { + type: 'category', + label: 'Reference', + items: [ + { + type: 'doc', + id: 'reference/configuration', + }, + { + type: 'doc', + id: 'reference/metrics', + }, + ], + }, + ], +}; diff --git a/tutorials/pages/create-nft-with-iota-sdk.md b/docs/tutorials/create-nft-with-iota-sdk.md similarity index 99% rename from tutorials/pages/create-nft-with-iota-sdk.md rename to docs/tutorials/create-nft-with-iota-sdk.md index 4f6fd843b15..f168b0a9bb1 100644 --- a/tutorials/pages/create-nft-with-iota-sdk.md +++ b/docs/tutorials/create-nft-with-iota-sdk.md @@ -58,7 +58,7 @@ Add your desired `*.jpg` file to the `wallet-setup` folder you created and renam For this tutorial we'll use the following image: -![NFT Image](/nft-image.jpg) +![NFT Image](/img/tutorials/nft-image.jpg) --- diff --git a/tutorials/pages/hornet-inx-interaction.md b/docs/tutorials/hornet-inx-interaction.md similarity index 100% rename from tutorials/pages/hornet-inx-interaction.md rename to docs/tutorials/hornet-inx-interaction.md diff --git a/tutorials/pages/proof-inclusion-of-a-block.md b/docs/tutorials/proof-inclusion-of-a-block.md similarity index 99% rename from tutorials/pages/proof-inclusion-of-a-block.md rename to docs/tutorials/proof-inclusion-of-a-block.md index 6081099142f..4721c1e0f08 100644 --- a/tutorials/pages/proof-inclusion-of-a-block.md +++ b/docs/tutorials/proof-inclusion-of-a-block.md @@ -16,7 +16,7 @@ Since the pattern assumes trusted access to the network, we recommend that both Please note that this pattern does not rely on a Permanode storing the entire Tangle history, as it was the case in almost all data-related use cases in the past. In comparison to a Permanode, storing selected blocks with their proof of inclusion to the Tangle, drastically reduces the node operator's storage requirements. -![PoI-Architecture](/proof-inclusion-of-a-block-architecture.png) +![PoI-Architecture](/img/tutorials/proof-inclusion-of-a-block-architecture.png) --- diff --git a/tutorials/pages/send-shimmer-tokens-with-iota-sdk.md b/docs/tutorials/send-shimmer-tokens-with-iota-sdk.md similarity index 100% rename from tutorials/pages/send-shimmer-tokens-with-iota-sdk.md rename to docs/tutorials/send-shimmer-tokens-with-iota-sdk.md diff --git a/tutorials/pages/setup_iota-js_for_development.md b/docs/tutorials/setup_iota-js_for_development.md similarity index 98% rename from tutorials/pages/setup_iota-js_for_development.md rename to docs/tutorials/setup_iota-js_for_development.md index 7dcb438432b..609fde90eec 100644 --- a/tutorials/pages/setup_iota-js_for_development.md +++ b/docs/tutorials/setup_iota-js_for_development.md @@ -180,7 +180,7 @@ Now, you can go to the [Shimmer Testnet Faucet Website](https://faucet.testnet.s The 'Request' button will become clickable as soon as a valid Shimmer address is recognized. ::: -![Shimmer Testnet Faucet](/shimmer-testnet-faucet.png) +![Shimmer Testnet Faucet](/img/tutorials/shimmer-testnet-faucet.png) --- diff --git a/tutorials/pages/shimmerevm-dapp-voting.md b/docs/tutorials/shimmerevm-dapp-voting.md similarity index 99% rename from tutorials/pages/shimmerevm-dapp-voting.md rename to docs/tutorials/shimmerevm-dapp-voting.md index 88a3e027241..13c05346b53 100644 --- a/tutorials/pages/shimmerevm-dapp-voting.md +++ b/docs/tutorials/shimmerevm-dapp-voting.md @@ -337,4 +337,4 @@ let tx = contractSigner.vote(i); ## Result If you followed everything above, it should look something like this: -![Voting Demo](/voting-dapp.jpg 'Voting dApp UI') +![Voting Demo](/img/tutorials/voting-dapp.jpg 'Voting dApp UI') diff --git a/tutorials/pages/shimmerevm-hardhat.md b/docs/tutorials/shimmerevm-hardhat.md similarity index 98% rename from tutorials/pages/shimmerevm-hardhat.md rename to docs/tutorials/shimmerevm-hardhat.md index baa75398e07..e1d85e011e9 100644 --- a/tutorials/pages/shimmerevm-hardhat.md +++ b/docs/tutorials/shimmerevm-hardhat.md @@ -48,7 +48,7 @@ The sample project used here comes from the [Hardhat Quickstart guide](https://h You should see the following prompt: -![Hardhat Setup](/shimmer-hardhat-setup.png 'Hardhat Setup') +![Hardhat Setup](/img/tutorials/shimmer-hardhat-setup.png 'Hardhat Setup') Choose the JavaScript project and go through these steps to compile, test and deploy the sample contract. diff --git a/tutorials/pages/shimmerevm-setup.mdx b/docs/tutorials/shimmerevm-setup.mdx similarity index 95% rename from tutorials/pages/shimmerevm-setup.mdx rename to docs/tutorials/shimmerevm-setup.mdx index 7cd3444d03c..eada2d97a90 100644 --- a/tutorials/pages/shimmerevm-setup.mdx +++ b/docs/tutorials/shimmerevm-setup.mdx @@ -30,7 +30,7 @@ To add the ShimmerEVM network manually to your Metamask use following info: - Currency Symbol: `SMR` - Explorer URL: https://explorer.evm.shimmer.network -![Metamask Adding New Network](/metamask-shimmerevm-mainnet.png 'Metamask Adding New Network') +![Metamask Adding New Network](/img/tutorials/metamask-shimmerevm-mainnet.png 'Metamask Adding New Network') Hit `Save` and wait for Metamask to connect to the network. diff --git a/tutorials/pages/shimmerevm-testnet-hardhat.md b/docs/tutorials/shimmerevm-testnet-hardhat.md similarity index 92% rename from tutorials/pages/shimmerevm-testnet-hardhat.md rename to docs/tutorials/shimmerevm-testnet-hardhat.md index c7f0ecf47ca..3e59a76cd89 100644 --- a/tutorials/pages/shimmerevm-testnet-hardhat.md +++ b/docs/tutorials/shimmerevm-testnet-hardhat.md @@ -48,7 +48,7 @@ The sample project used here comes from the [Hardhat Quickstart guide](https://h You should see the following prompt: -![Hardhat Setup](/shimmer-hardhat-setup.png 'Hardhat Setup') +![Hardhat Setup](/img/tutorials/shimmer-hardhat-setup.png 'Hardhat Setup') Choose the JavaScript project and go through these steps to compile, test and deploy the sample contract. @@ -128,9 +128,9 @@ Some important things to note are data types. `event` means that we can subscrib ```js module.exports = { solidity: '0.8.18', - defaultNetwork: 'shimmerevm-testnet', + defaultNetwork: 'evm-testnet', networks: { - 'shimmerevm-testnet': { + 'evm-testnet': { url: 'https://json-rpc.evm.testnet.shimmer.network', chainId: 1073, accounts: [priv_key], @@ -190,21 +190,21 @@ npx hardhat compile Run this command in root of the project directory: ```sh -npx hardhat run scripts/deploy.js --network shimmerevm-testnet +npx hardhat run scripts/deploy.js --network evm-testnet ``` -The contract will be deployed on ShimmerEVM Testnet, and you can check the deployment status here on the [explorer](https://explorer.evm.testnet.shimmer.network/). +The contract will be deployed on EVM Testnet, and you can check the deployment status here on the [explorer](https://explorer.evm.testnet.shimmer.network/). If you want to further verify your contract, add the following to your `hardhat.config.js`: ```js etherscan: { apiKey: { - 'shimmerevm-testnet': 'ABCDE12345ABCDE12345ABCDE123456789', + 'evm-testnet': 'ABCDE12345ABCDE12345ABCDE123456789', }, customChains: [ { - network: 'shimmerevm-testnet', + network: 'evm-testnet', chainId: 1073, urls: { apiURL: 'https://explorer.evm.testnet.shimmer.network/api', @@ -218,7 +218,7 @@ etherscan: { Then you can verify by running: ```sh -npx hardhat verify --network shimmerevm-testnet
+npx hardhat verify --network evm-testnet
``` :::tip Address and unlock time diff --git a/tutorials/pages/shimmerevm-testnet-setup.mdx b/docs/tutorials/shimmerevm-testnet-setup.mdx similarity index 79% rename from tutorials/pages/shimmerevm-testnet-setup.mdx rename to docs/tutorials/shimmerevm-testnet-setup.mdx index 0698310411e..8e5a385a672 100644 --- a/tutorials/pages/shimmerevm-testnet-setup.mdx +++ b/docs/tutorials/shimmerevm-testnet-setup.mdx @@ -1,10 +1,10 @@ import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton'; import { Networks } from '@theme/constant'; -# Connect to ShimmerEVM Testnet and deploy a Solidity Smart Contract +# Connect to EVM Testnet and deploy a Solidity Smart Contract :::info -In this tutorial, we will connect to ShimmerEVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity. +In this tutorial, we will connect to EVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity. ::: ## Prerequisites @@ -12,22 +12,22 @@ In this tutorial, we will connect to ShimmerEVM Testnet, connect Metamask to it, - [Metamask](https://metamask.io/) or any other wallet of your choice. - [Remix](https://remix-project.org/) or any other development environment of your choice. -## Connect to ShimmerEVM Testnet +## Connect to EVM Testnet -You can either just use the following button to add the ShimmerEVM Testnet network to Metamask +You can either just use the following button to add the EVM Testnet network to Metamask or enter the information manually. -To add the ShimmerEVM Testnet network manually to your Metamask use following info: +To add the EVM Testnet network manually to your Metamask use following info: -- Network Name: `ShimmerEVM Testnet` +- Network Name: `EVM Testnet` - New RPC URL: `https://json-rpc.evm.testnet.shimmer.network` - Chain ID: `1073` - Currency Symbol: `SMR` - Explorer URL: https://explorer.evm.testnet.shimmer.network -![Metamask Adding New Network](/metamask-shimmerevm.png 'Metamask Adding New Network') +![Metamask Adding New Network](/img/tutorials/metamask-shimmerevm.png 'Metamask Adding New Network') Alternatively, you can setup your own EVM Smart Contract Chain on top of the Shimmer network and provide a custom URL, which might look something like: `https://api.sc.testnet.shimmer.network/chain/rms1prr4r7az8e46qhagz5atugjm6x0xrg27d84677e3lurg0s6s76jr59dw4ls/evm/jsonrpc` as well as your own custom Chain ID. @@ -38,10 +38,10 @@ At this point, our Metamask wallet is connected to the Shimmer EVM Testnet, but ## Get EVM Account Funded Open [EVM Toolkit](https://evm-toolkit.evm.testnet.shimmer.network/) and enter your EVM address as shown below: -![EVM Toolkit](/evm-toolkit.png 'EVM Toolkit') +![EVM Toolkit](/img/tutorials/evm-toolkit.png 'EVM Toolkit') In case, you've setup a custom EVM chain, you'd need to add your custom network first. Please add your own chain address and select the relevant network as shown below: -![EVM Toolkit Custom Network](/evm-toolkit-custom-network.png 'EVM Toolkit Custom Network') +![EVM Toolkit Custom Network](/img/tutorials/evm-toolkit-custom-network.png 'EVM Toolkit Custom Network') Once you're done, click on `Send funds` and wait for a few minutes for the faucet to process. You should start seeing some funds on your Metamask wallet soon. @@ -81,7 +81,7 @@ And voila—it's done! width='560' height='315' src='https://www.youtube.com/embed/0_rmmprEKrM' - title='ShimmerEVM Tutorial: Connect to ShimmerEVM Testnet & Deploy a Solidity Smart Contract' + title='ShimmerEVM Tutorial: Connect to EVM Testnet & Deploy a Solidity Smart Contract' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen diff --git a/tutorials/pages/wallet-setup.md b/docs/tutorials/wallet-setup.md similarity index 99% rename from tutorials/pages/wallet-setup.md rename to docs/tutorials/wallet-setup.md index 95782c52ba7..47fd0d9c871 100644 --- a/tutorials/pages/wallet-setup.md +++ b/docs/tutorials/wallet-setup.md @@ -395,7 +395,7 @@ The 'Request' button will become clickable as soon as a valid Shimmer address is ::: -![Shimmer Testnet Faucet](/shimmer-testnet-faucet.png) +![Shimmer Testnet Faucet](/img/tutorials/shimmer-testnet-faucet.png) --- diff --git a/docusaurus.config.js b/docusaurus.config.js index 24a4aa77a8f..df91c09d66f 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -1,13 +1,14 @@ const { glob, merge } = require('./src/utils/config'); const path = require('path'); const { create_doc_plugin } = require('./src/utils/config'); -const contentConfigs = require('./contentPlugins'); -const articleRedirectsFile = require('./articleRedirects'); -const switcherConfig = require('./switcherConfig'); +const contentConfigs = require('./config/contentPlugins'); +const articleRedirectsFile = require('./config/articleRedirects'); +const switcherConfig = require('./config/switcherConfig'); +const tutorials = require('./config/tutorials'); const { buildPluginsConfig, maintainPluginsConfig, -} = require('./versionedConfig'); +} = require('./config/versionedConfig'); const { createVersionRedirects, } = require('./src/utils/pluginConfigGenerators'); @@ -54,9 +55,10 @@ module.exports = async () => { '^(/[^/]+)?/iota-sdk/.*|' + '^(/[^/]+)?/identity.rs/.*|' + '^(/[^/]+)?/stronghold.rs/.*|' + - '^(/[^/]+)?/wasp-cli/.*|' + - '^(/[^/]+)?/wasp-wasm/.*|' + - '^(/[^/]+)?/wasp-evm/.*', + '^(/[^/]+)?/isc/.*|' + + '^(/[^/]+)?/iota-sandbox/.*|' + + '^(/[^/]+)?/apis/.*|' + + '^(/[^/]+)?/cli-wallet/.*', }, { label: 'Maintain', @@ -64,6 +66,7 @@ module.exports = async () => { activeBaseRegex: '^(/[^/]+)?/maintain/.*|' + '^(/[^/]+)?/hornet/.*|' + + '^(/[^/]+)?/iota-core/.*|' + '^(/[^/]+)?/wasp/.*|' + '^(/[^/]+)?/chronicle/.*', }, @@ -144,6 +147,15 @@ module.exports = async () => { defaultMode: 'dark', }, switcher: switcherConfig, + + announcementBar: { + id: 'support_us', + content: + 'Experience seamless dApp development with IOTA EVM.', + backgroundColor: 'var(--ifm-color-primary)', + textColor: 'var(--ifm-font-color-base-inverse);', + isCloseable: true, + }, }, }; @@ -156,8 +168,8 @@ module.exports = async () => { }, plugins: [ // Temporarily disabled because of Cookiebot blocking required scripts. - // path.resolve(__dirname, 'plugins', 'cookiebot'), - path.resolve(__dirname, 'plugins', 'matomo'), + // require('./src/plugins/cookiebot'), + require('./src/plugins/matomo'), [ '@docusaurus/plugin-google-gtag', { @@ -210,6 +222,7 @@ module.exports = async () => { ], ], plugins: [ + ...tutorials, ...contentPlugins, [ '@docusaurus/plugin-content-docs', @@ -247,6 +260,7 @@ module.exports = async () => { 'docusaurus-plugin-openapi-docs', { id: 'openapi', + docsPlugin: './src/plugins/docs', docsPluginId: 'apis', // e.g. "classic" or the plugin-content-docs id config: { coreApiV2: { @@ -432,19 +446,9 @@ module.exports = async () => { ], 'plugin-image-zoom', ], - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', - integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', - }, - ], themes: [ 'docusaurus-theme-openapi-docs', '@saucelabs/theme-github-codeblock', - '@iota-wiki/theme', ], staticDirectories: [path.resolve(__dirname, 'static')], }, diff --git a/package.json b/package.json index 5a3424907cb..9801ce0f035 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,6 @@ "name": "@iota-wiki/core", "version": "1.1.0", "scripts": { - "build:cli": "yarn ./cli build", - "build:plugins": "yarn ./plugins/tutorial build && yarn ./plugins/docs build", - "build:theme": "yarn ./theme build", "checkout": "git submodule update --init", "checkout:remote": "yarn checkout --remote", "generate:api": "docusaurus gen-api-docs all && ./scripts/get_sdk_references.sh && ./scripts/get_wasp_references.sh", @@ -16,7 +13,7 @@ "format": "prettier --cache --write .", "format:check": "prettier --cache --check .", "format:svg": "svgo ./src/**/*.svg", - "prepare": "yarn build:plugins && yarn build:theme && yarn checkout", + "prepare": "yarn checkout", "docusaurus": "docusaurus", "start": "NODE_OPTIONS='--max-old-space-size=4096' docusaurus start", "start:section:build": "SELECTED_SECTION='build' yarn start", @@ -33,27 +30,28 @@ }, "dependencies": { "@algolia/client-search": "^4.22.1", + "@artsy/to-title-case": "^1.1.0", "@docusaurus/core": "2.4.3", "@docusaurus/plugin-client-redirects": "2.4.3", "@docusaurus/preset-classic": "2.4.3", "@docusaurus/remark-plugin-npm2yarn": "^2.4.3", + "@docusaurus/theme-classic": "2.4.3", "@docusaurus/theme-common": "2.4.3", - "@iota-wiki/plugin-docs": "workspace:^", - "@iota-wiki/plugin-tutorial": "workspace:^", - "@iota-wiki/theme": "workspace:^", "@mdx-js/react": "^1.6.21", + "@metamask/providers": "^10.2.1", "@popperjs/core": "^2.11.5", "@saucelabs/theme-github-codeblock": "^0.2.3", "@svgr/webpack": "^5.5.0", "bufferutil": "^4.0.8", "clsx": "^1.2.1", - "docusaurus-plugin-openapi-docs": "dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-plugin-openapi-docs", - "docusaurus-theme-openapi-docs": "dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-theme-openapi-docs", + "docusaurus-plugin-openapi-docs": "jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-plugin-openapi-docs", + "docusaurus-theme-openapi-docs": "jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-theme-openapi-docs", "file-loader": "^6.2.0", "flickity": "2.3.0", "flickity-fade": "^2.0.0", "globby": "^13.1.4", "hast-util-is-element": "1.1.0", + "html-react-parser": "^4.2.10", "humanize-duration": "^3.30.0", "infima": "^0.2.0-alpha.43", "plugin-image-zoom": "flexanalytics/plugin-image-zoom", @@ -63,6 +61,7 @@ "react-dom": "18.2.0", "react-flickity-component": "^3.6.3", "react-image-gallery": "^1.3.0", + "react-markdown": "6", "react-player": "^2.11.2", "react-popper": "^2.3.0", "react-select": "^5.7.7", @@ -76,9 +75,10 @@ "remark-remove-comments": "^0.2.0", "url-loader": "^4.1.1", "utf-8-validate": "^6.0.3", + "web3": "^4.2.2", "webpack": "^5.89.0", "webpack-node-externals": "^3.0.0", - "ws": "^8.16.0" + "ws": "^8.17.1" }, "resolutions": { "@types/react": "18.2.71", diff --git a/plugins/docs/.gitignore b/plugins/docs/.gitignore deleted file mode 100644 index cd1b407c23c..00000000000 --- a/plugins/docs/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -node_modules -/dist - -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -.pnp.* diff --git a/plugins/docs/.yarnrc.yml b/plugins/docs/.yarnrc.yml deleted file mode 100644 index 3186f3f0795..00000000000 --- a/plugins/docs/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/plugins/docs/README.md b/plugins/docs/README.md deleted file mode 100644 index 12596d6da43..00000000000 --- a/plugins/docs/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Docs - -This plugin wraps the Docusaurus docs plugin and adds the possibility to expose selected sidebars on the client side globally, where the Docusaurus docs plugin would only expose a link instead of the complete sidebar structure. This allows us to display sidebars statically in docs other than the one the sidebar is associated with. - -## Usage - -``` -yarn add @iota-wiki/plugin-docs -``` - -Configure it like you would do with the Docusaurus docs plugin. Then register any sidebars you want to expose globally by adding their ID, found in the associated sidebars configuration file, to the `globalSidebars` array: - -```js - plugins: [ - [ - '@iota-wiki/plugin-docs', - { - globalSidebars: ['sidebar-id'], // Optional - ... - }, - ], - ... - ... -``` - -Now the global data for that docs plugin will contain a `globalSidebars` object, which maps sidebar IDs to their items. For example: - -```js -import { useAllDocsData } from '@docusaurus/plugin-content-docs/client'; - ... - const plugins = useAllDocsData(); - const sidebarItems = plugins['default'].globalSidebars['sidebar-id']; - ... -``` diff --git a/plugins/docs/package.json b/plugins/docs/package.json deleted file mode 100644 index 4d5c6c0dc3a..00000000000 --- a/plugins/docs/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@iota-wiki/plugin-docs", - "version": "0.1.0", - "main": "dist/index.js", - "types": "src/types.d.ts", - "scripts": { - "clean": "rm -rf ./lib", - "build": "tsc --build", - "watch": "tsc --watch", - "prepack": "yarn build" - }, - "packageManager": "yarn@3.2.2", - "devDependencies": { - "@docusaurus/types": "2.4.3", - "typescript": "^4.6.3" - }, - "files": [ - "dist", - "src/types.d.ts" - ], - "dependencies": { - "@docusaurus/plugin-content-docs": "2.4.3" - } -} diff --git a/plugins/docs/src/index.ts b/plugins/docs/src/index.ts deleted file mode 100644 index bc27d7b5875..00000000000 --- a/plugins/docs/src/index.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { LoadContext, Plugin } from '@docusaurus/types'; -import { LoadedContent, OptionValidationContext, PluginOptions } from './types'; -import docsPlugin, { - validateOptions as docsValidateOptions, - PropVersionMetadata, -} from '@docusaurus/plugin-content-docs'; -import fs from 'fs/promises'; -import path from 'path'; - -export default async function pluginDocs( - context: LoadContext, - options: PluginOptions, -): Promise> { - // Destructure to separate the Docusaurus docs plugin options - // and initialize the Docusaurus docs plugin to wrap. - const { bannerPath, globalSidebars, ...docsOptions } = options; - const plugin = await docsPlugin(context, docsOptions); - - return { - ...plugin, - getPathsToWatch: () => { - const pathsToWatch = plugin.getPathsToWatch(); - - if (bannerPath) - pathsToWatch.push(path.resolve(context.siteDir, bannerPath)); - - return pathsToWatch; - }, - loadContent: async () => { - const docsLoadedContent = await plugin.loadContent(); - return { - ...docsLoadedContent, - // Load banner content from file - bannerContent: bannerPath - ? await fs.readFile(bannerPath, { - encoding: 'utf-8', - }) - : undefined, - }; - }, - translateContent: ({ content, ...args }) => { - // Propagate banner content - const { bannerContent, ...docsContent } = content; - const docsContentLoaded = plugin.translateContent({ - content: docsContent, - ...args, - }); - return { - ...docsContentLoaded, - bannerContent, - }; - }, - // Override the `contentLoaded` function to add sidebars to the - // global data exposed by the Docusaurus docs plugin. - contentLoaded: async ({ actions, content, ...args }) => { - const { bannerContent, ...docsContent } = content; - const globalSidebarEntries = []; - - const createData = async (name: string, data: string) => { - // Hook into the `createData` call to extract the sidebars we need. - const versionMetadata = JSON.parse(data) as PropVersionMetadata; - if (versionMetadata.docsSidebars) { - // We can do this, because all `createData` calls are assured - // to resolve before `setGlobalData` is called. - Object.entries(versionMetadata.docsSidebars) - .filter(([sidebarId]) => globalSidebars.includes(sidebarId)) - .forEach((entry) => globalSidebarEntries.push(entry)); - } - - return await actions.createData( - name, - // Expose banner content to be used by the DocBanner theme component - JSON.stringify( - { - ...versionMetadata, - bannerContent, - }, - null, - 2, - ), - ); - }; - - const setGlobalData = (data: object) => { - actions.setGlobalData({ - ...data, - globalSidebars: Object.fromEntries(globalSidebarEntries), - }); - }; - - await plugin.contentLoaded({ - ...args, - content: docsContent, - actions: { - ...actions, - createData, - setGlobalData, - }, - }); - }, - }; -} - -export function validateOptions({ - validate, - options, -}: OptionValidationContext): PluginOptions { - const { bannerPath, globalSidebars = [], ...docsOptions } = options; - return { - ...docsValidateOptions({ validate, options: docsOptions }), - globalSidebars, - bannerPath, - }; -} diff --git a/plugins/docs/tsconfig.json b/plugins/docs/tsconfig.json deleted file mode 100644 index aebee81749e..00000000000 --- a/plugins/docs/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2019", - "module": "NodeNext", - "moduleResolution": "node", - "esModuleInterop": true, - "rootDir": "src", - "outDir": "dist", - "declaration": true - }, - "include": ["src"] -} diff --git a/plugins/tutorial/.gitignore b/plugins/tutorial/.gitignore deleted file mode 100644 index cd1b407c23c..00000000000 --- a/plugins/tutorial/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -node_modules -/dist - -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -.pnp.* diff --git a/plugins/tutorial/.yarnrc.yml b/plugins/tutorial/.yarnrc.yml deleted file mode 100644 index 3186f3f0795..00000000000 --- a/plugins/tutorial/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/plugins/tutorial/README.md b/plugins/tutorial/README.md deleted file mode 100644 index 3a4cb46c947..00000000000 --- a/plugins/tutorial/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Tutorial plugin - -This is a small plugin to register tutorials to be listed on the tutorial page plugin. - -## Usage - -``` -yarn add @iota-wiki/plugin-tutorial -``` - -Then register any tutorials to list on the tutorial page by providing information like the titles, routes and metadata of the tutorials: - -```js - plugins: [ - [ - '@iota-wiki/plugin-tutorial', - { - title: "EVM Tutorial", - description: - "In this tutorial, you will learn how to use the EVM in IOTA.", - route: "evm-tutorial/intro", - tags: ["text"], - source: "https://github.com/dr-electron/tutorial-template", // Optional - preview: "evm-tutorial.png", // Optional - }, - ], - ... - ... -``` diff --git a/plugins/tutorial/package.json b/plugins/tutorial/package.json deleted file mode 100644 index e3d733f0fc0..00000000000 --- a/plugins/tutorial/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@iota-wiki/plugin-tutorial", - "version": "1.0.6", - "main": "dist/index.js", - "types": "src/types.d.ts", - "scripts": { - "clean": "rm -rf ./lib", - "build": "tsc --build", - "prepack": "yarn build" - }, - "packageManager": "yarn@3.2.2", - "devDependencies": { - "@docusaurus/types": "2.4.3", - "typescript": "^4.6.3" - }, - "files": [ - "dist", - "src/types.d.ts" - ] -} diff --git a/plugins/tutorial/src/index.ts b/plugins/tutorial/src/index.ts deleted file mode 100644 index 5681ea392e9..00000000000 --- a/plugins/tutorial/src/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { - OptionValidationContext, - LoadContext, - Plugin, -} from '@docusaurus/types'; - -import type { NormalizedOptions, UserOptions } from './types'; - -export default async function pluginTutorial( - context: LoadContext, - options: NormalizedOptions, -): Promise { - return { - name: '@iota-wiki/plugin-tutorial', - async contentLoaded({ actions }) { - actions.setGlobalData(options); - }, - }; -} - -export function validateOptions({ - options: userOptions, -}: OptionValidationContext): NormalizedOptions { - const id = userOptions.title.normalize().toLowerCase().replace(/\W/, '-'); - - const defaultOptions = { - id, - route: id, - }; - - return Object.assign(defaultOptions, userOptions); -} diff --git a/plugins/tutorial/tsconfig.json b/plugins/tutorial/tsconfig.json deleted file mode 100644 index aebee81749e..00000000000 --- a/plugins/tutorial/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2019", - "module": "NodeNext", - "moduleResolution": "node", - "esModuleInterop": true, - "rootDir": "src", - "outDir": "dist", - "declaration": true - }, - "include": ["src"] -} diff --git a/scripts/get_wasp_references.sh b/scripts/get_wasp_references.sh index a9e19a4c50b..a1919e76452 100755 --- a/scripts/get_wasp_references.sh +++ b/scripts/get_wasp_references.sh @@ -5,11 +5,17 @@ mkdir tmp cd tmp # Download and copy docs -curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.0/iscmagic.tar.gz | tar xzv -cp -Rv docs/iscmagic/* ../docs/build/isc/v1.0.0-rc.6/docs/reference/magic-contract/ +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.1/iscmagic.tar.gz | tar xzv +cp -Rv docs/iscmagic/* ../docs/build/isc/v1.1/docs/reference/magic-contract/ -curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.0/iscutils.tar.gz | tar xzv -cp -Rv docs/iscutils ../docs/build/isc/v1.0.0-rc.6/docs/reference/ +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.1/iscutils.tar.gz | tar xzv +cp -Rv docs/iscutils ../docs/build/isc/v1.1/docs/reference/ + +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.3/iscmagic.tar.gz | tar xzv +cp -Rv docs/iscmagic/* ../docs/build/isc/v1.3/docs/reference/magic-contract/ + +curl -sL https://s3.eu-central-1.amazonaws.com/files.iota.org/iota-wiki/wasp/1.3/iscutils.tar.gz | tar xzv +cp -Rv docs/iscutils ../docs/build/isc/v1.3/docs/reference/ # Return to root and cleanup cd - diff --git a/src/components/HomeLayout/index.tsx b/src/components/HomeLayout/index.tsx index 93d79f53f17..4d75af6b9ff 100644 --- a/src/components/HomeLayout/index.tsx +++ b/src/components/HomeLayout/index.tsx @@ -18,7 +18,7 @@ const { IntegrationServices, IotaCore, PickAWallet, - Shimmer, + IotaEVM, Search, Tips, Tutorials, @@ -85,6 +85,12 @@ export default function HomeLayout() { > Start building + + Build your dApp on IOTA EVM + @@ -106,18 +112,16 @@ export default function HomeLayout() {

- +
- +
-

What is Shimmer?

+

Build on IOTA EVM

- A scalable and feeless network enabling frictionless - decentralized and scalable Web3 economies. + Experience seamless dApp development with IOTA EVM's + oracles, subgraphs, Layer 0 interoperability, and robust Blast + API endpoints.

diff --git a/src/components/TutorialCard/index.tsx b/src/components/TutorialCard/index.tsx index 843fc4d8e68..92ecf3aeede 100644 --- a/src/components/TutorialCard/index.tsx +++ b/src/components/TutorialCard/index.tsx @@ -11,7 +11,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; import './styles.css'; import FavoriteIcon from '../svgIcons/FavoriteIcon'; import { sortBy } from '@site/src/utils/jsUtils'; -import { NormalizedOptions as Tutorial } from '@iota-wiki/plugin-tutorial'; +import { NormalizedOptions as Tutorial } from '../../plugins/tutorial'; import { Tag, TagValues, Tags } from '@site/src/utils/tags'; import Link from '@docusaurus/Link'; diff --git a/src/components/TutorialFilters/index.tsx b/src/components/TutorialFilters/index.tsx index e4055bc0865..2d890796759 100644 --- a/src/components/TutorialFilters/index.tsx +++ b/src/components/TutorialFilters/index.tsx @@ -11,7 +11,7 @@ import { Collapsible, useCollapsible } from '@docusaurus/theme-common'; import './styles.css'; -import { NormalizedOptions as Tutorial } from '@iota-wiki/plugin-tutorial'; +import { NormalizedOptions as Tutorial } from '../../plugins/tutorial'; import { TagCategories } from '@site/src/utils/tags'; type UserState = { diff --git a/src/icons/iota/index.ts b/src/icons/iota/index.ts index 5b096a14155..0c2b8d46a30 100644 --- a/src/icons/iota/index.ts +++ b/src/icons/iota/index.ts @@ -6,6 +6,7 @@ import { default as Identity } from '@site/static/icons/iota/identity.svg'; import { default as IntegrationServices } from '@site/static/icons/iota/integration_services.svg'; import { default as Iota20 } from '@site/static/icons/iota/iota_20.svg'; import { default as IotaCore } from '@site/static/icons/iota/iota_core.svg'; +import { default as IotaEVM } from '@site/static/icons/iota/iota_evm.svg'; import { default as IotaToken } from '@site/static/icons/iota/iota_token.svg'; import { default as Next } from '@site/static/icons/iota/next.svg'; import { default as PickAWallet } from '@site/static/icons/iota/pick_a_wallet.svg'; @@ -29,6 +30,7 @@ export default { IntegrationServices, Iota20, IotaCore, + IotaEVM, IotaToken, Next, PickAWallet, diff --git a/plugins/cookiebot/index.js b/src/plugins/cookiebot/index.js similarity index 100% rename from plugins/cookiebot/index.js rename to src/plugins/cookiebot/index.js diff --git a/plugins/docs/src/types.d.ts b/src/plugins/docs/index.d.ts similarity index 75% rename from plugins/docs/src/types.d.ts rename to src/plugins/docs/index.d.ts index 4e4e03b0a83..572ba55a8f7 100644 --- a/plugins/docs/src/types.d.ts +++ b/src/plugins/docs/index.d.ts @@ -1,25 +1,14 @@ import { Options as DocsOptions, PluginOptions as DocsPluginOptions, - LoadedContent as DocsLoadedContent, - DocMetadata as DocsDocMetadata, } from '@docusaurus/plugin-content-docs'; import { OptionValidationContext as DocsOptionValidationContext, Validate, } from '@docusaurus/types'; -export type DocMetadata = DocsDocMetadata & { - bannerContent?: string; -}; - -export type LoadedContent = DocsLoadedContent & { - bannerContent?: string; -}; - export type PluginOptions = DocsPluginOptions & { globalSidebars: string[]; - bannerPath?: string; }; export type Options = Partial; diff --git a/src/plugins/docs/index.js b/src/plugins/docs/index.js new file mode 100644 index 00000000000..fa2630add3d --- /dev/null +++ b/src/plugins/docs/index.js @@ -0,0 +1,134 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.validateOptions = void 0; +const plugin_content_docs_1 = __importStar( + require('@docusaurus/plugin-content-docs'), +); +async function pluginDocs(context, options) { + // Destructure to separate the Docusaurus docs plugin options + // and initialize the Docusaurus docs plugin to wrap. + const { globalSidebars, ...docsOptions } = options; + const plugin = await (0, plugin_content_docs_1.default)(context, docsOptions); + return { + ...plugin, + // Override the `contentLoaded` function to add sidebars to the + // global data exposed by the Docusaurus docs plugin. + contentLoaded: async ({ actions, content, ...args }) => { + const globalSidebarEntries = []; + const createData = async (name, data) => { + // Hook into the `createData` call to extract the sidebars we need. + const versionMetadata = JSON.parse(data); + if (versionMetadata.docsSidebars) { + // We can do this, because all `createData` calls are assured + // to resolve before `setGlobalData` is called. + Object.entries(versionMetadata.docsSidebars) + .filter(([sidebarId]) => globalSidebars.includes(sidebarId)) + .forEach((entry) => globalSidebarEntries.push(entry)); + } + return await actions.createData(name, data); + }; + const setGlobalData = (data) => { + actions.setGlobalData({ + ...data, + globalSidebars: Object.fromEntries(globalSidebarEntries), + }); + }; + await plugin.contentLoaded({ + ...args, + content, + actions: { + ...actions, + createData, + setGlobalData, + }, + }); + }, + }; +} +exports.default = pluginDocs; +function validateOptions({ validate, options }) { + const { versions = {}, globalSidebars = [], ...docsOptions } = options; + const versionEntries = Object.entries(versions); + if (versionEntries.length > 1) + throw 'Multiple Docusuaurus doc versions not allowed in the Wiki'; + // Handle version banner. + const versionBannerMap = {}; + const docsVersionEntries = versionEntries.map( + ([versionLabel, versionOptions]) => { + // TODO: validate banner + const { banner, ...docsVersionOptions } = versionOptions; + versionBannerMap[versionLabel] = banner; + return [versionLabel, docsVersionOptions]; + }, + ); + const validatedDocsOptions = (0, plugin_content_docs_1.validateOptions)({ + validate, + options: { + ...docsOptions, + versions: Object.fromEntries(docsVersionEntries), + }, + }); + // Re-add banner. + validatedDocsOptions.versions = Object.fromEntries( + Object.entries(validatedDocsOptions.versions).map( + ([versionLabel, versionOptions]) => { + return [ + versionLabel, + { + ...versionOptions, + banner: versionBannerMap[versionLabel], + }, + ]; + }, + ), + ); + return { + ...validatedDocsOptions, + globalSidebars, + }; +} +exports.validateOptions = validateOptions; diff --git a/plugins/matomo/index.js b/src/plugins/matomo/index.js similarity index 100% rename from plugins/matomo/index.js rename to src/plugins/matomo/index.js diff --git a/plugins/tutorial/src/types.d.ts b/src/plugins/tutorial/index.d.ts similarity index 100% rename from plugins/tutorial/src/types.d.ts rename to src/plugins/tutorial/index.d.ts diff --git a/src/plugins/tutorial/index.js b/src/plugins/tutorial/index.js new file mode 100644 index 00000000000..994374b021b --- /dev/null +++ b/src/plugins/tutorial/index.js @@ -0,0 +1,19 @@ +function pluginTutorial(context, options) { + return { + name: '@iota-wiki/plugin-tutorial', + async contentLoaded({ actions }) { + actions.setGlobalData(options); + }, + }; +} + +pluginTutorial.validateOptions = ({ options: userOptions }) => { + const id = userOptions.title.normalize().toLowerCase().replace(/\W/, '-'); + const defaultOptions = { + id, + route: id, + }; + return Object.assign(defaultOptions, userOptions); +}; + +module.exports = pluginTutorial; diff --git a/theme/src/theme/AddToMetaMaskButton/index.tsx b/src/theme/AddToMetaMaskButton/index.tsx similarity index 96% rename from theme/src/theme/AddToMetaMaskButton/index.tsx rename to src/theme/AddToMetaMaskButton/index.tsx index dc10cf4cc43..553b2aafb27 100644 --- a/theme/src/theme/AddToMetaMaskButton/index.tsx +++ b/src/theme/AddToMetaMaskButton/index.tsx @@ -20,7 +20,7 @@ export function AddToMetaMaskButton(props: NetworkProps) { try { await window.ethereum.request({ method: 'wallet_addEthereumChain', - params: [props.evm], + params: [props.evm.core], }); } catch (error) { console.error(error); diff --git a/theme/src/theme/ChainId/index.tsx b/src/theme/ChainId/index.tsx similarity index 100% rename from theme/src/theme/ChainId/index.tsx rename to src/theme/ChainId/index.tsx diff --git a/src/theme/DocVersionBanner/index.tsx b/src/theme/DocVersionBanner/index.tsx new file mode 100644 index 00000000000..90bbff23f15 --- /dev/null +++ b/src/theme/DocVersionBanner/index.tsx @@ -0,0 +1,200 @@ +/** + * SWIZZLED VERSION: 2.4.3 + * REASONS: + * - Remove use of siteTitle as it is irrelevant in our setup. + * - Link to our own latest version. + * - Update text pointing to latest version + * - Add `staging` banner. + */ +import React, { type ComponentType } from 'react'; +import clsx from 'clsx'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; +import { type GlobalVersion } from '@docusaurus/plugin-content-docs/client'; +import { ThemeClassNames } from '@docusaurus/theme-common'; +import { useDocsVersion } from '@docusaurus/theme-common/internal'; +import type { Props } from '@theme/DocVersionBanner'; +import type { + VersionBanner, + PropVersionMetadata, +} from '@docusaurus/plugin-content-docs'; +import { useWikiPreferredVersion } from '@site/src/utils/wikiPreferredVersion'; +import { useLocation } from '@docusaurus/router'; +import { + useAllLatestVersion, + useCurrentDocPlugins, +} from '@site/src/utils/wikiVersion'; + +type WikiVersionBanner = VersionBanner & 'staging'; + +type BannerLabelComponentProps = { + siteTitle: string; + versionMetadata: PropVersionMetadata; +}; + +function UnreleasedVersionLabel({ + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + {'This is unreleased documentation for {versionLabel} version.'} + + ); +} + +function StagingVersionLabel({ versionMetadata }: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is documentation for {versionLabel} version wich is currently running on our staging network.' + } + + ); +} + +function UnmaintainedVersionLabel({ + versionMetadata, +}: BannerLabelComponentProps) { + return ( + {versionMetadata.label}, + }} + > + { + 'This is documentation for {versionLabel}, which is no longer actively maintained.' + } + + ); +} + +const BannerLabelComponents: { + [banner in WikiVersionBanner]: ComponentType; +} = { + unreleased: UnreleasedVersionLabel, + staging: StagingVersionLabel, + unmaintained: UnmaintainedVersionLabel, +}; + +function BannerLabel(props: BannerLabelComponentProps) { + const BannerLabelComponent = + BannerLabelComponents[props.versionMetadata.banner!]; + return ; +} + +function LatestVersionSuggestionLabel({ + versionLabel, + to, + onClick, +}: { + to: string; + onClick: () => void; + versionLabel: string; +}) { + return ( + + + + latest version + + + + ), + }} + > + { + 'For the latest stable release, see the {latestVersionLink} ({versionLabel}).' + } + + ); +} + +function DocVersionBannerEnabled({ + className, + versionMetadata, +}: Props & { + versionMetadata: PropVersionMetadata; +}): JSX.Element { + const { + siteConfig: { title: siteTitle }, + } = useDocusaurusContext(); + const { pathname } = useLocation(); + const pluginIds = useCurrentDocPlugins(pathname); + + const getVersionMainDoc = (version: GlobalVersion) => + version.docs.find((doc) => doc.id === version.mainDocId)!; + + const { savePreferredVersionName } = useWikiPreferredVersion( + pathname, + pluginIds, + ); + + const latestVersionSuggestion = useAllLatestVersion(pluginIds); + const latestDocSuggestion = getVersionMainDoc(latestVersionSuggestion); + + // Try to link to same doc in latest version (not always possible), falling + // back to main doc of latest version + const latestVersionSuggestedDoc = + latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion); + + return ( +
+
+ +
+
+ savePreferredVersionName(latestVersionSuggestion.name)} + /> +
+
+ ); +} + +export default function DocVersionBanner({ + className, +}: Props): JSX.Element | null { + const versionMetadata = useDocsVersion(); + if (versionMetadata.banner) { + return ( + + ); + } + return null; +} diff --git a/theme/src/theme/Glossary/index.tsx b/src/theme/Glossary/index.tsx similarity index 96% rename from theme/src/theme/Glossary/index.tsx rename to src/theme/Glossary/index.tsx index f012b4d75b7..b8237730fcc 100644 --- a/theme/src/theme/Glossary/index.tsx +++ b/src/theme/Glossary/index.tsx @@ -4,7 +4,7 @@ import { toTitleCase } from '@artsy/to-title-case'; import { clsx } from 'clsx'; export default function Glossary() { - const glossary = require('@site/common/jargon.js'); + const glossary = require('@site/config/jargon.js'); const parse = require('html-react-parser'); const sortedGlossary = Object.keys(glossary) diff --git a/src/theme/NetworkInfo/index.tsx b/src/theme/NetworkInfo/index.tsx new file mode 100644 index 00000000000..145bff9b6fc --- /dev/null +++ b/src/theme/NetworkInfo/index.tsx @@ -0,0 +1,168 @@ +import React from 'react'; +import { ChainId } from '../ChainId'; +import { NetworkProps } from '../constant'; +import CodeBlock from '@theme/CodeBlock'; +import Admonition from '@theme/Admonition'; + +function L1(props: NetworkProps) { + return ( + + + + + + + + + + + + + + + + + + + + + + + {props.faucet && ( + + + + + )} + +
Base Token{props.baseToken}
Protocol{props.protocol}
HTTP REST API + {props.httpRestApi} +
Event API + {props.eventApi} +
Permanode API + {props.permaNodeApi} +
Faucet + + {props.faucet} + +
+ ); +} + +function Evm(props: NetworkProps) { + return ( + + + + + + + + + + + + + + + + + + + {props.evm.tools && props.evm.tools.blastApiUrls && ( + + + + + )} + + + + + + + + + + + + + +
Base Token{props.baseToken}
ProtocolISC / EVM
Chain ID + +
RPC URL + {props.evm.core.rpcUrls.map((url, index) => ( + {url} + ))} +
+ + Blast API provides highly + scalable fault-tolerant API endpoints. + + + {props.evm.tools.blastApiUrls.map((object, index) => + typeof object === 'string' ? ( + {object as string} + ) : ( + + {' '} + {Object.values(object)[0]}{' '} + + ), + )} +
Explorer + + {props.evm.core.blockExplorerUrls[0]} + +
+ {props.evm.custom.toolkit.hasFaucet + ? 'Toolkit & Faucet' + : 'Toolkit'} + + + {props.evm.custom.toolkit.url} + +
WASP API + {props.evm.custom.api} +
+ ); +} + +function EvmCustom(props: NetworkProps) { + return ( + + + + + + + + + + + +
Chain Address + + {props.evm.custom.chainAddress} + +
Alias ID{props.evm.custom.aliasId}
+ ); +} + +export default { + L1, + Evm, + EvmCustom, +}; diff --git a/src/theme/constant.tsx b/src/theme/constant.tsx new file mode 100644 index 00000000000..bbf07ff3c08 --- /dev/null +++ b/src/theme/constant.tsx @@ -0,0 +1,214 @@ +export const Networks: { [key: string]: NetworkProps } = { + iota: { + baseToken: 'IOTA Token', + protocol: 'Stardust', + httpRestApi: 'https://api.stardust-mainnet.iotaledger.net', + eventApi: 'wss://api.stardust-mainnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', + permaNodeApi: 'https://chronicle.stardust-mainnet.iotaledger.net', + explorer: 'https://explorer.iota.org/mainnet', + evm: { + core: { + chainId: '0x2276', + chainName: 'IOTA EVM', + nativeCurrency: { + name: 'IOTA', + symbol: 'IOTA', + decimals: 18, + }, + rpcUrls: [ + 'https://json-rpc.evm.iotaledger.net', + 'wss://ws.json-rpc.evm.iotaledger.net', + ], + blockExplorerUrls: ['https://explorer.evm.iota.org'], + }, + tools: { + blastApiUrls: [ + 'https://iota-mainnet-evm.public.blastapi.io', + 'wss://iota-mainnet-evm.public.blastapi.io', + { + 'Archive RPC': + 'https://iota-mainnet-evm.blastapi.io/e7596858-fc63-4a54-8727-b885a2af4ec8', + }, + ], + }, + custom: { + chainAddress: + 'iota1pzt3mstq6khgc3tl0mwuzk3eqddkryqnpdxmk4nr25re2466uxwm28qqxu5', + aliasId: + '0x971dc160d5ae8c457f7eddc15a39035b6190130b4dbb5663550795575ae19db5', + toolkit: { + url: 'https://evm-toolkit.evm.iotaledger.net', + hasFaucet: false, + }, + api: 'https://api.evm.iotaledger.net', + }, + }, + }, + iota_2_testnet: { + baseToken: 'Testnet Token (no value)', + protocol: 'IOTA 2.0', + httpRestApi: 'https://api.nova-testnet.iotaledger.net/', + eventApi: 'wss://api.nova-testnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', + permaNodeApi: 'https://chronicle.nova-testnet.iotaledger.net', + explorer: 'https://explorer.iota.org/iota2-testnet', + faucet: 'https://faucet.nova-testnet.iotaledger.net', + }, + iota_testnet: { + baseToken: 'Testnet Token (no value)', + protocol: 'Stardust', + httpRestApi: 'https://api.testnet.iotaledger.net', + eventApi: 'wss://api.testnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', + permaNodeApi: 'https://chronicle.testnet.iotaledger.net', + faucet: 'https://faucet.testnet.iotaledger.net', + explorer: 'https://explorer.iota.org/iota-testnet', + evm: { + core: { + chainId: '0x433', + chainName: 'IOTA EVM Testnet', + nativeCurrency: { + name: 'IOTA', + symbol: 'IOTA', + decimals: 18, + }, + rpcUrls: [ + 'https://json-rpc.evm.testnet.iotaledger.net', + 'wss://ws.json-rpc.evm.testnet.iotaledger.net', + ], + blockExplorerUrls: ['https://explorer.evm.testnet.iotaledger.net'], + }, + tools: { + blastApiUrls: [ + 'https://iota-testnet-evm.public.blastapi.io', + 'wss://iota-testnet-evm.public.blastapi.io', + { + 'Archive RPC': + 'https://iota-testnet-evm.blastapi.io/e7596858-fc63-4a54-8727-b885a2af4ec8', + }, + ], + }, + custom: { + chainAddress: + 'tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu', + aliasId: + '0x8d018fdd082cd10b518b4935ed8672c8cb3d450c4abcd24fdc620d16babfbb61', + toolkit: { + url: 'https://evm-toolkit.evm.testnet.iotaledger.net', + hasFaucet: true, + }, + api: 'https://api.evm.testnet.iotaledger.net', + }, + }, + }, + shimmer: { + baseToken: 'Shimmer Token', + protocol: 'Stardust', + httpRestApi: 'https://api.shimmer.network', + eventApi: 'wss://api.shimmer.network:443/api/mqtt/v1 (MQTT 3.1)', + permaNodeApi: 'https://chronicle.shimmer.network', + explorer: 'https://explorer.shimmer.network/shimmer', + evm: { + core: { + chainId: '0x94', + chainName: 'ShimmerEVM', + nativeCurrency: { + name: 'Shimmer', + symbol: 'SMR', + decimals: 18, + }, + rpcUrls: [ + 'https://json-rpc.evm.shimmer.network', + 'wss://ws.json-rpc.evm.shimmer.network', + ], + blockExplorerUrls: ['https://explorer.evm.shimmer.network/'], + }, + custom: { + chainAddress: + 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', + aliasId: + '0xccc7018e4fa63e5014332f45ddc8a5450da89572676d12d4d5e51c98d64155b3', + toolkit: { + url: 'https://evm-toolkit.evm.shimmer.network', + hasFaucet: false, + }, + api: 'https://api.evm.shimmer.network', + }, + }, + }, + shimmer_testnet: { + baseToken: 'Testnet Token (no value)', + protocol: 'Stardust', + httpRestApi: 'https://api.testnet.shimmer.network', + eventApi: 'wss://api.testnet.shimmer.network:443/api/mqtt/v1 (MQTT 3.1)', + permaNodeApi: 'https://chronicle.testnet.shimmer.network', + faucet: 'https://faucet.testnet.shimmer.network', + explorer: 'https://explorer.shimmer.network/shimmer-testnet', + evm: { + core: { + chainId: '0x431', + chainName: 'ShimmerEVM Testnet', + nativeCurrency: { + name: 'Shimmer', + symbol: 'SMR', + decimals: 18, + }, + rpcUrls: ['https://json-rpc.evm.testnet.shimmer.network'], + blockExplorerUrls: ['https://explorer.evm.testnet.shimmer.network/'], + }, + custom: { + chainAddress: + 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', + aliasId: + '0x42f7da9bdb55b3ec87e5ac1a1e6d88e16768663fde5eca3429eb6f579cc538ac', + toolkit: { + url: 'https://evm-toolkit.evm.testnet.shimmer.network', + hasFaucet: true, + }, + api: 'https://api.evm.testnet.shimmer.network', + }, + }, + }, +}; + +export interface Toolkit { + url: string; + hasFaucet: boolean; +} + +// This is just a copy of https://github.com/MetaMask/metamask-sdk/blob/890ec432439705af4c8d02281b7447a1a4f94de3/packages/sdk-react-ui/src/hooks/MetaMaskWagmiHooks.ts#L25-L36 +// and should not be touched +export interface AddEthereumChainParameter { + chainId: string; // A 0x-prefixed hexadecimal string + chainName: string; + nativeCurrency?: { + name: string; + symbol: string; // 2-6 characters long + decimals: number; + }; + rpcUrls?: string[]; + blockExplorerUrls?: string[]; + iconUrls?: string[]; // Currently ignored. +} + +export interface EVMProps { + core: AddEthereumChainParameter; + tools?: { + blastApiUrls?: Array; + }; + custom: { + chainAddress: string; + aliasId: string; + api: string; + toolkit: Toolkit; + }; +} + +export interface NetworkProps { + baseToken: string; + protocol: string; + httpRestApi: string; + eventApi: string; + permaNodeApi: string; + faucet?: string; + explorer: string; + evm?: EVMProps; +} diff --git a/src/utils/config.js b/src/utils/config.js index 27c67533e27..437e2a3ecba 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -1,5 +1,5 @@ const path = require('path'); -const defaultSettings = require('../common/defaultContentPlugin'); +const defaultSettings = require('./defaultContentPlugin'); const fs = require('fs'); /** @@ -129,8 +129,8 @@ async function create_doc_plugin({ ...options }) { } return [ - '@iota-wiki/plugin-docs', - /** @type {import('@iota-wiki/plugin-docs').Options} */ + './src/plugins/docs', + /** @type {import('../plugins/docs').Options} */ ({ ...setting, ...options, diff --git a/src/common/defaultContentPlugin.js b/src/utils/defaultContentPlugin.js similarity index 89% rename from src/common/defaultContentPlugin.js rename to src/utils/defaultContentPlugin.js index a2079d57bb0..050ec334931 100644 --- a/src/common/defaultContentPlugin.js +++ b/src/utils/defaultContentPlugin.js @@ -1,7 +1,7 @@ /** @type {import('@docusaurus/plugin-content-docs').Options} */ module.exports = async () => { const jargonPlugin = (await import('rehype-jargon')).default; - const jargonConfig = (await import('./../../common/jargon.js')).default; + const jargonConfig = (await import('../../config/jargon.js')).default; return { editUrl: 'https://github.com/iotaledger/iota-wiki/edit/main/', diff --git a/src/utils/pluginConfigGenerators.js b/src/utils/pluginConfigGenerators.js index 864841a20a6..4cd7f6769f3 100644 --- a/src/utils/pluginConfigGenerators.js +++ b/src/utils/pluginConfigGenerators.js @@ -23,19 +23,22 @@ function generatePluginConfig(pluginConfig, basePath) { return doc.versions.map((version) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { label, badges, ...rest } = version; + const { label, badges, banner, ...rest } = version; // TODO: This could be removed once we don't use points in paths anymore. const plugin_name_path = doc.routeBasePath ? doc.routeBasePath : doc.id; - const extended_base_path = - basePath + plugin_name_path + '/' + (label ? label : ''); + const extended_base_path = [ + basePath, + plugin_name_path, + ...(label ? [label] : []), + ].join('/'); plugin = { id: doc.id + (label ? '-' + label.replace(/\./g, '-') : ''), - path: path.resolve(extended_base_path + '/docs'), + path: path.resolve(extended_base_path, 'docs'), routeBasePath: plugin_name_path, - sidebarPath: path.resolve(extended_base_path + '/sidebars.js'), + sidebarPath: path.resolve(extended_base_path, 'sidebars.js'), ...(doc.versions.length > 1 ? { versions: { @@ -43,6 +46,7 @@ function generatePluginConfig(pluginConfig, basePath) { label, path: mainVersion.label === label ? undefined : label, badge: true, + banner, }, }, } diff --git a/src/utils/tags.ts b/src/utils/tags.ts index 367cf687caf..465660936b2 100644 --- a/src/utils/tags.ts +++ b/src/utils/tags.ts @@ -1,5 +1,5 @@ //TODO tutorial.json should propably be a key-value dictionary -import config from '../../tutorials/tags.json'; +import config from '../../config/tags.json'; export interface Tag { label: string; diff --git a/static/icons/iota/iota_evm.svg b/static/icons/iota/iota_evm.svg new file mode 100644 index 00000000000..6062f9fb96c --- /dev/null +++ b/static/icons/iota/iota_evm.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/iota/iota_evm_dm.svg b/static/icons/iota/iota_evm_dm.svg new file mode 100644 index 00000000000..9096955db5f --- /dev/null +++ b/static/icons/iota/iota_evm_dm.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/get-started/safe/safe.png b/static/img/get-started/safe/safe.png new file mode 100644 index 00000000000..5f0a8f60720 Binary files /dev/null and b/static/img/get-started/safe/safe.png differ diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-A.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-A.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-A.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-B.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-B.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-B.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-C.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-C.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-C.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-D.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-D.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-D.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-D.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-E.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-E.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-E.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-F.jpg b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-F.jpg similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-F.jpg rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-F.jpg diff --git a/tutorials/static/IOTA-Smart-Contract-Tutorials-G.png b/static/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png similarity index 100% rename from tutorials/static/IOTA-Smart-Contract-Tutorials-G.png rename to static/img/tutorials/IOTA-Smart-Contract-Tutorials-G.png diff --git a/tutorials/static/connect-shimmerevm-and-deploy.png b/static/img/tutorials/connect-shimmerevm-and-deploy.png similarity index 100% rename from tutorials/static/connect-shimmerevm-and-deploy.png rename to static/img/tutorials/connect-shimmerevm-and-deploy.png diff --git a/tutorials/static/connect-shimmerevm-testnet-and-deploy.png b/static/img/tutorials/connect-shimmerevm-testnet-and-deploy.png similarity index 100% rename from tutorials/static/connect-shimmerevm-testnet-and-deploy.png rename to static/img/tutorials/connect-shimmerevm-testnet-and-deploy.png diff --git a/tutorials/static/create-nft-with-wallet-lib.png b/static/img/tutorials/create-nft-with-wallet-lib.png similarity index 100% rename from tutorials/static/create-nft-with-wallet-lib.png rename to static/img/tutorials/create-nft-with-wallet-lib.png diff --git a/tutorials/static/evm-toolkit-custom-network.png b/static/img/tutorials/evm-toolkit-custom-network.png similarity index 100% rename from tutorials/static/evm-toolkit-custom-network.png rename to static/img/tutorials/evm-toolkit-custom-network.png diff --git a/tutorials/static/evm-toolkit.png b/static/img/tutorials/evm-toolkit.png similarity index 100% rename from tutorials/static/evm-toolkit.png rename to static/img/tutorials/evm-toolkit.png diff --git a/tutorials/static/hornet-inx-interaction.png b/static/img/tutorials/hornet-inx-interaction.png similarity index 100% rename from tutorials/static/hornet-inx-interaction.png rename to static/img/tutorials/hornet-inx-interaction.png diff --git a/tutorials/static/metamask-shimmerevm-mainnet.png b/static/img/tutorials/metamask-shimmerevm-mainnet.png similarity index 100% rename from tutorials/static/metamask-shimmerevm-mainnet.png rename to static/img/tutorials/metamask-shimmerevm-mainnet.png diff --git a/tutorials/static/metamask-shimmerevm.png b/static/img/tutorials/metamask-shimmerevm.png similarity index 100% rename from tutorials/static/metamask-shimmerevm.png rename to static/img/tutorials/metamask-shimmerevm.png diff --git a/tutorials/static/nft-image.jpg b/static/img/tutorials/nft-image.jpg similarity index 100% rename from tutorials/static/nft-image.jpg rename to static/img/tutorials/nft-image.jpg diff --git a/tutorials/static/proof-inclusion-of-a-block-architecture.png b/static/img/tutorials/proof-inclusion-of-a-block-architecture.png similarity index 100% rename from tutorials/static/proof-inclusion-of-a-block-architecture.png rename to static/img/tutorials/proof-inclusion-of-a-block-architecture.png diff --git a/tutorials/static/proof-inclusion-of-a-block.png b/static/img/tutorials/proof-inclusion-of-a-block.png similarity index 100% rename from tutorials/static/proof-inclusion-of-a-block.png rename to static/img/tutorials/proof-inclusion-of-a-block.png diff --git a/tutorials/static/send-iota-tokens-with-javascript.svg b/static/img/tutorials/send-iota-tokens-with-javascript.svg similarity index 100% rename from tutorials/static/send-iota-tokens-with-javascript.svg rename to static/img/tutorials/send-iota-tokens-with-javascript.svg diff --git a/tutorials/static/send-shimmer-tokens-with-iota-sdk.png b/static/img/tutorials/send-shimmer-tokens-with-iota-sdk.png similarity index 100% rename from tutorials/static/send-shimmer-tokens-with-iota-sdk.png rename to static/img/tutorials/send-shimmer-tokens-with-iota-sdk.png diff --git a/tutorials/static/send-shimmer-tokens-with-javascript.png b/static/img/tutorials/send-shimmer-tokens-with-javascript.png similarity index 100% rename from tutorials/static/send-shimmer-tokens-with-javascript.png rename to static/img/tutorials/send-shimmer-tokens-with-javascript.png diff --git a/tutorials/static/setup_iota-js_for_development.png b/static/img/tutorials/setup_iota-js_for_development.png similarity index 100% rename from tutorials/static/setup_iota-js_for_development.png rename to static/img/tutorials/setup_iota-js_for_development.png diff --git a/tutorials/static/shimmer-hardhat-setup.png b/static/img/tutorials/shimmer-hardhat-setup.png similarity index 100% rename from tutorials/static/shimmer-hardhat-setup.png rename to static/img/tutorials/shimmer-hardhat-setup.png diff --git a/tutorials/static/shimmer-testnet-faucet.png b/static/img/tutorials/shimmer-testnet-faucet.png similarity index 100% rename from tutorials/static/shimmer-testnet-faucet.png rename to static/img/tutorials/shimmer-testnet-faucet.png diff --git a/tutorials/static/shimmerevm-dapp-voting.jpg b/static/img/tutorials/shimmerevm-dapp-voting.jpg similarity index 100% rename from tutorials/static/shimmerevm-dapp-voting.jpg rename to static/img/tutorials/shimmerevm-dapp-voting.jpg diff --git a/tutorials/static/shimmerevm-hardhat.jpg b/static/img/tutorials/shimmerevm-hardhat.jpg similarity index 100% rename from tutorials/static/shimmerevm-hardhat.jpg rename to static/img/tutorials/shimmerevm-hardhat.jpg diff --git a/tutorials/static/voting-dapp.jpg b/static/img/tutorials/voting-dapp.jpg similarity index 100% rename from tutorials/static/voting-dapp.jpg rename to static/img/tutorials/voting-dapp.jpg diff --git a/tutorials/static/wallet-setup.png b/static/img/tutorials/wallet-setup.png similarity index 100% rename from tutorials/static/wallet-setup.png rename to static/img/tutorials/wallet-setup.png diff --git a/tutorials/static/wasp-setup-shimmer.png b/static/img/tutorials/wasp-setup-shimmer.png similarity index 100% rename from tutorials/static/wasp-setup-shimmer.png rename to static/img/tutorials/wasp-setup-shimmer.png diff --git a/screenshot.css b/tests/screenshot.css similarity index 100% rename from screenshot.css rename to tests/screenshot.css diff --git a/screenshot.spec.ts b/tests/screenshot.spec.ts similarity index 91% rename from screenshot.spec.ts rename to tests/screenshot.spec.ts index 4ca0a67a310..fc120009b8c 100644 --- a/screenshot.spec.ts +++ b/tests/screenshot.spec.ts @@ -5,8 +5,8 @@ import { extractSitemapPathnames, pathnameToArgosName } from './utils'; // Constants const siteUrl = 'http://localhost:3000'; -const sitemapPath = './build/sitemap.xml'; -const stylesheetPath = './screenshot.css'; +const sitemapPath = require.resolve('../build/sitemap.xml'); +const stylesheetPath = require.resolve('./screenshot.css'); const stylesheet = fs.readFileSync(stylesheetPath).toString(); // Wait for hydration, requires Docusaurus v2.4.3+ diff --git a/utils.ts b/tests/utils.ts similarity index 100% rename from utils.ts rename to tests/utils.ts diff --git a/theme/.gitignore b/theme/.gitignore deleted file mode 100644 index 9b1c8b133c9..00000000000 --- a/theme/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/dist diff --git a/theme/README.md b/theme/README.md deleted file mode 100644 index 6f553ec6216..00000000000 --- a/theme/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# IOTA Theme - -The IOTA Wiki theme for Docusaurus. - -## Installation - -Add `@iota-wiki/theme` to your package: - -```bash -npm i @iota-wiki/theme -# or -yarn add @iota-wiki/theme -``` - -Modify your `docusaurus.config.js`: - -```diff -module.exports = { - ... -+ themes: ['@iota-wiki/theme'], - ... -} -``` - -## Components - -### AddToMetaMaskButton - -A button to add the ShimmerEVM network to MetaMask. - -``` -import { AddToMetaMaskButton } from '@theme/AddToMetaMaskButton' -import { Networks } from '@theme/constant' - - -``` - -### CodeSnippetBlock - -This component finds `startString` and `endString` in a code listing and displays the snippet in between. - -``` -import CodeSnippetBlock from '@theme/CodeSnippetBlock' -import code_snippet from '!!raw-loader!../../code_snippet.py' - - -``` - -### NetworkInfo - -A set of components showing information about the different networks. - -``` -import NetworkInfo from '@theme/NetworkInfo' -import { Networks } from '@theme/constant' - - - - -``` - -## Swizzling components - -```bash -npm swizzle @iota-wiki/theme [component name] -``` - -All components used by this theme can be found [here](https://github.com/iota-wiki/iota-wiki/tree/main/theme/src/theme) diff --git a/theme/package.json b/theme/package.json deleted file mode 100644 index a6cefe462c0..00000000000 --- a/theme/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "@iota-wiki/theme", - "version": "0.1.0", - "description": "IOTA Wiki theme components", - "main": "dist/index.js", - "types": "src/types.d.ts", - "license": "MIT", - "scripts": { - "copy": "copyfiles -u 1 \"./src/**/*.css\" \"./dist\"", - "build": "tsc --build && yarn copy && prettier --config ../.prettierrc.json --write \"dist/theme/**/*.js\"", - "watch": "nodemon --watch src --ext '*' --exec yarn build", - "prepack": "yarn build", - "test": "jest" - }, - "dependencies": { - "@artsy/to-title-case": "^1.1.0", - "@docusaurus/theme-classic": "2.4.3", - "@docusaurus/theme-common": "2.4.3", - "@iota-wiki/plugin-docs": "workspace:^", - "@metamask/providers": "^10.2.1", - "clsx": "^1.2.1", - "html-react-parser": "^4.2.10", - "react-markdown": "6", - "web3": "^4.2.2" - }, - "devDependencies": { - "@docusaurus/types": "2.4.3", - "@types/react": "18.2.71", - "copyfiles": "^2.4.1", - "nodemon": "^2.0.16", - "prettier": "^2.8.8", - "react": "18.2.0", - "typescript": "^4.9" - }, - "peerDependencies": { - "react": "*" - }, - "files": [ - "./src", - "./dist" - ], - "packageManager": "yarn@3.2.0", - "engines": { - "node": ">=14.0.0" - } -} diff --git a/theme/src/index.ts b/theme/src/index.ts deleted file mode 100644 index bd691e320cd..00000000000 --- a/theme/src/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Plugin } from '@docusaurus/types'; - -export default function iotaWikiTheme(): Plugin { - return { - name: '@iota-wiki/theme', - - getThemePath() { - return '../dist/theme'; - }, - getTypeScriptThemePath() { - return '../src/theme'; - }, - }; -} diff --git a/theme/src/theme/DocBanner/index.tsx b/theme/src/theme/DocBanner/index.tsx deleted file mode 100644 index 7e01bbf6946..00000000000 --- a/theme/src/theme/DocBanner/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { useDoc } from '@docusaurus/theme-common/internal'; -import { DocMetadata } from '@iota-wiki/plugin-docs'; -import ReactMarkdown from 'react-markdown'; -import './styles.css'; - -export default function DocBanner() { - const { bannerContent } = useDoc().metadata as DocMetadata; - - if (!bannerContent) return null; - - return ( - - {bannerContent} - - ); -} diff --git a/theme/src/theme/DocBanner/styles.css b/theme/src/theme/DocBanner/styles.css deleted file mode 100644 index 6af2f55eacf..00000000000 --- a/theme/src/theme/DocBanner/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -.doc-banner p { - margin: 0; -} - -.doc-banner p + p { - margin: var(--ifm-paragraph-margin-bottom) 0 0; -} diff --git a/theme/src/theme/NetworkInfo/index.tsx b/theme/src/theme/NetworkInfo/index.tsx deleted file mode 100644 index 15735129435..00000000000 --- a/theme/src/theme/NetworkInfo/index.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import React from 'react'; -import { ChainId } from '../ChainId'; -import { NetworkProps } from '../constant'; -import CodeBlock from '@theme/CodeBlock'; - -function L1(props: NetworkProps) { - return ( - - - - - - - - - - - - - - - - - - - -
Base TokenProtocolHTTP REST APIEvent APIPermanode API
{props.baseToken}{props.protocol} - -

{props.httpRestApi}

-
-
{props.eventApi} - - {props.permaNodeApi} - -
- ); -} - -function Evm(props: NetworkProps) { - return ( - - - - - - - - - - - - - - - - - - - -
Base TokenProtocolChain IDRPC URLExplorer
{props.baseToken}ISC / EVM - - - {props.evm.rpcUrls.map((url, index) => ( - {url} - ))} - - - {props.evm.blockExplorerUrls[0]} - -
- ); -} - -function EvmCustom(props: NetworkProps) { - return ( - - - - - - - - - - - - - -
Chain AddressAlias ID
- - {props.evmCustom.chainAddress} - - {props.evmCustom.aliasId}
- ); -} - -export default { - L1, - Evm, - EvmCustom, -}; diff --git a/theme/src/theme/constant.tsx b/theme/src/theme/constant.tsx deleted file mode 100644 index c38cd15b367..00000000000 --- a/theme/src/theme/constant.tsx +++ /dev/null @@ -1,130 +0,0 @@ -export const Networks = { - iota: { - baseToken: 'IOTA Token', - protocol: 'Stardust', - httpRestApi: 'https://api.stardust-mainnet.iotaledger.net', - eventApi: 'wss://api.stardust-mainnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', - permaNodeApi: 'https://chronicle.stardust-mainnet.iotaledger.net', - explorer: 'https://explorer.iota.org/mainnet', - }, - iota_2_testnet: { - baseToken: 'Testnet Token (no value)', - protocol: 'IOTA 2.0', - httpRestApi: 'https://api.nova-testnet.iotaledger.net/', - eventApi: 'wss://api.nova-testnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', - permaNodeApi: 'https://chronicle.nova-testnet.iotaledger.net', - explorer: 'https://explorer.iota.org/iota2-testnet', - faucet: 'https://faucet.nova-testnet.iotaledger.net', - }, - iota_testnet: { - baseToken: 'Testnet Token (no value)', - protocol: 'Stardust', - httpRestApi: 'https://api.testnet.iotaledger.net', - eventApi: 'wss://api.testnet.iotaledger.net:443 (MQTT 3.1, /mqtt)', - permaNodeApi: 'https://chronicle.testnet.iotaledger.net', - faucet: 'https://faucet.testnet.iotaledger.net', - explorer: 'https://explorer.iota.org/iota-testnet', - evm: { - chainId: '0x433', - chainName: 'IOTA EVM Testnet', - nativeCurrency: { - name: 'IOTA', - symbol: 'IOTA', - decimals: 18, - }, - rpcUrls: [ - 'https://json-rpc.evm.testnet.iotaledger.net', - 'wss://ws.json-rpc.evm.testnet.iotaledger.net', - ], - blockExplorerUrls: ['https://explorer.evm.testnet.iotaledger.net'], - }, - evmCustom: { - chainAddress: - 'tst1pzxsrr7apqkdzz633dyntmvxwtyvk029p39te5j0m33q6946h7akzv663zu', - aliasId: - '0x8d018fdd082cd10b518b4935ed8672c8cb3d450c4abcd24fdc620d16babfbb61', - }, - }, - shimmer: { - baseToken: 'Shimmer Token', - protocol: 'Stardust', - httpRestApi: 'https://api.shimmer.network', - eventApi: 'wss://api.shimmer.network:443/api/mqtt/v1 (MQTT 3.1)', - permaNodeApi: 'https://chronicle.shimmer.network', - explorer: 'https://explorer.shimmer.network/shimmer', - evm: { - chainId: '0x94', - chainName: 'ShimmerEVM', - nativeCurrency: { - name: 'Shimmer', - symbol: 'SMR', - decimals: 18, - }, - rpcUrls: [ - 'https://json-rpc.evm.shimmer.network', - 'wss://ws.json-rpc.evm.shimmer.network', - ], - blockExplorerUrls: ['https://explorer.evm.shimmer.network/'], - }, - evmCustom: { - chainAddress: - 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', - aliasId: - '0xccc7018e4fa63e5014332f45ddc8a5450da89572676d12d4d5e51c98d64155b3', - }, - }, - shimmer_testnet: { - baseToken: 'Testnet Token (no value)', - protocol: 'Stardust', - httpRestApi: 'https://api.testnet.shimmer.network', - eventApi: 'wss://api.testnet.shimmer.network:443/api/mqtt/v1 (MQTT 3.1)', - permaNodeApi: 'https://chronicle.testnet.shimmer.network', - faucet: 'https://faucet.testnet.shimmer.network', - explorer: 'https://explorer.shimmer.network/shimmer-testnet', - evm: { - chainId: '0x431', - chainName: 'ShimmerEVM Testnet', - nativeCurrency: { - name: 'Shimmer', - symbol: 'SMR', - decimals: 18, - }, - rpcUrls: ['https://json-rpc.evm.testnet.shimmer.network'], - blockExplorerUrls: ['https://explorer.evm.testnet.shimmer.network/'], - }, - evmCustom: { - chainAddress: - 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', - aliasId: - '0x42f7da9bdb55b3ec87e5ac1a1e6d88e16768663fde5eca3429eb6f579cc538ac', - }, - }, -}; - -export interface AddEthereumChainParameter { - chainId: string; // A 0x-prefixed hexadecimal string - chainName: string; - nativeCurrency?: { - name: string; - symbol: string; // 2-6 characters long - decimals: number; - }; - rpcUrls?: string[]; - blockExplorerUrls?: string[]; - iconUrls?: string[]; // Currently ignored. -} - -export interface NetworkProps { - baseToken: string; - protocol: string; - httpRestApi: string; - eventApi: string; - permaNodeApi: string; - faucet?: string; - explorer: string; - evm: AddEthereumChainParameter; - evmCustom: { - chainAddress: string; - aliasId: string; - }; -} diff --git a/theme/src/types.d.ts b/theme/src/types.d.ts deleted file mode 100644 index e6678212569..00000000000 --- a/theme/src/types.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// - -declare module '@theme/CodeSnippetBlock' { - import type { Props as BaseProps } from '@theme/CodeBlock'; - - export interface Props extends Omit { - language: string; - code: string; - startString?: string; - endString?: string; - } - - export default function CodeSnippetBlock(props: Props): JSX.Element; -} - -declare module '@theme/AddToMetaMaskButton' { - export default function AddToMetaMaskButton(): JSX.Element; -} - -declare module '@theme/DocBanner' { - export default function DocBanner(): JSX.Element; -} - -declare module '@theme/NetworkInfo' { - export default { - IOTA: JSX.Element, - Shimmer: JSX.Element, - ShimmerEVM: JSX.Element, - ShimmerEVMAdditional: JSX.Element, - Testnet: JSX.Element, - TestnetEVM: JSX.Element, - TestnetEVMAdditional: JSX.Element, - }; -} diff --git a/theme/tsconfig.client.json b/theme/tsconfig.client.json deleted file mode 100644 index bcd29911eb3..00000000000 --- a/theme/tsconfig.client.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - /* Emit */ - "rootDir": "src", - "outDir": "dist", - "noEmit": false, - "composite": true, - "incremental": true, - "tsBuildInfoFile": "./dist/.tsbuildinfo-client", - "module": "ESNext" - }, - "include": ["src/theme", "src/*.d.ts"], - "exclude": ["**/__tests__/**"] -} diff --git a/theme/tsconfig.json b/theme/tsconfig.json deleted file mode 100644 index 6c16c42462a..00000000000 --- a/theme/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "references": [ - { "path": "./tsconfig.client.json" }, - { "path": "./tsconfig.server.json" } - ], - "compilerOptions": { - /* Emit */ - "target": "ES2020", - "declaration": true, - "jsx": "react-native", - "noEmit": true, - // Will be overridden for client code - "module": "NodeNext", - - /* Module Resolution */ - "moduleResolution": "NodeNext", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "isolatedModules": true, - "skipLibCheck": true, - "allowJs": true - } -} diff --git a/theme/tsconfig.server.json b/theme/tsconfig.server.json deleted file mode 100644 index 8fef396d8db..00000000000 --- a/theme/tsconfig.server.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - /* Emit */ - "rootDir": "src", - "outDir": "dist", - "noEmit": false, - "composite": true, - "incremental": true, - "tsBuildInfoFile": "./dist/.tsbuildinfo" - }, - "include": ["src"], - "exclude": ["src/theme", "**/__tests__/**"] -} diff --git a/tutorials/docusaurus.config.js b/tutorials/docusaurus.config.js deleted file mode 100644 index 8579dc6c807..00000000000 --- a/tutorials/docusaurus.config.js +++ /dev/null @@ -1,255 +0,0 @@ -const path = require('path'); - -module.exports = { - plugins: [ - [ - '@docusaurus/plugin-content-pages', - { - id: 'single-page-tutorials', - path: path.resolve(__dirname, 'pages'), - routeBasePath: '/tutorials', - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Run a Wasp Node', - description: 'In this tutorial you will learn how to run a wasp node.', - preview: '/IOTA-Smart-Contract-Tutorials-A.jpg', - route: '/wasp/how-tos/running-a-node', - tags: ['text', 'video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Run a Wasp Chain', - description: 'In this tutorial you will learn how to run a wasp chain.', - preview: '/IOTA-Smart-Contract-Tutorials-B.jpg', - route: '/wasp/how-tos/setting-up-a-chain', - tags: ['text', 'video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Deploy a WASM Smart Contract', - description: - 'In this tutorial you will learn how to deploy a wasm smart contract.', - preview: '/IOTA-Smart-Contract-Tutorials-C.jpg', - route: '/wasp/how-tos/setting-up-a-chain#deploying-a-wasm-contract', - tags: ['text', 'video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Deploy a Solidity Smart Contract Using Remix + Metamask', - description: - 'In this tutorial you will learn how to deploy a solidity smart contract on EVM using remix and metamask.', - preview: '/IOTA-Smart-Contract-Tutorials-E.jpg', - route: '/isc/getting-started/tools#remix', - tags: ['text', 'video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Generate a WASM Smart Contract Using the Schema Tool', - description: - 'In this tutorial you will learn how to use schema tool to generate smart contract template code on rust and golang', - preview: '/IOTA-Smart-Contract-Tutorials-G.png', - route: '/isc/schema/how-tos/usage', - tags: ['text', 'video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: - 'Generate a WASM Smart Contract Using the Schema Tool in Typescript', - description: - 'In this tutorial you will learn how to use schema tool to generate smart contract template code on typescript', - preview: '/IOTA-Smart-Contract-Tutorials-G.png', - route: 'https://www.youtube.com/watch?v=P5HMgmY3DMM', - tags: ['video'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Interact with IOTA Node Extension (INX)', - description: - 'In this tutorial you will learn how to interact with the IOTA Node Extension (INX) interface based on gRPC.', - preview: '/hornet-inx-interaction.png', - route: 'tutorials/hornet-inx-interaction', - tags: ['text', 'getting-started', 'shimmer', 'js'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Tokenless Data Notarization', - description: - 'Proove that a block was part of the past Tangle, even if this part of the Tangle was already pruned from network nodes.', - preview: '/proof-inclusion-of-a-block.png', - route: 'tutorials/proof-inclusion-of-a-block', - tags: ['text', 'getting-started', 'js', 'client', 'shimmer'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Set Up a Testnet Address and Receive Funds From the Faucet', - description: - 'In this tutorial you will learn how to create a seed and address with wallet.rs and receive testnet tokens from the faucet.', - preview: '/wallet-setup.png', - route: 'tutorials/wallet-setup', - tags: ['text', 'getting-started', 'node_js', 'wallet', 'shimmer'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'How to Set Up iota.js for Development', - description: - 'In this tutorial you will learn how to create a new project, generate a new address and receive x funds from the faucet.', - preview: '/setup_iota-js_for_development.png', - route: 'tutorials/setup_iota-js_for_development', - tags: ['text', 'getting-started', 'client', 'shimmer', 'js'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: - 'Connect to Shimmer EVM Testnet and Deploy a Solidity Smart Contract', - description: - 'In this tutorial, we will connect to Shimmer EVM Testnet, connect Metamask to it, get funded and deploy a smart contract in Solidity.', - preview: '/connect-shimmerevm-testnet-and-deploy.png', - route: 'tutorials/shimmerevm-testnet-setup', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'getting-started', - 'wasp', - 'iscp', - 'video', - ], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: - 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Testnet Using Hardhat', - description: - 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', - preview: '/shimmerevm-hardhat.jpg', - route: 'tutorials/shimmerevm-testnet-hardhat', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'shimmerevm', - 'hardhat', - 'iscp', - 'video', - ], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Create a Simple Voting dApp on ShimmerEVM', - description: - 'This tutorial will guide you as you write and deploy a voting dApp on ShimmerEVM. You can vote on a few options and view the results; all data will be stored on-chain.', - preview: '/shimmerevm-dapp-voting.jpg', - route: 'tutorials/shimmerevm-dapp-voting', - tags: ['text', 'shimmer', 'solidity', 'iscp'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Set Up WASP locally Using Docker', - description: - 'In this tutorial you will learn how to set up WASP and Hornet locally for Development setup.', - preview: '/wasp-setup-shimmer.png', - route: 'https://youtu.be/ltem9Bh_4hA', - tags: ['text', 'shimmer', 'video', 'wasp', 'iscp'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Create an NFT with the IOTA SDK and IPFS in NodeJs', - description: - 'In this tutorial you will learn how to create a NFT on the Shimmer network with iota-sdk and IPFS.', - preview: '/create-nft-with-wallet-lib.png', - route: 'tutorials/create-nft-with-iota-sdk', - tags: [ - 'text', - 'getting-started', - 'node_js', - 'iota-sdk', - 'ipfs', - 'shimmer', - 'sdk', - ], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Send Shimmer Tokens with IOTA SDK in NodeJs', - description: - 'In this tutorial you will learn how to send Shimmer Tokens with IOTA SDK in NodeJs.', - preview: '/send-shimmer-tokens-with-iota-sdk.png', - route: 'tutorials/send-shimmer-tokens-with-iota-sdk', - tags: ['text', 'iota-sdk', 'sdk', 'getting-started', 'rust', 'shimmer'], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: 'Connect to Shimmer EVM and Deploy a Solidity Smart Contract', - description: - 'In this tutorial, we will connect to Shimmer EVM, connect Metamask to it, get funded and deploy a smart contract in Solidity.', - preview: '/connect-shimmerevm-and-deploy.png', - route: 'tutorials/shimmerevm-setup', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'getting-started', - 'wasp', - 'iscp', - 'video', - ], - }, - ], - [ - '@iota-wiki/plugin-tutorial', - { - title: - 'Tutorial - Deploy a Solidity Smart Contract on ShimmerEVM Using Hardhat', - description: - 'In this tutorial, you will learn how to set up Hardhat and use it to build, test and deploy a simple smart contract on ShimmerEVM.', - preview: '/shimmerevm-hardhat.jpg', - route: 'tutorials/shimmerevm-hardhat', - tags: [ - 'text', - 'shimmer', - 'solidity', - 'shimmerevm', - 'hardhat', - 'iscp', - 'video', - ], - }, - ], - ], - staticDirectories: [path.resolve(__dirname, 'static')], -}; diff --git a/yarn.lock b/yarn.lock index 6f1babc382f..9b2bec32341 100644 --- a/yarn.lock +++ b/yarn.lock @@ -218,16 +218,14 @@ __metadata: languageName: node linkType: hard -"@apidevtools/json-schema-ref-parser@npm:^10.1.0": - version: 10.1.0 - resolution: "@apidevtools/json-schema-ref-parser@npm:10.1.0" +"@apidevtools/json-schema-ref-parser@npm:^11.5.4": + version: 11.6.2 + resolution: "@apidevtools/json-schema-ref-parser@npm:11.6.2" dependencies: "@jsdevtools/ono": ^7.1.3 - "@types/json-schema": ^7.0.11 - "@types/lodash.clonedeep": ^4.5.7 + "@types/json-schema": ^7.0.15 js-yaml: ^4.1.0 - lodash.clonedeep: ^4.5.0 - checksum: 6220dea1ffa2f1b34da54583cf447cc97c51e25b96c10705e858f42c8290bc775b5821182282493a8f99ec6e0dae8f01ccd865d547aa29c1a6be6a38713c4571 + checksum: 4baa460fe43634cd60440bce8e8af3c52c710eb0f5a8be19640bc7ae65936860e3e2bc158dbbfa18fb12acd470e2106b8fc792f7d93918ba14d301cc810ae904 languageName: node linkType: hard @@ -1775,16 +1773,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.9.6": - version: 7.9.6 - resolution: "@babel/runtime@npm:7.9.6" - dependencies: - regenerator-runtime: ^0.13.4 - checksum: 67cd41b670af1b2c5f7b5f0fb385b025dd645bfea0e43c0a46edf7599f84312383278333d023b9624743c986183076c96fbfeb9f8d302fe79bd134fa669d9a5c - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.24.0 resolution: "@babel/runtime@npm:7.24.0" dependencies: @@ -2080,7 +2069,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/plugin-content-docs@npm:2.4.3, @docusaurus/plugin-content-docs@npm:>=2.3.0 <2.5.0": +"@docusaurus/plugin-content-docs@npm:2.4.3, @docusaurus/plugin-content-docs@npm:>=2.4.1 <=2.4.3": version: 2.4.3 resolution: "@docusaurus/plugin-content-docs@npm:2.4.3" dependencies: @@ -2291,7 +2280,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/theme-common@npm:2.4.3, @docusaurus/theme-common@npm:>=2.3.0 <2.5.0": +"@docusaurus/theme-common@npm:2.4.3, @docusaurus/theme-common@npm:>=2.4.1 <=2.4.3": version: 2.4.3 resolution: "@docusaurus/theme-common@npm:2.4.3" dependencies: @@ -2388,7 +2377,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/utils-validation@npm:2.4.3, @docusaurus/utils-validation@npm:>=2.3.0 <2.5.0": +"@docusaurus/utils-validation@npm:2.4.3, @docusaurus/utils-validation@npm:>=2.4.1 <=2.4.3": version: 2.4.3 resolution: "@docusaurus/utils-validation@npm:2.4.3" dependencies: @@ -2401,7 +2390,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/utils@npm:2.4.3, @docusaurus/utils@npm:>=2.3.0 <2.5.0": +"@docusaurus/utils@npm:2.4.3, @docusaurus/utils@npm:>=2.4.1 <=2.4.3": version: 2.4.3 resolution: "@docusaurus/utils@npm:2.4.3" dependencies: @@ -2631,55 +2620,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.18.2": - version: 1.18.2 - resolution: "@formatjs/ecma402-abstract@npm:1.18.2" - dependencies: - "@formatjs/intl-localematcher": 0.5.4 - tslib: ^2.4.0 - checksum: c664056ccab4e3407feabd5802276075eae2b614acb8c5979045ff5a70bfec4c04488188c30b311b6db0e0eb0b5c1ca328868d76472a14243c944bc0639e8a4d - languageName: node - linkType: hard - -"@formatjs/fast-memoize@npm:2.2.0": - version: 2.2.0 - resolution: "@formatjs/fast-memoize@npm:2.2.0" - dependencies: - tslib: ^2.4.0 - checksum: 8697fe72a7ece252d600a7d08105f2a2f758e2dd96f54ac0a4c508b1205a559fc08835635e1f8e5ca9dcc3ee61ce1fca4a0e7047b402f29fc96051e293a280ff - languageName: node - linkType: hard - -"@formatjs/icu-messageformat-parser@npm:2.7.6": - version: 2.7.6 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.6" - dependencies: - "@formatjs/ecma402-abstract": 1.18.2 - "@formatjs/icu-skeleton-parser": 1.8.0 - tslib: ^2.4.0 - checksum: d537253cbfe0515c0b72495b1133528a6643f23f978f6d9576defe5150dbb4b9b4e4b7028e2ff1bfaa4d104b05aa1119688d3fb7a4cf9b1b78ba8019a6adfeb1 - languageName: node - linkType: hard - -"@formatjs/icu-skeleton-parser@npm:1.8.0": - version: 1.8.0 - resolution: "@formatjs/icu-skeleton-parser@npm:1.8.0" - dependencies: - "@formatjs/ecma402-abstract": 1.18.2 - tslib: ^2.4.0 - checksum: 85ca45148a8535c61f2667d24d3e59ab97cd2b4accee8383594872a319e875effae7d54e070fd0d3926fc1407b04f5685f94336c1d0d587fcb1064bb498e5319 - languageName: node - linkType: hard - -"@formatjs/intl-localematcher@npm:0.5.4": - version: 0.5.4 - resolution: "@formatjs/intl-localematcher@npm:0.5.4" - dependencies: - tslib: ^2.4.0 - checksum: a0af57874fcd163add5f7a0cb1c008e9b09feb1d24cbce1263379ae0393cddd6681197a7f2f512f351a97666fc8675ed52cc17d1834266ee8fc65e9edf3435f6 - languageName: node - linkType: hard - "@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": version: 9.3.0 resolution: "@hapi/hoek@npm:9.3.0" @@ -2732,52 +2672,6 @@ __metadata: languageName: node linkType: hard -"@internationalized/date@npm:3.0.0-rc.1": - version: 3.0.0-rc.1 - resolution: "@internationalized/date@npm:3.0.0-rc.1" - dependencies: - "@babel/runtime": ^7.6.2 - checksum: 922966e37360052d251a6d7d2ec472632f7d2265baa1b380da8d9f2433fd979a0cf47e032e967eb161f4ec5ec9e230d2ce7c17616338b1a900f06627f1bca1bd - languageName: node - linkType: hard - -"@internationalized/date@npm:^3.5.2": - version: 3.5.2 - resolution: "@internationalized/date@npm:3.5.2" - dependencies: - "@swc/helpers": ^0.5.0 - checksum: 7cd31aebe1bfa7307cb31d24366a9cc18c598e38a7eb6cd68a86b3c2d9e7c4f03376fe8a3ac6c6556fb80e58fa7697238af2ee9d753058e063f9a136143dafc2 - languageName: node - linkType: hard - -"@internationalized/message@npm:^3.0.7, @internationalized/message@npm:^3.1.2": - version: 3.1.2 - resolution: "@internationalized/message@npm:3.1.2" - dependencies: - "@swc/helpers": ^0.5.0 - intl-messageformat: ^10.1.0 - checksum: 230fcd1688ce12bd244779f66a78167bd1c7e5c30a228fe3dc8d433428a64dda90085852bec38107795e9e81307c29e7dc3e584b5949f19536099aebc1ade19b - languageName: node - linkType: hard - -"@internationalized/number@npm:^3.1.1, @internationalized/number@npm:^3.5.1": - version: 3.5.1 - resolution: "@internationalized/number@npm:3.5.1" - dependencies: - "@swc/helpers": ^0.5.0 - checksum: c24dfe0bfef1bde551463f660ed58fa45709db878a0ffec2b183d464856d47f043699dc65adb339d40d4143f1029080fa8fd8d1a9532b90f475e7144d451963e - languageName: node - linkType: hard - -"@internationalized/string@npm:^3.2.1": - version: 3.2.1 - resolution: "@internationalized/string@npm:3.2.1" - dependencies: - "@swc/helpers": ^0.5.0 - checksum: 967d5c4d03e2680082af591d085be741b9599527b088f444fef25d612f0960a501b6873d2f532e10b494d2ac0c2e29b6333a960a75f441170b53e1308cefdf76 - languageName: node - linkType: hard - "@iota-wiki/cli@workspace:^, @iota-wiki/cli@workspace:cli": version: 0.0.0-use.local resolution: "@iota-wiki/cli@workspace:cli" @@ -2827,18 +2721,18 @@ __metadata: "@algolia/client-search": ^4.22.1 "@argos-ci/cli": ^1.0.11 "@argos-ci/playwright": ^1.9.3 + "@artsy/to-title-case": ^1.1.0 "@docusaurus/core": 2.4.3 "@docusaurus/module-type-aliases": 2.4.3 "@docusaurus/plugin-client-redirects": 2.4.3 "@docusaurus/plugin-google-gtag": 2.4.3 "@docusaurus/preset-classic": 2.4.3 "@docusaurus/remark-plugin-npm2yarn": ^2.4.3 + "@docusaurus/theme-classic": 2.4.3 "@docusaurus/theme-common": 2.4.3 "@iota-wiki/cli": "workspace:^" - "@iota-wiki/plugin-docs": "workspace:^" - "@iota-wiki/plugin-tutorial": "workspace:^" - "@iota-wiki/theme": "workspace:^" "@mdx-js/react": ^1.6.21 + "@metamask/providers": ^10.2.1 "@playwright/test": ^1.42.1 "@popperjs/core": ^2.11.5 "@saucelabs/theme-github-codeblock": ^0.2.3 @@ -2852,8 +2746,8 @@ __metadata: bufferutil: ^4.0.8 cheerio: ^1.0.0-rc.12 clsx: ^1.2.1 - docusaurus-plugin-openapi-docs: "dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-plugin-openapi-docs" - docusaurus-theme-openapi-docs: "dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-theme-openapi-docs" + docusaurus-plugin-openapi-docs: "jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-plugin-openapi-docs" + docusaurus-theme-openapi-docs: "jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-theme-openapi-docs" eslint: ^8.48.0 eslint-config-prettier: ^8.9.0 eslint-plugin-react: ^7.26.0 @@ -2863,6 +2757,7 @@ __metadata: flickity-fade: ^2.0.0 globby: ^13.1.4 hast-util-is-element: 1.1.0 + html-react-parser: ^4.2.10 humanize-duration: ^3.30.0 infima: ^0.2.0-alpha.43 plugin-image-zoom: flexanalytics/plugin-image-zoom @@ -2873,6 +2768,7 @@ __metadata: react-dom: 18.2.0 react-flickity-component: ^3.6.3 react-image-gallery: ^1.3.0 + react-markdown: 6 react-player: ^2.11.2 react-popper: ^2.3.0 react-select: ^5.7.7 @@ -2888,53 +2784,10 @@ __metadata: typescript: ^4.5.4 url-loader: ^4.1.1 utf-8-validate: ^6.0.3 + web3: ^4.2.2 webpack: ^5.89.0 webpack-node-externals: ^3.0.0 - ws: ^8.16.0 - languageName: unknown - linkType: soft - -"@iota-wiki/plugin-docs@workspace:^, @iota-wiki/plugin-docs@workspace:plugins/docs": - version: 0.0.0-use.local - resolution: "@iota-wiki/plugin-docs@workspace:plugins/docs" - dependencies: - "@docusaurus/plugin-content-docs": 2.4.3 - "@docusaurus/types": 2.4.3 - typescript: ^4.6.3 - languageName: unknown - linkType: soft - -"@iota-wiki/plugin-tutorial@workspace:^, @iota-wiki/plugin-tutorial@workspace:plugins/tutorial": - version: 0.0.0-use.local - resolution: "@iota-wiki/plugin-tutorial@workspace:plugins/tutorial" - dependencies: - "@docusaurus/types": 2.4.3 - typescript: ^4.6.3 - languageName: unknown - linkType: soft - -"@iota-wiki/theme@workspace:^, @iota-wiki/theme@workspace:theme": - version: 0.0.0-use.local - resolution: "@iota-wiki/theme@workspace:theme" - dependencies: - "@artsy/to-title-case": ^1.1.0 - "@docusaurus/theme-classic": 2.4.3 - "@docusaurus/theme-common": 2.4.3 - "@docusaurus/types": 2.4.3 - "@iota-wiki/plugin-docs": "workspace:^" - "@metamask/providers": ^10.2.1 - "@types/react": 18.2.71 - clsx: ^1.2.1 - copyfiles: ^2.4.1 - html-react-parser: ^4.2.10 - nodemon: ^2.0.16 - prettier: ^2.8.8 - react: 18.2.0 - react-markdown: 6 - typescript: ^4.9 - web3: ^4.2.2 - peerDependencies: - react: "*" + ws: ^8.17.1 languageName: unknown linkType: soft @@ -3129,1132 +2982,213 @@ __metadata: languageName: node linkType: hard -"@nextui-org/react@npm:^1.0.0-beta.12": - version: 1.0.0-beta.9-dbg2 - resolution: "@nextui-org/react@npm:1.0.0-beta.9-dbg2" - dependencies: - "@babel/runtime": 7.9.6 - "@react-aria/button": 3.5.0 - "@react-aria/checkbox": 3.4.0 - "@react-aria/dialog": 3.2.0 - "@react-aria/focus": 3.6.0 - "@react-aria/i18n": 3.4.0 - "@react-aria/interactions": 3.9.0 - "@react-aria/label": 3.3.0 - "@react-aria/menu": 3.5.0 - "@react-aria/overlays": 3.9.0 - "@react-aria/radio": 3.2.0 - "@react-aria/ssr": 3.2.0 - "@react-aria/table": 3.3.0 - "@react-aria/utils": 3.13.0 - "@react-aria/visually-hidden": 3.3.0 - "@react-stately/checkbox": 3.1.0 - "@react-stately/data": 3.5.0 - "@react-stately/overlays": 3.3.0 - "@react-stately/radio": 3.4.0 - "@react-stately/table": 3.2.0 - "@react-stately/toggle": 3.3.0 - "@react-stately/tree": 3.3.0 - "@react-types/button": ^3.5.0 - "@react-types/checkbox": 3.3.0 - "@react-types/grid": 3.1.0 - "@react-types/menu": 3.6.0 - "@react-types/overlays": 3.6.0 - "@react-types/shared": 3.13.0 - "@stitches/react": 1.2.8 - peerDependencies: - react: ">=16.8.0" - react-dom: ">=16.8.0" - checksum: 557fcd4d23580c9695a02b9bed455310958ca25e1c89a016c0e455459e37997a228e8ed7eb418239f53b576078a83ec71434dc3f37ea3bc1d6ee4f39bbfbee81 - languageName: node - linkType: hard - "@noble/curves@npm:1.3.0, @noble/curves@npm:~1.3.0": version: 1.3.0 resolution: "@noble/curves@npm:1.3.0" dependencies: - "@noble/hashes": 1.3.3 - checksum: b65342ee66c4a440eee2978524412eabba9a9efdd16d6370e15218c6a7d80bddf35e66bb57ed52c0dfd32cb9a717b439ab3a72db618f1a0066dfebe3fd12a421 - languageName: node - linkType: hard - -"@noble/hashes@npm:1.3.3, @noble/hashes@npm:~1.3.2": - version: 1.3.3 - resolution: "@noble/hashes@npm:1.3.3" - checksum: 8a6496d1c0c64797339bc694ad06cdfaa0f9e56cd0c3f68ae3666cfb153a791a55deb0af9c653c7ed2db64d537aa3e3054629740d2f2338bb1dcb7ab60cd205b - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: ^1.1.9 - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: ^1.6.0 - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^2.0.0": - version: 2.2.1 - resolution: "@npmcli/agent@npm:2.2.1" - dependencies: - agent-base: ^7.1.0 - http-proxy-agent: ^7.0.0 - https-proxy-agent: ^7.0.1 - lru-cache: ^10.0.1 - socks-proxy-agent: ^8.0.1 - checksum: c69aca42dbba393f517bc5777ee872d38dc98ea0e5e93c1f6d62b82b8fecdc177a57ea045f07dda1a770c592384b2dd92a5e79e21e2a7cf51c9159466a8f9c9b - languageName: node - linkType: hard - -"@npmcli/config@npm:^6.0.0": - version: 6.4.1 - resolution: "@npmcli/config@npm:6.4.1" - dependencies: - "@npmcli/map-workspaces": ^3.0.2 - ci-info: ^4.0.0 - ini: ^4.1.0 - nopt: ^7.0.0 - proc-log: ^3.0.0 - read-package-json-fast: ^3.0.2 - semver: ^7.3.5 - walk-up-path: ^3.0.1 - checksum: 0036cf05d8c9fe373c33e7b35724099e6dc356255e7ef27a161e9efa53f51b0ddeb70b4452f3de9bbc48a28d78312856852941950838da8da4bb23bbb9f950a2 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.0 - resolution: "@npmcli/fs@npm:3.1.0" - dependencies: - semver: ^7.3.5 - checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e - languageName: node - linkType: hard - -"@npmcli/map-workspaces@npm:^3.0.2": - version: 3.0.4 - resolution: "@npmcli/map-workspaces@npm:3.0.4" - dependencies: - "@npmcli/name-from-folder": ^2.0.0 - glob: ^10.2.2 - minimatch: ^9.0.0 - read-package-json-fast: ^3.0.0 - checksum: 99607dbc502b16d0ce7a47a81ccc496b3f5ed10df4e61e61a505929de12c356092996044174ae0cfd6d8cc177ef3b597eef4987b674fc0c5a306d3a8cc1fe91a - languageName: node - linkType: hard - -"@npmcli/name-from-folder@npm:^2.0.0": - version: 2.0.0 - resolution: "@npmcli/name-from-folder@npm:2.0.0" - checksum: fb3ef891aa57315fb6171866847f298577c8bda98a028e93e458048477133e142b4eb45ce9f3b80454f7c257612cb01754ee782d608507698dd712164436f5bd - languageName: node - linkType: hard - -"@paloaltonetworks/openapi-to-postmanv2@npm:3.1.0-hotfix.1": - version: 3.1.0-hotfix.1 - resolution: "@paloaltonetworks/openapi-to-postmanv2@npm:3.1.0-hotfix.1" - dependencies: - "@paloaltonetworks/postman-collection": ^4.1.0 - ajv: 8.1.0 - ajv-formats: 2.1.1 - async: 3.2.1 - commander: 2.20.3 - js-yaml: 3.14.1 - json-schema-merge-allof: 0.8.1 - lodash: 4.17.21 - oas-resolver-browser: 2.5.2 - path-browserify: 1.0.1 - yaml: 1.10.2 - bin: - openapi2postmanv2: bin/openapi2postmanv2.js - checksum: 31021f3eae6098b9860eb4bbd903c1fbfdd4fa3930228f57ef428d673e53a2ee59f5dec3271f13c2bd40ad887401abf52d5f669530a9f3c504c441ec34a78cc4 - languageName: node - linkType: hard - -"@paloaltonetworks/postman-code-generators@npm:1.1.15-patch.2": - version: 1.1.15-patch.2 - resolution: "@paloaltonetworks/postman-code-generators@npm:1.1.15-patch.2" - dependencies: - "@paloaltonetworks/postman-collection": ^4.1.0 - async: ^3.2.4 - path: ^0.12.7 - shelljs: ^0.8.5 - checksum: bfea89b57778b142591513cb676e0e88bf85b884cd725c825ddb65aebaeb3f92b781a2feb4bee0bbba99c077b32bea195b0f579c689923eb4c78371c6bce309a - languageName: node - linkType: hard - -"@paloaltonetworks/postman-collection@npm:^4.1.0": - version: 4.1.1 - resolution: "@paloaltonetworks/postman-collection@npm:4.1.1" - dependencies: - file-type: 3.9.0 - http-reasons: 0.1.0 - iconv-lite: 0.6.3 - liquid-json: 0.3.1 - lodash: 4.17.21 - mime-format: 2.0.1 - mime-types: 2.1.34 - postman-url-encoder: 3.0.5 - semver: 7.3.5 - uuid: 8.3.2 - checksum: bf284e9a2ad41383af871842f6cc85e8affb629f06c6736b21bca760c6b37516a8f51a7a31a6eb2f84f9d5b7f2a2e792139f2bc7ec83d98f98f8520244d62b96 - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f - languageName: node - linkType: hard - -"@playwright/test@npm:^1.42.1": - version: 1.42.1 - resolution: "@playwright/test@npm:1.42.1" - dependencies: - playwright: 1.42.1 - bin: - playwright: cli.js - checksum: a41505f02a4dac358e645452a190cac620b8d4eae79ab5d90ea1fb7ca06d86a9f5749b1a803dea789b662d1cbfd216380f722bed72093897e18b4238f4a07a4d - languageName: node - linkType: hard - -"@pnpm/config.env-replace@npm:^1.1.0": - version: 1.1.0 - resolution: "@pnpm/config.env-replace@npm:1.1.0" - checksum: a3d2b57e35eec9543d9eb085854f6e33e8102dac99fdef2fad2eebdbbfc345e93299f0c20e8eb61c1b4c7aa123bfd47c175678626f161cda65dd147c2b6e1fa0 - languageName: node - linkType: hard - -"@pnpm/network.ca-file@npm:^1.0.1": - version: 1.0.2 - resolution: "@pnpm/network.ca-file@npm:1.0.2" - dependencies: - graceful-fs: 4.2.10 - checksum: d8d0884646500576bd5390464d13db1bb9a62e32a1069293e5bddb2ad8354b354b7e2d2a35e12850025651e795e6a80ce9e601c66312504667b7e3ee7b52becc - languageName: node - linkType: hard - -"@pnpm/npm-conf@npm:^2.1.0": - version: 2.2.2 - resolution: "@pnpm/npm-conf@npm:2.2.2" - dependencies: - "@pnpm/config.env-replace": ^1.1.0 - "@pnpm/network.ca-file": ^1.0.1 - config-chain: ^1.1.11 - checksum: d64aa4464be584caa855eafa8f109509390489997e36d602d6215784e2973b896bef3968426bb00896cf4ae7d440fed2cee7bb4e0dbc90362f024ea3f9e27ab1 - languageName: node - linkType: hard - -"@polka/url@npm:^1.0.0-next.24": - version: 1.0.0-next.25 - resolution: "@polka/url@npm:1.0.0-next.25" - checksum: 4ab1d7a37163139c0e7bfc9d1e3f6a2a0db91a78b9f0a21f571d6aec2cdaeaacced744d47886c117aa7579aa5694b303fe3e0bd1922bb9cb3ce6bf7c2dc09801 - languageName: node - linkType: hard - -"@popperjs/core@npm:^2.11.5": - version: 2.11.8 - resolution: "@popperjs/core@npm:2.11.8" - checksum: e5c69fdebf52a4012f6a1f14817ca8e9599cb1be73dd1387e1785e2ed5e5f0862ff817f420a87c7fc532add1f88a12e25aeb010ffcbdc98eace3d55ce2139cf0 - languageName: node - linkType: hard - -"@react-aria/button@npm:3.5.0": - version: 3.5.0 - resolution: "@react-aria/button@npm:3.5.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/focus": ^3.6.0 - "@react-aria/interactions": ^3.9.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/toggle": ^3.3.0 - "@react-types/button": ^3.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: f6960c91b073ea68f82dd7751f8c77ccdc4d62e227f190ae0030811a15bf943998e87708ceadaded2d7fbd45015b3c68ea74618d7157121c01c6126cc06de3ee - languageName: node - linkType: hard - -"@react-aria/checkbox@npm:3.4.0": - version: 3.4.0 - resolution: "@react-aria/checkbox@npm:3.4.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/label": ^3.3.0 - "@react-aria/toggle": ^3.3.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/checkbox": ^3.1.0 - "@react-stately/toggle": ^3.3.0 - "@react-types/checkbox": ^3.3.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: f71cb254326edd4407c717e7bb3c28626e03995445b290c8fe02d9a79413555aa5eea1d1d67918bade32041b83456065018c237ef319bf7a150d14fb1d440b22 - languageName: node - linkType: hard - -"@react-aria/dialog@npm:3.2.0": - version: 3.2.0 - resolution: "@react-aria/dialog@npm:3.2.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/focus": ^3.6.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/overlays": ^3.3.0 - "@react-types/dialog": ^3.4.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: a62a7c71bf65fc28f7e863bd1f250977f16043097b0863583cebd235d8d5abfed40789a0d00af06fb398afe5d16219e1f694d017d0bd0ff0d8479fa041409f19 - languageName: node - linkType: hard - -"@react-aria/focus@npm:3.6.0": - version: 3.6.0 - resolution: "@react-aria/focus@npm:3.6.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/interactions": ^3.9.0 - "@react-aria/utils": ^3.13.0 - "@react-types/shared": ^3.13.0 - clsx: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 5b459ec9e7150c58bc515cc70db87d3fc10df42b171b69f021dee339e71fecafe4055f08c423f1e006643aa678b08e975312c5f02e474d7342c1ad24d6e26429 - languageName: node - linkType: hard - -"@react-aria/focus@npm:^3.16.2, @react-aria/focus@npm:^3.6.0": - version: 3.16.2 - resolution: "@react-aria/focus@npm:3.16.2" - dependencies: - "@react-aria/interactions": ^3.21.1 - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - clsx: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: d97eabc981acd8b6e0e3984a0316ebafddffdd19732c3efc6890482f89dc06605202f682b7700a73292f71c80e8a2e846136a61dfbfead3053f92bb865272ad5 - languageName: node - linkType: hard - -"@react-aria/grid@npm:^3.3.0": - version: 3.8.8 - resolution: "@react-aria/grid@npm:3.8.8" - dependencies: - "@react-aria/focus": ^3.16.2 - "@react-aria/i18n": ^3.10.2 - "@react-aria/interactions": ^3.21.1 - "@react-aria/live-announcer": ^3.3.2 - "@react-aria/selection": ^3.17.5 - "@react-aria/utils": ^3.23.2 - "@react-stately/collections": ^3.10.5 - "@react-stately/grid": ^3.8.5 - "@react-stately/selection": ^3.14.3 - "@react-stately/virtualizer": ^3.6.8 - "@react-types/checkbox": ^3.7.1 - "@react-types/grid": ^3.2.4 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8a21a989b8dec75be241b3877fd1b91c8fa5745f2b9de2fdb8b1a296966e7fecc6e08d0239f85ff7a7d9686b698c6153c291d46bee78e66d88e89b15130c88db - languageName: node - linkType: hard - -"@react-aria/i18n@npm:3.4.0": - version: 3.4.0 - resolution: "@react-aria/i18n@npm:3.4.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@internationalized/date": 3.0.0-rc.1 - "@internationalized/message": ^3.0.7 - "@internationalized/number": ^3.1.1 - "@react-aria/ssr": ^3.2.0 - "@react-aria/utils": ^3.13.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 28bcf3e94815b11580737eabc076cbe7d709043bfc0606d440fa0d6caead295722fafc950717c0d1a1a9162aec552758ff854a9ec44f58ab4ecb8276e7c09889 - languageName: node - linkType: hard - -"@react-aria/i18n@npm:^3.10.2, @react-aria/i18n@npm:^3.4.0": - version: 3.10.2 - resolution: "@react-aria/i18n@npm:3.10.2" - dependencies: - "@internationalized/date": ^3.5.2 - "@internationalized/message": ^3.1.2 - "@internationalized/number": ^3.5.1 - "@internationalized/string": ^3.2.1 - "@react-aria/ssr": ^3.9.2 - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 229b2c65f4e6346e06780d0d131ae3cb915fcf66f31f8fc7b00aa9aec451e57da4d3f28794958933950f9c7b97fcd808b6a0e75bef57d10b88eabef0d6b511d6 - languageName: node - linkType: hard - -"@react-aria/interactions@npm:3.9.0": - version: 3.9.0 - resolution: "@react-aria/interactions@npm:3.9.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/utils": ^3.13.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 783d4fa59bda9329f4977d8e83c88555c3376c489e40d97c974c7725ebf286849ed149f8e20226fbab070bd45356e5ba01ace328d2ed785f0f40e28790e7b0d5 - languageName: node - linkType: hard - -"@react-aria/interactions@npm:^3.21.1, @react-aria/interactions@npm:^3.9.0": - version: 3.21.1 - resolution: "@react-aria/interactions@npm:3.21.1" - dependencies: - "@react-aria/ssr": ^3.9.2 - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 73384b026ee0819cf37e4fa85ef7998c3b77d64ae9d97f4a0b78ee88d8ee6d44c6d43a44164485b90409cc065a24e9c9c1e2d06f152802d46714355dab74345d - languageName: node - linkType: hard - -"@react-aria/label@npm:3.3.0": - version: 3.3.0 - resolution: "@react-aria/label@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/utils": ^3.13.0 - "@react-types/label": ^3.6.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8d756bf9be31a90a845b30ed4b052f40e7ace254421de2688b4d7f493c050c01a0723511b3f02f797f8ad5c6ae56f65c2b9ab527645f75ec2f07ed27681df0c4 - languageName: node - linkType: hard - -"@react-aria/label@npm:^3.3.0": - version: 3.7.6 - resolution: "@react-aria/label@npm:3.7.6" - dependencies: - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 580dddcfd88c5cd1a9778209c3c2b90960ef623f59a60634f0141d64c666bdcbaf6706fb8ee759f4fcab36bb74e3918b8da22a869bc4c102d04270d043efe611 - languageName: node - linkType: hard - -"@react-aria/live-announcer@npm:^3.1.0, @react-aria/live-announcer@npm:^3.3.2": - version: 3.3.2 - resolution: "@react-aria/live-announcer@npm:3.3.2" - dependencies: - "@swc/helpers": ^0.5.0 - checksum: d6729908ad4688ad32b09396510a8eef6665ccce027ee5ffdaa8d9c3f4cef7e116a95786742f5abce76c4204340dc85ae4a6278d45c87e9469cb56687beaaac3 - languageName: node - linkType: hard - -"@react-aria/menu@npm:3.5.0": - version: 3.5.0 - resolution: "@react-aria/menu@npm:3.5.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/i18n": ^3.4.0 - "@react-aria/interactions": ^3.9.0 - "@react-aria/overlays": ^3.9.0 - "@react-aria/selection": ^3.9.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/collections": ^3.4.0 - "@react-stately/menu": ^3.3.0 - "@react-stately/tree": ^3.3.0 - "@react-types/button": ^3.5.0 - "@react-types/menu": ^3.6.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 4b5cdbb4f829ae72a31f75e9a9e96e47b570b45c40ddde9a9c87a5cf5faabc94b33daf5a9bf24e0f666dff83ab800965268389462de3d64ca34ce2fe411089ae - languageName: node - linkType: hard - -"@react-aria/overlays@npm:3.9.0": - version: 3.9.0 - resolution: "@react-aria/overlays@npm:3.9.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/i18n": ^3.4.0 - "@react-aria/interactions": ^3.9.0 - "@react-aria/utils": ^3.13.0 - "@react-aria/visually-hidden": ^3.3.0 - "@react-stately/overlays": ^3.3.0 - "@react-types/button": ^3.5.0 - "@react-types/overlays": ^3.6.0 - "@react-types/shared": ^3.13.0 - dom-helpers: ^5.2.1 - react-transition-group: ^4.4.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: a4d39ff53a2d3583b51ac3074be3286b0ae16f1b8665054b2bd35f8257e34b40034d469b5be012c0a6282bdcd6904f2a5b2976883b9dc0fc7470b7b0525876f3 - languageName: node - linkType: hard - -"@react-aria/overlays@npm:^3.9.0": - version: 3.21.1 - resolution: "@react-aria/overlays@npm:3.21.1" - dependencies: - "@react-aria/focus": ^3.16.2 - "@react-aria/i18n": ^3.10.2 - "@react-aria/interactions": ^3.21.1 - "@react-aria/ssr": ^3.9.2 - "@react-aria/utils": ^3.23.2 - "@react-aria/visually-hidden": ^3.8.10 - "@react-stately/overlays": ^3.6.5 - "@react-types/button": ^3.9.2 - "@react-types/overlays": ^3.8.5 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 59819eaa63d4360367143c89ee1017001b9fcb7be23f4835d67bbb3051c7fa1951a1807671070df2729c8dafa6c95939ba804d66b8b356ec54bfaf066961f5f8 - languageName: node - linkType: hard - -"@react-aria/radio@npm:3.2.0": - version: 3.2.0 - resolution: "@react-aria/radio@npm:3.2.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/focus": ^3.6.0 - "@react-aria/i18n": ^3.4.0 - "@react-aria/interactions": ^3.9.0 - "@react-aria/label": ^3.3.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/radio": ^3.4.0 - "@react-types/radio": ^3.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: d6a291903979ae68b5ce5112ebd813bb91e41a6f975b59c518576f19a361767286f74cbb20432b43632de9b8d5757dc750c311d352666b060d86ad119176bdaa - languageName: node - linkType: hard - -"@react-aria/selection@npm:^3.17.5, @react-aria/selection@npm:^3.9.0": - version: 3.17.5 - resolution: "@react-aria/selection@npm:3.17.5" - dependencies: - "@react-aria/focus": ^3.16.2 - "@react-aria/i18n": ^3.10.2 - "@react-aria/interactions": ^3.21.1 - "@react-aria/utils": ^3.23.2 - "@react-stately/selection": ^3.14.3 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 317cd072ffd2fcf9213ccb255b0d8612e3f0a2b29de8f31fc685e693d21e84a369a7c1c346aea9a358ddb13fc33cfe1dea6c31defce19eb35f323d1eff85664f - languageName: node - linkType: hard - -"@react-aria/ssr@npm:3.2.0": - version: 3.2.0 - resolution: "@react-aria/ssr@npm:3.2.0" - dependencies: - "@babel/runtime": ^7.6.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 30468b436f9d56636eb3fb89cbbbf861c55ad841e255e529d225a0efd9c23628badaee72c42ab3870b5f17a9d5b5163564a64e9b928565230a090cb4f7de23bf - languageName: node - linkType: hard - -"@react-aria/ssr@npm:^3.2.0, @react-aria/ssr@npm:^3.9.2": - version: 3.9.2 - resolution: "@react-aria/ssr@npm:3.9.2" - dependencies: - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: ef11ef02195665f8a05cc430781da33509d6a20b88590e3ca018323f0824ce80f7cf470f99789cb6aeaeeeeac5d345d2eb671ff5b2d470b7c274f071e7c8abf5 - languageName: node - linkType: hard - -"@react-aria/table@npm:3.3.0": - version: 3.3.0 - resolution: "@react-aria/table@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/focus": ^3.6.0 - "@react-aria/grid": ^3.3.0 - "@react-aria/i18n": ^3.4.0 - "@react-aria/interactions": ^3.9.0 - "@react-aria/live-announcer": ^3.1.0 - "@react-aria/selection": ^3.9.0 - "@react-aria/utils": ^3.13.0 - "@react-stately/table": ^3.2.0 - "@react-stately/virtualizer": ^3.2.0 - "@react-types/checkbox": ^3.3.0 - "@react-types/grid": ^3.1.0 - "@react-types/shared": ^3.13.0 - "@react-types/table": ^3.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 1046d9d19cc4d9654bb76ab12647a9e5054df6d7b6903553f0413d8d455ee55eeeaefada076c63615d245702a4e90b2a9b2a52b8847feaa2b633a02934efcf46 - languageName: node - linkType: hard - -"@react-aria/toggle@npm:^3.3.0": - version: 3.10.2 - resolution: "@react-aria/toggle@npm:3.10.2" - dependencies: - "@react-aria/focus": ^3.16.2 - "@react-aria/interactions": ^3.21.1 - "@react-aria/utils": ^3.23.2 - "@react-stately/toggle": ^3.7.2 - "@react-types/checkbox": ^3.7.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 034d2148132208f9eed804a55890c4d5456cbfa572072495a2db0f11fb663db7f0e6bf7a0750eb8d389d635710123834983835c4814cdc39024f86146f8c76d5 - languageName: node - linkType: hard - -"@react-aria/utils@npm:3.13.0": - version: 3.13.0 - resolution: "@react-aria/utils@npm:3.13.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/ssr": ^3.2.0 - "@react-stately/utils": ^3.5.0 - "@react-types/shared": ^3.13.0 - clsx: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 7a154d6258adf6205ac367def0fcaf1b3fd0db3644c43481b2cb6eb9bc0f35ebddab9ecbddbec8dee92bbf5e38b63222137e1df5c26e5c8c1775ffa0e0b172fa - languageName: node - linkType: hard - -"@react-aria/utils@npm:^3.13.0, @react-aria/utils@npm:^3.23.2": - version: 3.23.2 - resolution: "@react-aria/utils@npm:3.23.2" - dependencies: - "@react-aria/ssr": ^3.9.2 - "@react-stately/utils": ^3.9.1 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - clsx: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 31a57fc3505879dde5da273e35a7f421b3473611e6b108a0a1a32f782c39b5c5a8cb99cc7f35afc742725e0a977165fec8462b127665be7d38d70d12fa40b544 - languageName: node - linkType: hard - -"@react-aria/visually-hidden@npm:3.3.0": - version: 3.3.0 - resolution: "@react-aria/visually-hidden@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/interactions": ^3.9.0 - "@react-aria/utils": ^3.13.0 - clsx: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 455bdacbdd0d39bf610d173db06a882b50acd3018af0d0ff41958e6b26cfe942b49fff797479b82728b7894c0b9f4c2e5ab85c1d1650add63c95907259649247 - languageName: node - linkType: hard - -"@react-aria/visually-hidden@npm:^3.3.0, @react-aria/visually-hidden@npm:^3.8.10": - version: 3.8.10 - resolution: "@react-aria/visually-hidden@npm:3.8.10" - dependencies: - "@react-aria/interactions": ^3.21.1 - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 06cc318ac0239c888fe68cbdebd1ac9a6c5f79177df6fb5a7894fc2ce4d6a1c76fc10175e7dcc889942e747ed1cc040ed6f9fa5f25e25c3508aadb5e90a7c31d - languageName: node - linkType: hard - -"@react-stately/checkbox@npm:3.1.0": - version: 3.1.0 - resolution: "@react-stately/checkbox@npm:3.1.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-stately/toggle": ^3.3.0 - "@react-stately/utils": ^3.5.0 - "@react-types/checkbox": ^3.3.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: c0d2b7687bcce54890d0314e78d3d5fe26982508eded648494dfa87303bd1008ecfe209df6c000710d7fb38dbc25fdef37fdfbeea1bcf69258bb9e2452f1b110 - languageName: node - linkType: hard - -"@react-stately/checkbox@npm:^3.1.0": - version: 3.6.3 - resolution: "@react-stately/checkbox@npm:3.6.3" - dependencies: - "@react-stately/form": ^3.0.1 - "@react-stately/utils": ^3.9.1 - "@react-types/checkbox": ^3.7.1 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 75a5969a62372c84851355705ac48a0c5667acfb0720407e8605747c63c6a31414ca859f6d27c93fadf4179667e91403bb78e84707504f46a8ef394ef014f97e - languageName: node - linkType: hard - -"@react-stately/collections@npm:^3.10.5, @react-stately/collections@npm:^3.4.0": - version: 3.10.5 - resolution: "@react-stately/collections@npm:3.10.5" - dependencies: - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 871a943644c70e3e0c91a0fbdd37c8a211f2393e15caef68d030272ab792535c2707db42f2aa73acf0a586ba4af6648e0596983145e0da2bf5bb8fe6ffc4d93e - languageName: node - linkType: hard - -"@react-stately/data@npm:3.5.0": - version: 3.5.0 - resolution: "@react-stately/data@npm:3.5.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 34725449d5f37bccc15d3aa52ba237921d089d73774452e129fe4931b980c9e30dfe011fc84858eb996a3c62fcae26b9fa5d23a6d763e0577e2c2b22aefbbc08 - languageName: node - linkType: hard - -"@react-stately/flags@npm:^3.0.1": - version: 3.0.1 - resolution: "@react-stately/flags@npm:3.0.1" - dependencies: - "@swc/helpers": ^0.4.14 - checksum: 24bde3fcca2454854734107c4c3c924e1b4509b78a0fb9ff251a998cd9c482073ef11f31280f6a9645f44c4c2f4694cf70a6f79117d0690c27cd037b8e376ce6 - languageName: node - linkType: hard - -"@react-stately/form@npm:^3.0.1": - version: 3.0.1 - resolution: "@react-stately/form@npm:3.0.1" - dependencies: - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 11b0721855bdd0d10802d63d06bca1af7624189a8240a901efb9ce24981d596e7a0375000d23c26428a9d02013209699d60ef3a700b01051322251661ad4ef9e - languageName: node - linkType: hard - -"@react-stately/grid@npm:^3.2.0, @react-stately/grid@npm:^3.8.5": - version: 3.8.5 - resolution: "@react-stately/grid@npm:3.8.5" - dependencies: - "@react-stately/collections": ^3.10.5 - "@react-stately/selection": ^3.14.3 - "@react-types/grid": ^3.2.4 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 90a88fe753ef21d87c0f4e0ee64a8a801c7d5ecaef598a10147a843869b76d38dc1404831ea0f5895c81989269b03a53bcd56af86a017329341361a5a9122ff4 - languageName: node - linkType: hard - -"@react-stately/menu@npm:^3.3.0": - version: 3.6.1 - resolution: "@react-stately/menu@npm:3.6.1" - dependencies: - "@react-stately/overlays": ^3.6.5 - "@react-types/menu": ^3.9.7 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: a24cfbfd2b232369c9862f047e3c32a02b79dbf52e6c338d53a0c88c7758a1cbeaa4366aec81cb2bb2f60401c37d1101c9a6a5a77b196f9ec0523148903f45b7 - languageName: node - linkType: hard - -"@react-stately/overlays@npm:3.3.0": - version: 3.3.0 - resolution: "@react-stately/overlays@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-stately/utils": ^3.5.0 - "@react-types/overlays": ^3.6.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 19d4e9f2c9fb745704f9400d54a7b78766bd3f7592df9253ddf11a9231b2a21f6412166d714d7cea8ace28db33791989c092ac1ab7f566a8b53f3c9d17e9b18c - languageName: node - linkType: hard - -"@react-stately/overlays@npm:^3.3.0, @react-stately/overlays@npm:^3.6.5": - version: 3.6.5 - resolution: "@react-stately/overlays@npm:3.6.5" - dependencies: - "@react-stately/utils": ^3.9.1 - "@react-types/overlays": ^3.8.5 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 30d665b93f093fb497d5177ff5ebf700c0fe976393504debd5924811fafba9bd0cd40b6b4943427c5f4c4d8cc45103417015b0fb8e5aed5559bc5c23fc8bbf50 - languageName: node - linkType: hard - -"@react-stately/radio@npm:3.4.0": - version: 3.4.0 - resolution: "@react-stately/radio@npm:3.4.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-stately/utils": ^3.5.0 - "@react-types/radio": ^3.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 7208fcf4dc31d2b8a7ac1dba0cd4d25ce4f4ae174a7b6386775a8601537e2d966c5afa83301312a3145a7f0bd4fd908a9e8828def56ddb5e86ff11a25cf04596 - languageName: node - linkType: hard - -"@react-stately/radio@npm:^3.4.0": - version: 3.10.2 - resolution: "@react-stately/radio@npm:3.10.2" - dependencies: - "@react-stately/form": ^3.0.1 - "@react-stately/utils": ^3.9.1 - "@react-types/radio": ^3.7.1 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 72aaef7112c950d0476e893a173dd356d55e2deeaf7dff3969a85dc597291a64c653b29536ba0f7f912381effa8490249a35eeb51aaee7b9fcff41e067e9aec5 - languageName: node - linkType: hard - -"@react-stately/selection@npm:^3.10.0, @react-stately/selection@npm:^3.14.3": - version: 3.14.3 - resolution: "@react-stately/selection@npm:3.14.3" - dependencies: - "@react-stately/collections": ^3.10.5 - "@react-stately/utils": ^3.9.1 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8138fab2371448cfcef8c6f8623bc4175fb8b81261a7445f6986d2fd7da2ec791679ac6f9e90ab9be8f50c5c47b8843b55c6da95592c3525b0a38fa48d12f0d8 - languageName: node - linkType: hard - -"@react-stately/table@npm:3.2.0": - version: 3.2.0 - resolution: "@react-stately/table@npm:3.2.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-aria/utils": ^3.13.0 - "@react-stately/collections": ^3.4.0 - "@react-stately/grid": ^3.2.0 - "@react-stately/selection": ^3.10.0 - "@react-types/grid": ^3.1.0 - "@react-types/shared": ^3.13.0 - "@react-types/table": ^3.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: fa1dfc5c84fa449a70c0cc6c6dbc2e8e72fbe0552f0beb8f4d86fbaf5c89c6cdcc685540da882937589a1954786345af3095cdcbc30979521b9a4d3242faa959 - languageName: node - linkType: hard - -"@react-stately/table@npm:^3.2.0": - version: 3.11.6 - resolution: "@react-stately/table@npm:3.11.6" - dependencies: - "@react-stately/collections": ^3.10.5 - "@react-stately/flags": ^3.0.1 - "@react-stately/grid": ^3.8.5 - "@react-stately/selection": ^3.14.3 - "@react-stately/utils": ^3.9.1 - "@react-types/grid": ^3.2.4 - "@react-types/shared": ^3.22.1 - "@react-types/table": ^3.9.3 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: d4ad81b878372f0314818aac8ab0f32c123d601053bce5ea5158daebafe5af964dd83227578a58b0ab6d6936958f7fc6ec104e3dcd5bfbc9df5f36963faf1cdc - languageName: node - linkType: hard - -"@react-stately/toggle@npm:3.3.0": - version: 3.3.0 - resolution: "@react-stately/toggle@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-stately/utils": ^3.5.0 - "@react-types/checkbox": ^3.3.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 3c6e721acb8c7527d44f82dbf1edb219bccbf84006c908b8ba66c7e044d4d81115227f84b781f3dcdf60d835986d964526ff653564f15889001499f6c22c6e85 - languageName: node - linkType: hard - -"@react-stately/toggle@npm:^3.3.0, @react-stately/toggle@npm:^3.7.2": - version: 3.7.2 - resolution: "@react-stately/toggle@npm:3.7.2" - dependencies: - "@react-stately/utils": ^3.9.1 - "@react-types/checkbox": ^3.7.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: a59e44a0aee68f7588e8cf4bcf0f782200b1a978ca46a99d049117f5456726a904d710a38acae7c6ab7658911de0cf50652110e56b5069f543e95af8f235c212 + "@noble/hashes": 1.3.3 + checksum: b65342ee66c4a440eee2978524412eabba9a9efdd16d6370e15218c6a7d80bddf35e66bb57ed52c0dfd32cb9a717b439ab3a72db618f1a0066dfebe3fd12a421 languageName: node linkType: hard -"@react-stately/tree@npm:3.3.0": - version: 3.3.0 - resolution: "@react-stately/tree@npm:3.3.0" - dependencies: - "@babel/runtime": ^7.6.2 - "@react-stately/collections": ^3.4.0 - "@react-stately/selection": ^3.10.0 - "@react-stately/utils": ^3.5.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 724d5833c2ca262f7b07c659d787df6deb0a871b58e067a92813175272f3a6333bb26dedcf997bda4cf950afa152223b635dc253d299514dd0918161948ed9b1 +"@noble/hashes@npm:1.3.3, @noble/hashes@npm:~1.3.2": + version: 1.3.3 + resolution: "@noble/hashes@npm:1.3.3" + checksum: 8a6496d1c0c64797339bc694ad06cdfaa0f9e56cd0c3f68ae3666cfb153a791a55deb0af9c653c7ed2db64d537aa3e3054629740d2f2338bb1dcb7ab60cd205b languageName: node linkType: hard -"@react-stately/tree@npm:^3.3.0": - version: 3.7.6 - resolution: "@react-stately/tree@npm:3.7.6" +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" dependencies: - "@react-stately/collections": ^3.10.5 - "@react-stately/selection": ^3.14.3 - "@react-stately/utils": ^3.9.1 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 95884bb63bc44363d8091efa785b1092e1d18a309c31edb0a0fe4f1b261b308db8bf036ca6370069261e5aca4d80b96c452dae4be6a8e4c4d4767d8d896c46de + "@nodelib/fs.stat": 2.0.5 + run-parallel: ^1.1.9 + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 languageName: node linkType: hard -"@react-stately/utils@npm:^3.5.0, @react-stately/utils@npm:^3.9.1": - version: 3.9.1 - resolution: "@react-stately/utils@npm:3.9.1" - dependencies: - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 290445ec2b48e24951c7685320b2cfd21694c3d8edd6c6db3135b168f0344c0740b5ee90b920c9ca6163cff6a4162219fb74b236cf47e8bf8a237c1efbdc908a +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 languageName: node linkType: hard -"@react-stately/virtualizer@npm:^3.2.0, @react-stately/virtualizer@npm:^3.6.8": - version: 3.6.8 - resolution: "@react-stately/virtualizer@npm:3.6.8" +"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: - "@react-aria/utils": ^3.23.2 - "@react-types/shared": ^3.22.1 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8b5196a95deb23a7fbf86199a28fa237e00283a6f48f22e191e2685d09601a590822e8c798166ee91c20a6a5b5000986ead448a125884fb8068a05a6780a38c3 + "@nodelib/fs.scandir": 2.1.5 + fastq: ^1.6.0 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 languageName: node linkType: hard -"@react-types/button@npm:^3.5.0, @react-types/button@npm:^3.9.2": - version: 3.9.2 - resolution: "@react-types/button@npm:3.9.2" +"@npmcli/agent@npm:^2.0.0": + version: 2.2.1 + resolution: "@npmcli/agent@npm:2.2.1" dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 38955ab60a15c3da0d9a32fb7af204149dfb884508de76cebe0d1f527e4fa9ec04158826aeff45c7bc4650cbc54f6a0e539ae10abcdf6b2f7e084c28bdf3d685 + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.1 + checksum: c69aca42dbba393f517bc5777ee872d38dc98ea0e5e93c1f6d62b82b8fecdc177a57ea045f07dda1a770c592384b2dd92a5e79e21e2a7cf51c9159466a8f9c9b languageName: node linkType: hard -"@react-types/checkbox@npm:3.3.0": - version: 3.3.0 - resolution: "@react-types/checkbox@npm:3.3.0" +"@npmcli/config@npm:^6.0.0": + version: 6.4.1 + resolution: "@npmcli/config@npm:6.4.1" dependencies: - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 9fb34839fca2c2e46b3b68ca492eee8a9db76b532eb363717529cb28970b72880b54f80eacbbf1a5607b6a0749b1b1fa68fe010a6c0a381fe58ee50ffb7ce276 + "@npmcli/map-workspaces": ^3.0.2 + ci-info: ^4.0.0 + ini: ^4.1.0 + nopt: ^7.0.0 + proc-log: ^3.0.0 + read-package-json-fast: ^3.0.2 + semver: ^7.3.5 + walk-up-path: ^3.0.1 + checksum: 0036cf05d8c9fe373c33e7b35724099e6dc356255e7ef27a161e9efa53f51b0ddeb70b4452f3de9bbc48a28d78312856852941950838da8da4bb23bbb9f950a2 languageName: node linkType: hard -"@react-types/checkbox@npm:^3.3.0, @react-types/checkbox@npm:^3.7.1": - version: 3.7.1 - resolution: "@react-types/checkbox@npm:3.7.1" +"@npmcli/fs@npm:^3.1.0": + version: 3.1.0 + resolution: "@npmcli/fs@npm:3.1.0" dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 9caa368a6f3d7376b5f2943b61749fc3b5e67e94c31b18e47ba90a7bf7760e76be837ccc894b8883ed3714babfb6f6974c58d58b8f66d5dcb57550b919fcddc4 + semver: ^7.3.5 + checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e languageName: node linkType: hard -"@react-types/dialog@npm:^3.4.0": - version: 3.5.8 - resolution: "@react-types/dialog@npm:3.5.8" +"@npmcli/map-workspaces@npm:^3.0.2": + version: 3.0.4 + resolution: "@npmcli/map-workspaces@npm:3.0.4" dependencies: - "@react-types/overlays": ^3.8.5 - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 079f955ed8da84407823e4145bdc0c13a76c8fa63b886aff5a514de148bcbb8c833b217d2416e3d50139f5d382bde51be4af82f2f0200bb508a142126c08bc84 + "@npmcli/name-from-folder": ^2.0.0 + glob: ^10.2.2 + minimatch: ^9.0.0 + read-package-json-fast: ^3.0.0 + checksum: 99607dbc502b16d0ce7a47a81ccc496b3f5ed10df4e61e61a505929de12c356092996044174ae0cfd6d8cc177ef3b597eef4987b674fc0c5a306d3a8cc1fe91a languageName: node linkType: hard -"@react-types/grid@npm:3.1.0": - version: 3.1.0 - resolution: "@react-types/grid@npm:3.1.0" - dependencies: - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 18207557ec789e943c22839cf58d9ff05fa522d7d9b271743c0b07a2c6a5ae545638d0ad5f87f2dba0f59b544630740d511417dd88d6dc045dcf16bbbb3d35cd +"@npmcli/name-from-folder@npm:^2.0.0": + version: 2.0.0 + resolution: "@npmcli/name-from-folder@npm:2.0.0" + checksum: fb3ef891aa57315fb6171866847f298577c8bda98a028e93e458048477133e142b4eb45ce9f3b80454f7c257612cb01754ee782d608507698dd712164436f5bd languageName: node linkType: hard -"@react-types/grid@npm:^3.1.0, @react-types/grid@npm:^3.2.4": - version: 3.2.4 - resolution: "@react-types/grid@npm:3.2.4" +"@paloaltonetworks/openapi-to-postmanv2@npm:3.1.0-hotfix.1": + version: 3.1.0-hotfix.1 + resolution: "@paloaltonetworks/openapi-to-postmanv2@npm:3.1.0-hotfix.1" dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: b022bd9be91109c6b508b68abc9db89be028a73764073db56a7bcdcc5c5aa53f5c45241ba17e8ad8858d2a1993e7b5ac5861391a96a244392fb47e72004dce69 + "@paloaltonetworks/postman-collection": ^4.1.0 + ajv: 8.1.0 + ajv-formats: 2.1.1 + async: 3.2.1 + commander: 2.20.3 + js-yaml: 3.14.1 + json-schema-merge-allof: 0.8.1 + lodash: 4.17.21 + oas-resolver-browser: 2.5.2 + path-browserify: 1.0.1 + yaml: 1.10.2 + bin: + openapi2postmanv2: bin/openapi2postmanv2.js + checksum: 31021f3eae6098b9860eb4bbd903c1fbfdd4fa3930228f57ef428d673e53a2ee59f5dec3271f13c2bd40ad887401abf52d5f669530a9f3c504c441ec34a78cc4 languageName: node linkType: hard -"@react-types/label@npm:^3.6.0": - version: 3.9.1 - resolution: "@react-types/label@npm:3.9.1" +"@paloaltonetworks/postman-code-generators@npm:1.1.15-patch.2": + version: 1.1.15-patch.2 + resolution: "@paloaltonetworks/postman-code-generators@npm:1.1.15-patch.2" dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 91241272a7b3e2f2c38b95903d31474866fbc7233d222aca116511accf5b2f6330ecfbb7bd139b0cf870a7eda5c52e8f53ddbb19dcc8296792b47993ac4b160d + "@paloaltonetworks/postman-collection": ^4.1.0 + async: ^3.2.4 + path: ^0.12.7 + shelljs: ^0.8.5 + checksum: bfea89b57778b142591513cb676e0e88bf85b884cd725c825ddb65aebaeb3f92b781a2feb4bee0bbba99c077b32bea195b0f579c689923eb4c78371c6bce309a languageName: node linkType: hard -"@react-types/menu@npm:3.6.0": - version: 3.6.0 - resolution: "@react-types/menu@npm:3.6.0" +"@paloaltonetworks/postman-collection@npm:^4.1.0": + version: 4.1.1 + resolution: "@paloaltonetworks/postman-collection@npm:4.1.1" dependencies: - "@react-types/overlays": ^3.6.0 - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 7108d9bd0b74efdd1a7dd960bb9c8dcb62bc35ef3851559e38789909b9d8dcfd3b9dcdd8cf54c50caea13d7e10b7e5cbde7d00033e85b82794f6f744d6e0e52e + file-type: 3.9.0 + http-reasons: 0.1.0 + iconv-lite: 0.6.3 + liquid-json: 0.3.1 + lodash: 4.17.21 + mime-format: 2.0.1 + mime-types: 2.1.34 + postman-url-encoder: 3.0.5 + semver: 7.3.5 + uuid: 8.3.2 + checksum: bf284e9a2ad41383af871842f6cc85e8affb629f06c6736b21bca760c6b37516a8f51a7a31a6eb2f84f9d5b7f2a2e792139f2bc7ec83d98f98f8520244d62b96 languageName: node linkType: hard -"@react-types/menu@npm:^3.6.0, @react-types/menu@npm:^3.9.7": - version: 3.9.7 - resolution: "@react-types/menu@npm:3.9.7" - dependencies: - "@react-types/overlays": ^3.8.5 - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: da1a76d7014a3f404557a037b3acdcd435a5571254f2b4aff52a46da8d64998fbba374a4c6f69c4149624b0130485a3fe572cbecc1fbeafdebb67b8e96a5696b +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f languageName: node linkType: hard -"@react-types/overlays@npm:3.6.0": - version: 3.6.0 - resolution: "@react-types/overlays@npm:3.6.0" +"@playwright/test@npm:^1.42.1": + version: 1.42.1 + resolution: "@playwright/test@npm:1.42.1" dependencies: - "@react-types/shared": ^3.13.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 9f6c773bcb4877c9847d79946e90286d335f5d0306e4f656be068bfeaa395bb685231614155282395356bf9acffc7a9086fc4aca8b117b4231e5985332cbe8fc + playwright: 1.42.1 + bin: + playwright: cli.js + checksum: a41505f02a4dac358e645452a190cac620b8d4eae79ab5d90ea1fb7ca06d86a9f5749b1a803dea789b662d1cbfd216380f722bed72093897e18b4238f4a07a4d languageName: node linkType: hard -"@react-types/overlays@npm:^3.6.0, @react-types/overlays@npm:^3.8.5": - version: 3.8.5 - resolution: "@react-types/overlays@npm:3.8.5" - dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 7c4aba5abc21c79543e1f497e595da8e4fde8c0583336cc5ab7c961cfc5ce608de2c33f3566a4ad89b01571d3b8483b06a14d5ef30b736fd4066f70ffa0c139d +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: a3d2b57e35eec9543d9eb085854f6e33e8102dac99fdef2fad2eebdbbfc345e93299f0c20e8eb61c1b4c7aa123bfd47c175678626f161cda65dd147c2b6e1fa0 languageName: node linkType: hard -"@react-types/radio@npm:^3.2.0, @react-types/radio@npm:^3.7.1": - version: 3.7.1 - resolution: "@react-types/radio@npm:3.7.1" +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" dependencies: - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 58935787e7e58f153bb8d94d54921d21e66be04b15e9cea4835f1b6f7716edfb743cf23a200ec15e9c4d575d2a94b01855a220372bb7fcfd891be871dd586c39 + graceful-fs: 4.2.10 + checksum: d8d0884646500576bd5390464d13db1bb9a62e32a1069293e5bddb2ad8354b354b7e2d2a35e12850025651e795e6a80ce9e601c66312504667b7e3ee7b52becc languageName: node linkType: hard -"@react-types/shared@npm:3.13.0": - version: 3.13.0 - resolution: "@react-types/shared@npm:3.13.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 59b94fd8ef8fbb8edeb44e233113450a15fee107f231eaced043a1acb820c7fb8bf690623a0f85e2a638a870ee074919d6f89263ad2395c26e363ae25b102bdf +"@pnpm/npm-conf@npm:^2.1.0": + version: 2.2.2 + resolution: "@pnpm/npm-conf@npm:2.2.2" + dependencies: + "@pnpm/config.env-replace": ^1.1.0 + "@pnpm/network.ca-file": ^1.0.1 + config-chain: ^1.1.11 + checksum: d64aa4464be584caa855eafa8f109509390489997e36d602d6215784e2973b896bef3968426bb00896cf4ae7d440fed2cee7bb4e0dbc90362f024ea3f9e27ab1 languageName: node linkType: hard -"@react-types/shared@npm:^3.13.0, @react-types/shared@npm:^3.22.1": - version: 3.22.1 - resolution: "@react-types/shared@npm:3.22.1" - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 162031517b3b2762d23999ca7b2d4f1d404a1b1823037f28abd7b70138dfe7929beee8a56781ec171de12ec510ec64837e60cb7a83ec959796368e9f7dc51f78 +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.25 + resolution: "@polka/url@npm:1.0.0-next.25" + checksum: 4ab1d7a37163139c0e7bfc9d1e3f6a2a0db91a78b9f0a21f571d6aec2cdaeaacced744d47886c117aa7579aa5694b303fe3e0bd1922bb9cb3ce6bf7c2dc09801 languageName: node linkType: hard -"@react-types/table@npm:^3.2.0, @react-types/table@npm:^3.9.3": - version: 3.9.3 - resolution: "@react-types/table@npm:3.9.3" - dependencies: - "@react-types/grid": ^3.2.4 - "@react-types/shared": ^3.22.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 077bd6fbf0ac2a22dd8d3770b421ebd8faa7dbddd831e8f14426baccd85b5ba8db97c84d79e1df5267cab761a86731a130a04010e2938a45604db271c65ca9b2 +"@popperjs/core@npm:^2.11.5": + version: 2.11.8 + resolution: "@popperjs/core@npm:2.11.8" + checksum: e5c69fdebf52a4012f6a1f14817ca8e9599cb1be73dd1387e1785e2ed5e5f0862ff817f420a87c7fc532add1f88a12e25aeb010ffcbdc98eace3d55ce2139cf0 languageName: node linkType: hard @@ -4270,11 +3204,19 @@ __metadata: languageName: node linkType: hard -"@redocly/openapi-core@npm:^1.0.0-beta.125": - version: 1.10.3 - resolution: "@redocly/openapi-core@npm:1.10.3" +"@redocly/config@npm:^0.5.0": + version: 0.5.0 + resolution: "@redocly/config@npm:0.5.0" + checksum: d81aab495af6554e1ddcd3b72625c3145887f2bac996ff5c1b565fad2b8cf2fa31bc7e5dbdcadf0f749d9dc3f9d2068023630a0be086c93014f5dca43e332880 + languageName: node + linkType: hard + +"@redocly/openapi-core@npm:^1.10.5": + version: 1.13.0 + resolution: "@redocly/openapi-core@npm:1.13.0" dependencies: "@redocly/ajv": ^8.11.0 + "@redocly/config": ^0.5.0 colorette: ^1.2.0 js-levenshtein: ^1.1.6 js-yaml: ^4.1.0 @@ -4283,7 +3225,7 @@ __metadata: node-fetch: ^2.6.1 pluralize: ^8.0.0 yaml-ast-parser: 0.0.43 - checksum: 8617ee39b245fa70f52d4dfdbd3ce8c7f1ce958116cf992ff4b6f16e93a3622186e14631f4e012e728f1f7b103cc98c577c708b9f1b45c93193c45f41fb8b6ba + checksum: 4dda44f2469d3c6756bdedb4ba14efbf9c4637dd64f9026a0329d48ca982f57bde408a102ccb89daa457991476a49cd05fca2925d258c5c1502a5de944bd27c0 languageName: node linkType: hard @@ -4397,15 +3339,6 @@ __metadata: languageName: node linkType: hard -"@stitches/react@npm:1.2.8": - version: 1.2.8 - resolution: "@stitches/react@npm:1.2.8" - peerDependencies: - react: ">= 16.3.0" - checksum: 029795323cdedb5599ec0636526fc233b2cf41fa9c1f4a704b1f7f457c6170053384a7430afed45e25f73e348d7c391cf1379bc079943cd9cad44302234a5244 - languageName: node - linkType: hard - "@svgr/babel-plugin-add-jsx-attribute@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:5.4.0" @@ -4693,25 +3626,6 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:^0.4.14": - version: 0.4.36 - resolution: "@swc/helpers@npm:0.4.36" - dependencies: - legacy-swc-helpers: "npm:@swc/helpers@=0.4.14" - tslib: ^2.4.0 - checksum: 20b9f021a9711633d709ef1c231423eb079cb7ed14ad191dc9583b0b46684a95d0e87c3efd7472e7673ddbd30eb200c21490ab43ad251df8f845cd09df3d236f - languageName: node - linkType: hard - -"@swc/helpers@npm:^0.5.0": - version: 0.5.6 - resolution: "@swc/helpers@npm:0.5.6" - dependencies: - tslib: ^2.4.0 - checksum: 45de57097e1f6f356f571c7a4f55c692a46b0404c8601e5d9552e152000dfe541ff529d3d01c8a4abf60799d6e7d0078936e40be0a203ca356299d5d6adea765 - languageName: node - linkType: hard - "@szmarczak/http-timer@npm:^1.1.2": version: 1.1.2 resolution: "@szmarczak/http-timer@npm:1.1.2" @@ -5080,7 +3994,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 @@ -5103,16 +4017,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash.clonedeep@npm:^4.5.7": - version: 4.5.9 - resolution: "@types/lodash.clonedeep@npm:4.5.9" - dependencies: - "@types/lodash": "*" - checksum: ef85512b7dce7a4f981a818ae44d11982907e1f26b5b26bedf0957c35e8591eb8e1d24fa31ca851d4b40e0a1ee88563853d762412691fe5f357e8335cead2325 - languageName: node - linkType: hard - -"@types/lodash@npm:*, @types/lodash@npm:^4.14.191": +"@types/lodash@npm:^4.14.191": version: 4.14.202 resolution: "@types/lodash@npm:4.14.202" checksum: a91acf3564a568c6f199912f3eb2c76c99c5a0d7e219394294213b3f2d54f672619f0fde4da22b29dc5d4c31457cd799acc2e5cb6bd90f9af04a1578483b6ff7 @@ -8813,17 +7718,44 @@ __metadata: languageName: node linkType: hard -"docusaurus-plugin-openapi-docs@dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-plugin-openapi-docs": - version: 2.0.0-beta.3 - resolution: "docusaurus-plugin-openapi-docs@https://github.com/dr-electron/docusaurus-openapi-docs.git#workspace=docusaurus-plugin-openapi-docs&commit=68f3225fc89d5a2620c9d70955a479d6bc912dd8" +"docusaurus-plugin-openapi-docs@jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-plugin-openapi-docs": + version: 2.1.3 + resolution: "docusaurus-plugin-openapi-docs@https://github.com/jlvandenhout/docusaurus-openapi-docs.git#workspace=docusaurus-plugin-openapi-docs&commit=14c2a23d68bca86413e5fe8b3627d986da703667" + dependencies: + "@apidevtools/json-schema-ref-parser": ^11.5.4 + "@docusaurus/plugin-content-docs": ">=2.4.1 <=2.4.3" + "@docusaurus/utils": ">=2.4.1 <=2.4.3" + "@docusaurus/utils-validation": ">=2.4.1 <=2.4.3" + "@paloaltonetworks/openapi-to-postmanv2": 3.1.0-hotfix.1 + "@paloaltonetworks/postman-collection": ^4.1.0 + "@redocly/openapi-core": ^1.10.5 + chalk: ^4.1.2 + clsx: ^1.1.1 + fs-extra: ^9.0.1 + json-pointer: ^0.6.2 + json-schema-merge-allof: ^0.8.1 + lodash: ^4.17.20 + mustache: ^4.2.0 + slugify: ^1.6.5 + swagger2openapi: ^7.0.8 + xml-formatter: ^2.6.1 + peerDependencies: + react: ^16.8.4 || ^17.0.0 || ^18.0.0 + checksum: 6912ca4b9add60b70f6463d63503ab109d5aa964b4d37798fe2f8931153898888975dd6fda83e41028c95b4488453598eb4e8986486adf4c394962ac0af726d1 + languageName: node + linkType: hard + +"docusaurus-plugin-openapi-docs@npm:^2.1.3": + version: 2.1.3 + resolution: "docusaurus-plugin-openapi-docs@npm:2.1.3" dependencies: - "@apidevtools/json-schema-ref-parser": ^10.1.0 - "@docusaurus/plugin-content-docs": ">=2.3.0 <2.5.0" - "@docusaurus/utils": ">=2.3.0 <2.5.0" - "@docusaurus/utils-validation": ">=2.3.0 <2.5.0" + "@apidevtools/json-schema-ref-parser": ^11.5.4 + "@docusaurus/plugin-content-docs": ">=2.4.1 <=2.4.3" + "@docusaurus/utils": ">=2.4.1 <=2.4.3" + "@docusaurus/utils-validation": ">=2.4.1 <=2.4.3" "@paloaltonetworks/openapi-to-postmanv2": 3.1.0-hotfix.1 "@paloaltonetworks/postman-collection": ^4.1.0 - "@redocly/openapi-core": ^1.0.0-beta.125 + "@redocly/openapi-core": ^1.10.5 chalk: ^4.1.2 clsx: ^1.1.1 fs-extra: ^9.0.1 @@ -8835,8 +7767,8 @@ __metadata: swagger2openapi: ^7.0.8 xml-formatter: ^2.6.1 peerDependencies: - react: ^16.8.4 || ^17.0.0 - checksum: 96d4958cbc1b678a70f53975561aa540c3ec3cd32c28dc7a9e8ba45fe9626874a9e7d95f5e24dcbcb9fe66b4c867f1144b703469c0b3d57d95a31b1759ac8d3e + react: ^16.8.4 || ^17.0.0 || ^18.0.0 + checksum: 0ba75132f3d8eaf14acd40a1759af80dae0dcae4c4a3e5f2c60c78b64b3768bc1509c786e89a44a77391162acfc9cf5f435c377a2cc3b2e68023a22091d3d6ff languageName: node linkType: hard @@ -8852,20 +7784,19 @@ __metadata: languageName: node linkType: hard -"docusaurus-theme-openapi-docs@dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-theme-openapi-docs": - version: 2.0.0-beta.3 - resolution: "docusaurus-theme-openapi-docs@https://github.com/dr-electron/docusaurus-openapi-docs.git#workspace=docusaurus-theme-openapi-docs&commit=68f3225fc89d5a2620c9d70955a479d6bc912dd8" +"docusaurus-theme-openapi-docs@jlvandenhout/docusaurus-openapi-docs#head=patch-main&workspace=docusaurus-theme-openapi-docs": + version: 2.1.3 + resolution: "docusaurus-theme-openapi-docs@https://github.com/jlvandenhout/docusaurus-openapi-docs.git#workspace=docusaurus-theme-openapi-docs&commit=14c2a23d68bca86413e5fe8b3627d986da703667" dependencies: - "@docusaurus/theme-common": ">=2.3.0 <2.5.0" + "@docusaurus/theme-common": ">=2.4.1 <=2.4.3" "@hookform/error-message": ^2.0.1 - "@nextui-org/react": ^1.0.0-beta.12 "@paloaltonetworks/postman-code-generators": 1.1.15-patch.2 "@paloaltonetworks/postman-collection": ^4.1.0 "@reduxjs/toolkit": ^1.7.1 clsx: ^1.1.1 copy-text-to-clipboard: ^3.1.0 crypto-js: ^4.1.1 - docusaurus-plugin-openapi-docs: "dr-electron/docusaurus-openapi-docs#head=tmp-fix-type&workspace=docusaurus-plugin-openapi-docs" + docusaurus-plugin-openapi-docs: ^2.1.3 docusaurus-plugin-sass: ^0.2.3 file-saver: ^2.0.5 lodash: ^4.17.20 @@ -8879,12 +7810,13 @@ __metadata: react-redux: ^7.2.0 rehype-raw: ^6.1.1 sass: ^1.58.1 + sass-loader: ^13.3.2 webpack: ^5.61.0 xml-formatter: ^2.6.1 peerDependencies: - react: ^16.8.4 || ^17.0.0 - react-dom: ^16.8.4 || ^17.0.0 - checksum: 100c1530d741db4212791e1c59e3557ff71b68b57b3534672020bd8ba1b001a66d46bffbb86b81c4c9be7c590b02e3dfb230ff009a7246041b7c43b67b044331 + react: ^16.8.4 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0 + checksum: 59d45fc4217af4e30646678ac3aecec7ed408b3d778a9237cf09c01f7f945884059423e460135c35f2335b4643588f182259d5ba398bc1bbe7963578aa2500de languageName: node linkType: hard @@ -8897,7 +7829,7 @@ __metadata: languageName: node linkType: hard -"dom-helpers@npm:^5.0.1, dom-helpers@npm:^5.2.1": +"dom-helpers@npm:^5.0.1": version: 5.2.1 resolution: "dom-helpers@npm:5.2.1" dependencies: @@ -11757,18 +10689,6 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:^10.1.0": - version: 10.5.11 - resolution: "intl-messageformat@npm:10.5.11" - dependencies: - "@formatjs/ecma402-abstract": 1.18.2 - "@formatjs/fast-memoize": 2.2.0 - "@formatjs/icu-messageformat-parser": 2.7.6 - tslib: ^2.4.0 - checksum: b5574447a0d938170049042ec807344d57c72e9aabb2e72be0d5197baabeb763e05680b19b7607df93fadeec0e13c9bfcb450e9ba2fe7464b4f06600b612bf5e - languageName: node - linkType: hard - "invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -12838,15 +11758,6 @@ __metadata: languageName: node linkType: hard -"legacy-swc-helpers@npm:@swc/helpers@=0.4.14": - version: 0.4.14 - resolution: "@swc/helpers@npm:0.4.14" - dependencies: - tslib: ^2.4.0 - checksum: 273fd3f3fc461a92f3790cc551ea054745c6d6959afbe1232e6d7aa1c722bbc114d308aab96bef5c78fc0303c85c7b472ef00e2253251cc89737f3b1af56e5a5 - languageName: node - linkType: hard - "less@npm:^4.1.3": version: 4.2.0 resolution: "less@npm:4.2.0" @@ -16772,7 +15683,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"react-transition-group@npm:^4.3.0, react-transition-group@npm:^4.4.2, react-transition-group@npm:^4.4.5": +"react-transition-group@npm:^4.3.0, react-transition-group@npm:^4.4.5": version: 4.4.5 resolution: "react-transition-group@npm:4.4.5" dependencies: @@ -16975,13 +15886,6 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.4": - version: 0.13.11 - resolution: "regenerator-runtime@npm:0.13.11" - checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 - languageName: node - linkType: hard - "regenerator-runtime@npm:^0.14.0": version: 0.14.1 resolution: "regenerator-runtime@npm:0.14.1" @@ -17652,6 +16556,30 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"sass-loader@npm:^13.3.2": + version: 13.3.3 + resolution: "sass-loader@npm:13.3.3" + dependencies: + neo-async: ^2.6.2 + peerDependencies: + fibers: ">= 3.1.0" + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + sass: ^1.3.0 + sass-embedded: "*" + webpack: ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + sass-embedded: + optional: true + checksum: 32bdb99afc07de06291091c847ec5a21eca1a4136a58a5a57f965a70e53d40d4f88625b828915ffb205baa866eef16a7c2c3a4db416b74ec6fe0bb00a04b7609 + languageName: node + linkType: hard + "sass@npm:^1.58.1, sass@npm:^1.58.3": version: 1.71.1 resolution: "sass@npm:1.71.1" @@ -19401,7 +18329,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"typescript@npm:^4.5.4, typescript@npm:^4.6.3, typescript@npm:^4.9": +"typescript@npm:^4.5.4": version: 4.9.5 resolution: "typescript@npm:4.9.5" bin: @@ -19411,7 +18339,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"typescript@patch:typescript@^4.5.4#~builtin, typescript@patch:typescript@^4.6.3#~builtin, typescript@patch:typescript@^4.9#~builtin": +"typescript@patch:typescript@^4.5.4#~builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=bda367" bin: @@ -21061,7 +19989,7 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard -"ws@npm:^8.13.0, ws@npm:^8.16.0, ws@npm:^8.8.1": +"ws@npm:^8.13.0, ws@npm:^8.8.1": version: 8.16.0 resolution: "ws@npm:8.16.0" peerDependencies: @@ -21076,6 +20004,21 @@ plugin-image-zoom@flexanalytics/plugin-image-zoom: languageName: node linkType: hard +"ws@npm:^8.17.1": + version: 8.17.1 + resolution: "ws@npm:8.17.1" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 442badcce1f1178ec87a0b5372ae2e9771e07c4929a3180321901f226127f252441e8689d765aa5cfba5f50ac60dd830954afc5aeae81609aefa11d3ddf5cecf + languageName: node + linkType: hard + "xdg-basedir@npm:^4.0.0": version: 4.0.0 resolution: "xdg-basedir@npm:4.0.0"