diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..0afac12 --- /dev/null +++ b/404.html @@ -0,0 +1,3181 @@ + + + + + + + + + + + + + + + + + + + + + Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_site_essentials/fonts/GeneralSans-Bold.woff2 b/_site_essentials/fonts/GeneralSans-Bold.woff2 new file mode 100644 index 0000000..65b0b4a Binary files /dev/null and b/_site_essentials/fonts/GeneralSans-Bold.woff2 differ diff --git a/_site_essentials/fonts/GeneralSans-Medium.woff2 b/_site_essentials/fonts/GeneralSans-Medium.woff2 new file mode 100644 index 0000000..c90195f Binary files /dev/null and b/_site_essentials/fonts/GeneralSans-Medium.woff2 differ diff --git a/_site_essentials/fonts/GeneralSans-Regular.woff2 b/_site_essentials/fonts/GeneralSans-Regular.woff2 new file mode 100644 index 0000000..2bc4672 Binary files /dev/null and b/_site_essentials/fonts/GeneralSans-Regular.woff2 differ diff --git a/_site_essentials/fonts/GeneralSans-Semibold.woff2 b/_site_essentials/fonts/GeneralSans-Semibold.woff2 new file mode 100644 index 0000000..b17a037 Binary files /dev/null and b/_site_essentials/fonts/GeneralSans-Semibold.woff2 differ diff --git a/_site_essentials/js/mathjax.js b/_site_essentials/js/mathjax.js new file mode 100644 index 0000000..06dbf38 --- /dev/null +++ b/_site_essentials/js/mathjax.js @@ -0,0 +1,16 @@ +window.MathJax = { + tex: { + inlineMath: [["\\(", "\\)"]], + displayMath: [["\\[", "\\]"]], + processEscapes: true, + processEnvironments: true + }, + options: { + ignoreHtmlClass: ".*|", + processHtmlClass: "arithmatex" + } +}; + +document$.subscribe(() => { + MathJax.typesetPromise() +}) diff --git a/_site_essentials/stylesheets/dojima-docs.webflow.css b/_site_essentials/stylesheets/dojima-docs.webflow.css new file mode 100644 index 0000000..1ac0979 --- /dev/null +++ b/_site_essentials/stylesheets/dojima-docs.webflow.css @@ -0,0 +1,964 @@ +:root { + --smoke-white: #f8f8f8; + --main-black: #110c22; + --gray-light: #8d8a95; + --white: white; + --gray: #4f4b5c; + --purple: #773ef0; +} + +h1 { + margin-top: 0; + margin-bottom: 0 !important; + font-size: 38px; + font-weight: 600 !important; + line-height: 44px; + color: var(--main-black) !important; + font-family: Generalsans, sans-serif !important; +} + +h2 { + margin-top: 0; + margin-bottom: 0 !important; + font-size: 32px; + font-weight: 600 !important; + line-height: 36px; + color: var(--main-black) !important; + font-family: Generalsans, sans-serif !important; +} +.md-ellipsis { + color: var(--main-black); +} +.md-nav__item .md-nav__link--active, +.md-nav__item .md-nav__link--active .md-ellipsis { + color: var(--purple); +} +div.main h1 { + margin-top: 0 !important; +} + +div.main h3 { + margin-top: 0 !important; +} + +h3 { + margin-bottom: 0 !important; + font-size: 24px; + font-weight: 600 !important; + line-height: 1.2; + color: var(--main-black) !important; + font-family: Generalsans, sans-serif !important; +} + +h4, +h5 { + font-family: Generalsans, sans-serif !important; +} +.hero-div { + margin-top: 0px; +} +.icon-background { + width: 32px; + height: 32px; + border-radius: 100%; + background-color: #000; + padding: 8px; + display: flex; + align-items: center; + justify-items: center; + margin-left: 20px; +} + +.button-container { + display: flex; + row-gap: 100px; + align-items: center; + justify-items: center; + margin-top: 48px; +} + +.getstarted-button { + border: 1px solid #fff; + border-radius: 16px; + background-color: #7612d4; + color: #fff; + padding: 12px; + font-size: 20px; + font-weight: 500; + line-height: 20px; +} + +div.main p { + color: var(--gray); + margin-bottom: 0; + font-weight: 500; + line-height: 1.6; +} + +.md-tabs__item--active { + color: var(--purple) !important; + font-weight: 800 !important; +} + +.md-header--shadow { + box-shadow: none !important; +} + +.md-main { + background-color: var(--smoke-white) !important; +} + +div.main div.flexbox a { + color: var(--main-black) !important; +} + +div.main .nav-bar { + background-color: var(--white); + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + padding: 10px 108px; +} + +div.main .container-global { + width: 100%; + max-width: 1224px; + margin-left: auto; + margin-right: auto; +} + +div.main .nav-menu { + grid-column-gap: 24px; + grid-row-gap: 24px; + align-items: center; + display: flex; +} + +div.main .nav-link { + color: var(--gray); + padding: 2px 0; + font-weight: 500; + transition: color 0.2s; +} + +div.main .nav-link:hover { + color: var(--gray-light); +} + +div.main .nav-link.w--current { + color: var(--purple); + font-weight: 600; +} + +div.main .nav-content { + grid-row-gap: 20px; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + display: flex; +} + +div.main .section { +} + +.hero-content-flex { + grid-column-gap: 3rem; + grid-row-gap: 3rem; + justify-content: space-between; + align-items: flex-start; + display: flex; + position: relative; + bottom: 50px; + padding-bottom: 120px; +} + +.hero-content-flex.product-hero-flex { + grid-column-gap: 1rem; + grid-row-gap: 1rem; +} + +.hero-left { + /* max-width: 580px; */ + width: 50%; + position: relative; + z-index: 3; +} + +.hero-right { + position: absolute; + bottom: 0px; + right: 0; + width: 100%; + /* flex: 1 auto; */ +} + +.hero-right.is-big { + min-width: 50%; +} + +.hero-image { + width: 100%; + height: 100%; + object-fit: cover; +} + +.hero-content-flex .hero-heading { + color: var(--main-black) !important; + margin-bottom: 16px !important; + font-size: 56px; + line-height: 1.3 !important; + font-weight: 750; + line-height: 62px; + max-width: 493px; +} + +.hero-subext { + color: var(--gray); + font-weight: 500; +} + +.flexbox-2-col { + grid-column-gap: 24px; + grid-row-gap: 24px; + justify-content: space-between; + display: flex; +} + +.flex-card-child { + width: 100%; + background-color: var(--white); + border: 1px solid rgba(0, 0, 0, 0.08); + border-radius: 12px; + overflow: hidden; + box-shadow: 0 2px 4px rgba(17, 12, 34, 0.1); +} + +.flex-card-item { + color: var(--gray); + border-bottom: 1px solid #ececed; + flex-direction: column; + align-items: flex-start; + padding: 18px 24px; + text-decoration: none; + transition: background-color 0.2s, color 0.2s; + display: flex; +} + +.flex-card-item:hover { + color: var(--purple); + background-color: #f8f8f8; +} + +.flex-card-item.header-item { + padding-top: 24px; + padding-bottom: 24px; +} + +.flex-card-item.header-item:hover { + color: var(--gray); + background-color: #fff; +} + +.flex-card-item.last-item { + border: 1px #000; +} + +.heading-h3 { + margin-bottom: 8px; + font-size: 22px; +} + +.heading-h3.margin-none { + margin-bottom: 0; +} + +.feature-paragraph { + color: var(--gray-light); + font-size: 14px; + font-weight: 500; + line-height: 1.6; +} + +.feature-card-heading { + font-size: 18px; + font-weight: 600; +} + +.section-wrapper { + padding-top: 48px; +} +@media only screen and (min-width: 768px) { + .gird-container { + display: grid; + margin-top: 100px; + grid-template-columns: 415px auto; + column-gap: 24px; + } +} +@media only screen and (max-width: 767px) { + .gird-container { + display: grid; + grid-template-columns: auto; + row-gap: 12px; + } +} +.card-container { + border-radius: 16px; + border: 1px solid #e0e0e0; + padding: 32px 32px 65px 32px; + background-color: #fff; +} + +.right-card-container { + border-radius: 16px; + border: 1px solid #e0e0e0; + padding: 32px; + background-color: #fff; +} + +.first-p { + padding: 0px 0px 20px 0px; + border-bottom: 1px solid #e0e0e0; + color: #000000; + font-size: 18px; + font-weight: 400; + line-height: 26px; +} + +.middle-p { + display: block; + padding: 20px 0px 20px 0px; + border-bottom: 1px solid #e0e0e0; +} +.right-grid-a .live { + background-color: #8D57DE; + padding: 3px 8px; + border-radius: 6px; + font-size: 12px; + font-weight: 400; + color: #FFF; +} +.last-p { + display: block; + padding: 20px 0px 0px 0px; +} +@media only screen and (min-width: 768px) { + .div-left-grid { + display: flex; + flex-direction: column; + row-gap: 24px; + } +} +@media only screen and (max-width: 767px) { + .div-left-grid { + display: flex; + flex-direction: column; + row-gap: 12px; + } +} +.div-card { + display: flex; + flex-direction: column; +} + +.div-card-header { + display: flex; + flex-direction: row; + align-items: center; + column-gap: 24px; +} + +.div-leftcard-p { + font-size: 18px; + font-weight: 400; + line-height: 26px; + margin-top: 24px; + color: #000; +} + +.div-card-button-container { + display: flex; + flex-direction: column; + justify-items: center; + row-gap: 16px; + margin-top: 40px; +} + +.div-card-button { + display: flex; + flex-direction: row; + align-items: center; + color: #7612d4; + column-gap: 12px; + font-size: 18px; + font-weight: 650; + line-height: 26px; +} + +.right-grid-a { + display: flex; + flex-direction: row; + align-items: center; + column-gap: 12px; +} + +.left-p{ + font-size: 18px; + margin-top: 0; + font-weight: 650; + line-height: 26px; + color: #4051b5; +} +.right-grid-a .right-p { + font-size: 18px; + margin-top: 0; + font-weight: 650; + line-height: 26px; + color: #7612d4; +} + +.section-wrapper.product-section-head { + padding-top: 0; +} + +.section-header-wrapper { + margin-bottom: 48px; +} + +.heading-h2 { + margin-bottom: 8px; + line-height: 1.3; +} + +.heading-h2.product { + color: var(--main-black); + margin-bottom: 16px; +} + +.home-section-subtext.max-width-applied { + max-width: 72%; +} + +.flexbox { + grid-column-gap: 24px; + grid-row-gap: 24px; + display: flex; +} + +.flexbox.items-4 { + margin-top: 24px; +} + +.home-feature-card { + width: 100%; + min-height: 200px; + grid-column-gap: 24px; + grid-row-gap: 24px; + background-color: var(--white); + color: var(--main-black); + border: 1px solid rgba(0, 0, 0, 0); + border-radius: 12px; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + padding: 24px; + text-decoration: none; + transition: color 0.2s, border-color 0.2s; + display: flex; + box-shadow: 0 6px 16px -2px rgba(17, 12, 34, 0.1); +} + +.home-feature-card:hover { + color: var(--purple); + border: 1px solid #c6c5ca; +} + +.feature-icon { + width: 32px; + height: auto; +} + +.feature-content-name { + font-size: 22px; + font-weight: 600; + line-height: 1.2; + display: inline; +} + +.paragraph-small { + font-size: 14px; +} + +.feature-content-wrapper { + grid-column-gap: 8px; + grid-row-gap: 8px; + margin-bottom: 8px; +} + +.search-wrapper { + grid-column-gap: 12px; + grid-row-gap: 12px; + align-items: center; + display: flex; +} + +.search-block { + margin-bottom: 0; +} + +.search-bar { + max-width: 260px; + min-height: 40px; + min-width: 260px; + background-color: #ececed; + background-image: url("../images/search.svg"); + background-position: 8px; + background-repeat: no-repeat; + background-size: auto; + border: 1px #000; + border-radius: 9px; + margin-bottom: 0; + padding-left: 44px; + padding-right: 8px; +} + +.search-bar::-ms-input-placeholder { + color: var(--gray); + font-size: 14px; + font-weight: 500; +} + +.search-bar::placeholder { + color: var(--gray); + font-size: 14px; + font-weight: 500; +} + +.polygon-docs-link { + grid-column-gap: 8px; + grid-row-gap: 8px; + color: var(--main-black); + align-items: center; + padding: 8px; + font-size: 14px; + font-weight: 500; + text-decoration: none; + display: flex; +} + +.site-wrapper { + padding-left: 108px; + padding-right: 108px; +} + +.product-page-flex { + grid-column-gap: 48px; + grid-row-gap: 48px; + justify-content: space-between; + display: flex; +} + +.product-sidebar { + width: 25%; + align-self: flex-start; + position: -webkit-sticky; + position: sticky; + top: 32px; +} + +.product-content { + width: 75%; + border-left: 1px solid #ececed; + padding-left: 48px; +} + +.side-bar-link { + width: 100%; + color: var(--main-black); + border-radius: 8px; + margin-bottom: 8px; + padding: 8px 12px; + font-weight: 500; + line-height: 1.5; + text-decoration: none; + transition: all 0.25s; +} + +.side-bar-link:hover { + background-color: rgba(217, 216, 220, 0.25); +} + +.side-bar-link.w--current { + background-color: #d9d8dc; + font-weight: 600; +} + +.product-info { + color: var(--gray); +} + +.product-link-span { + color: #773ef0; +} + +.code-label { + grid-column-gap: 8px; + grid-row-gap: 8px; + color: var(--gray); + align-items: center; + margin-top: 16px; + font-size: 14px; + font-weight: 500; + display: flex; +} + +.purple-circle { + width: 8px; + height: 8px; + background-color: var(--purple); + border-radius: 50%; +} + +.nav-menu-btn { + padding: 8px; +} + +.search-trigger { + justify-content: space-between; + align-items: center; + display: none; +} + +.mobile-search-close { + display: none; +} + +.nav-content-left { + grid-column-gap: 20px; + grid-row-gap: 20px; + flex-direction: column; + display: flex; +} + +.product-list-header { + grid-column-gap: 8px; + grid-row-gap: 8px; + align-items: center; + margin-bottom: 8px; + display: flex; +} + +.status-tag { + color: var(--purple); + background-color: #ebe1ff; + border-radius: 4px; + margin-left: 10px; + padding-left: 8px; + padding-right: 8px; + font-size: 12px; + font-weight: 500; +} + +.product-list-item-header { + grid-row-gap: 12px; + flex-wrap: wrap; + align-items: flex-start; + margin-bottom: 8px; + display: flex; + position: relative; +} + +.hidden { + display: none; +} + +.arrow-embed { + width: 16px; + min-width: 16px; + margin-left: 8px; + display: inline-block; +} + +@media screen and (max-width: 991px) { + .nav-bar { + padding-left: 32px; + padding-right: 32px; + } + + .nav-menu { + width: 90vw; + background-color: var(--white); + flex-direction: column; + padding: 80px 24px 24px; + } + + .nav-link { + margin-bottom: 12px; + padding-top: 8px; + padding-bottom: 8px; + font-size: 24px; + } + + .nav-content { + flex-direction: row; + align-items: center; + } + + .section { + padding-left: 32px; + padding-right: 32px; + } + + .hero-content-flex { + grid-row-gap: 32px; + flex-direction: column; + padding-bottom: 0; + } + + .hero-left { + width: 100%; + max-width: none; + margin-top: auto; + margin-bottom: auto; + } + + .hero-right { + position: relative; + width: 100%; + } + + .flexbox-2-col { + grid-column-gap: 12px; + } + + .section-wrapper { + padding-top: 32px; + padding-bottom: 32px; + } + + .section-header-wrapper { + margin-bottom: 32px; + } + + .flexbox { + grid-column-gap: 12px; + grid-row-gap: 12px; + } + + .flexbox.items-4 { + margin-top: 12px; + } + + .site-wrapper { + padding-left: 32px; + padding-right: 32px; + } + + .product-page-flex { + padding-top: 0; + } + + .product-sidebar { + display: none; + } + + .product-content { + width: 100%; + border-left-style: none; + padding-left: 0; + } + + .polygon-docs-text { + display: none; + } + + .nav-menu-btn { + color: var(--white); + } + + .nav-menu-btn.w--open { + z-index: 5; + background-color: var(--white); + } + + .menu-icon { + width: 24px; + height: 24px; + } + + .nav-content-left { + grid-column-gap: 8px; + grid-row-gap: 8px; + flex-direction: row; + align-items: center; + } + + .nav-closer { + display: none; + } +} + +@media screen and (max-width: 767px) { + .nav-bar { + padding-left: 12px; + padding-right: 12px; + } + + .nav-menu { + -webkit-backdrop-filter: blur(6px); + backdrop-filter: blur(6px); + padding-left: 12px; + } + + .nav-brand.w--current { + padding-left: 0; + } + + .nav-content { + grid-row-gap: 8px; + } + + .section { + padding-left: 12px; + padding-right: 12px; + } + + .hero-content-flex .hero-heading { + font-size: 32px; + } + + .hero-subext { + font-size: 14px; + } + + .flexbox-2-col { + flex-direction: column; + } + + .section-wrapper { + padding-top: 24px; + padding-bottom: 24px; + } + + .heading-h2.product { + margin-bottom: 8px; + font-size: 24px; + } + + .flexbox { + grid-column-gap: 24px; + grid-row-gap: 24px; + flex-direction: column; + } + + .search-wrapper { + top: 0%; + } + + .search-block { + width: 100%; + height: 100%; + -webkit-backdrop-filter: blur(3px); + backdrop-filter: blur(3px); + background-color: rgba(255, 255, 255, 0.32); + padding-top: 24px; + display: none; + position: fixed; + top: 6%; + bottom: 0%; + left: 0%; + right: 0%; + } + + .search-form { + height: 100%; + padding-left: 12px; + padding-right: 12px; + } + + .search-bar { + max-width: none; + min-width: 0; + } + + .site-wrapper { + padding-left: 12px; + padding-right: 12px; + } + + .nav-menu-btn { + padding: 2px; + } + + .search-icon-mobile { + width: 24px; + height: auto; + } + + .mobile-search-icon { + padding: 8px; + } + + .search-trigger { + cursor: pointer; + justify-content: space-between; + display: flex; + } + + .mobile-search-close { + padding: 8px; + display: none; + } + + .nav-content-left { + grid-column-gap: 4px; + grid-row-gap: 4px; + } + + .search-close-mobile { + width: 20px; + height: auto; + } + + .nav-hamburger, + .nav-closer { + width: 28px; + height: 28px; + } +} + +@media screen and (max-width: 479px) { + .nav-brand.w--current { + padding-left: 0; + } +} + +@font-face { + font-family: "Generalsans"; + src: url("../fonts/GeneralSans-Semibold.woff2") format("woff2"); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Generalsans"; + src: url("../fonts/GeneralSans-Medium.woff2") format("woff2"); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Generalsans"; + src: url("../fonts/GeneralSans-Bold.woff2") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Generalsans"; + src: url("../fonts/GeneralSans-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} diff --git a/_site_essentials/stylesheets/extra.css b/_site_essentials/stylesheets/extra.css new file mode 100644 index 0000000..3375ab7 --- /dev/null +++ b/_site_essentials/stylesheets/extra.css @@ -0,0 +1,85 @@ +[data-md-color-scheme="slate"] { + --md-footer-bg-color: black; + + .md-footer, + .md-footer__inner, + .md-footer-meta { + background-color: black; + } +} + +[data-md-color-scheme="default"] { + --md-footer-bg-color: white; + --md-footer-fg-color: charcoal; + --md-default-bg-color: white; + --md-footer-fg-color--light: charcoal; + --md-footer-fg-color--lighter: charcoal; + + .md-footer, + .md-footer__inner, + .md-footer-meta { + background-color: white; + } +} + +img.figure { + margin: 0 auto; + display: block; +} + +div.flex-figure { + display: flex; +} + +div.flex-figure div.flex-figure-left { + flex-grow: 1; + flex-shrink: 5; +} + +div.flex-figure div.flex-figure-right { + flex-grow: 2; +} + +.feature-paragraph { + text-align: left; +} +* { +box-sizing: border-box; +} +.grid-container { +display: flex; +flex-wrap: wrap; +width: 100%; +padding: 10px; +align-items: stretch; +} +.grid-item { +background-color: white; +border-radius: 8px; +-webkit-box-shadow: 0 8px 16px 0 rgb(17 17 17 / 8%); +box-shadow: 0 8px 16px 0 rgb(17 17 17 / 8%); +padding: 33px; +margin: 5px; +text-align: center; +align-items: center; +flex: 32%; +width: 32%; +} +@media screen and (max-width: 1000px) { +.grid-item { +flex: 32%; +max-width: 32%; +} +} +@media screen and (max-width: 800px) { +.grid-item { +flex: 48%; +max-width: 48%; +} +} +@media screen and (max-width: 600px) { +.grid-item { +flex: 100%; +max-width: 100%; +} +} \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.bd41221c.min.js b/assets/javascripts/bundle.bd41221c.min.js new file mode 100644 index 0000000..70bcbf1 --- /dev/null +++ b/assets/javascripts/bundle.bd41221c.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var _i=Object.create;var br=Object.defineProperty;var Ai=Object.getOwnPropertyDescriptor;var Ci=Object.getOwnPropertyNames,Ft=Object.getOwnPropertySymbols,ki=Object.getPrototypeOf,vr=Object.prototype.hasOwnProperty,eo=Object.prototype.propertyIsEnumerable;var Zr=(e,t,r)=>t in e?br(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,F=(e,t)=>{for(var r in t||(t={}))vr.call(t,r)&&Zr(e,r,t[r]);if(Ft)for(var r of Ft(t))eo.call(t,r)&&Zr(e,r,t[r]);return e};var to=(e,t)=>{var r={};for(var o in e)vr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Ft)for(var o of Ft(e))t.indexOf(o)<0&&eo.call(e,o)&&(r[o]=e[o]);return r};var gr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Hi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ci(t))!vr.call(e,n)&&n!==r&&br(e,n,{get:()=>t[n],enumerable:!(o=Ai(t,n))||o.enumerable});return e};var jt=(e,t,r)=>(r=e!=null?_i(ki(e)):{},Hi(t||!e||!e.__esModule?br(r,"default",{value:e,enumerable:!0}):r,e));var ro=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var no=gr((xr,oo)=>{(function(e,t){typeof xr=="object"&&typeof oo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(C){return!!(C&&C!==document&&C.nodeName!=="HTML"&&C.nodeName!=="BODY"&&"classList"in C&&"contains"in C.classList)}function c(C){var ct=C.type,Ne=C.tagName;return!!(Ne==="INPUT"&&s[ct]&&!C.readOnly||Ne==="TEXTAREA"&&!C.readOnly||C.isContentEditable)}function p(C){C.classList.contains("focus-visible")||(C.classList.add("focus-visible"),C.setAttribute("data-focus-visible-added",""))}function l(C){C.hasAttribute("data-focus-visible-added")&&(C.classList.remove("focus-visible"),C.removeAttribute("data-focus-visible-added"))}function f(C){C.metaKey||C.altKey||C.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(C){o=!1}function h(C){a(C.target)&&(o||c(C.target))&&p(C.target)}function w(C){a(C.target)&&(C.target.classList.contains("focus-visible")||C.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(C.target))}function A(C){document.visibilityState==="hidden"&&(n&&(o=!0),Z())}function Z(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function te(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(C){C.target.nodeName&&C.target.nodeName.toLowerCase()==="html"||(o=!1,te())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",A,!0),Z(),r.addEventListener("focus",h,!0),r.addEventListener("blur",w,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var zr=gr((kt,Vr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof kt=="object"&&typeof Vr=="object"?Vr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof kt=="object"?kt.ClipboardJS=r():t.ClipboardJS=r()})(kt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Li}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(D){try{return document.execCommand(D)}catch(M){return!1}}var h=function(M){var O=f()(M);return u("cut"),O},w=h;function A(D){var M=document.documentElement.getAttribute("dir")==="rtl",O=document.createElement("textarea");O.style.fontSize="12pt",O.style.border="0",O.style.padding="0",O.style.margin="0",O.style.position="absolute",O.style[M?"right":"left"]="-9999px";var I=window.pageYOffset||document.documentElement.scrollTop;return O.style.top="".concat(I,"px"),O.setAttribute("readonly",""),O.value=D,O}var Z=function(M,O){var I=A(M);O.container.appendChild(I);var W=f()(I);return u("copy"),I.remove(),W},te=function(M){var O=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},I="";return typeof M=="string"?I=Z(M,O):M instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(M==null?void 0:M.type)?I=Z(M.value,O):(I=f()(M),u("copy")),I},J=te;function C(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?C=function(O){return typeof O}:C=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},C(D)}var ct=function(){var M=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},O=M.action,I=O===void 0?"copy":O,W=M.container,K=M.target,Ce=M.text;if(I!=="copy"&&I!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(K!==void 0)if(K&&C(K)==="object"&&K.nodeType===1){if(I==="copy"&&K.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(I==="cut"&&(K.hasAttribute("readonly")||K.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ce)return J(Ce,{container:W});if(K)return I==="cut"?w(K):J(K,{container:W})},Ne=ct;function Pe(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Pe=function(O){return typeof O}:Pe=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},Pe(D)}function xi(D,M){if(!(D instanceof M))throw new TypeError("Cannot call a class as a function")}function Xr(D,M){for(var O=0;O0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof W.action=="function"?W.action:this.defaultAction,this.target=typeof W.target=="function"?W.target:this.defaultTarget,this.text=typeof W.text=="function"?W.text:this.defaultText,this.container=Pe(W.container)==="object"?W.container:document.body}},{key:"listenClick",value:function(W){var K=this;this.listener=p()(W,"click",function(Ce){return K.onClick(Ce)})}},{key:"onClick",value:function(W){var K=W.delegateTarget||W.currentTarget,Ce=this.action(K)||"copy",It=Ne({action:Ce,container:this.container,target:this.target(K),text:this.text(K)});this.emit(It?"success":"error",{action:Ce,text:It,trigger:K,clearSelection:function(){K&&K.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(W){return hr("action",W)}},{key:"defaultTarget",value:function(W){var K=hr("target",W);if(K)return document.querySelector(K)}},{key:"defaultText",value:function(W){return hr("text",W)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(W){var K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(W,K)}},{key:"cut",value:function(W){return w(W)}},{key:"isSupported",value:function(){var W=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],K=typeof W=="string"?[W]:W,Ce=!!document.queryCommandSupported;return K.forEach(function(It){Ce=Ce&&!!document.queryCommandSupported(It)}),Ce}}]),O}(a()),Li=Mi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,h,w){var A=p.apply(this,arguments);return l.addEventListener(u,A,w),{destroy:function(){l.removeEventListener(u,A,w)}}}function c(l,f,u,h,w){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(A){return a(A,f,u,h,w)}))}function p(l,f,u,h){return function(w){w.delegateTarget=s(w.target,f),w.delegateTarget&&h.call(l,w)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,h,w){if(!u&&!h&&!w)throw new Error("Missing required arguments");if(!s.string(h))throw new TypeError("Second argument must be a String");if(!s.fn(w))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,h,w);if(s.nodeList(u))return l(u,h,w);if(s.string(u))return f(u,h,w);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,h,w){return u.addEventListener(h,w),{destroy:function(){u.removeEventListener(h,w)}}}function l(u,h,w){return Array.prototype.forEach.call(u,function(A){A.addEventListener(h,w)}),{destroy:function(){Array.prototype.forEach.call(u,function(A){A.removeEventListener(h,w)})}}}function f(u,h,w){return a(document.body,u,h,w)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Va=/["'&<>]/;qn.exports=za;function za(e){var t=""+e,r=Va.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function V(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function z(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,h)})})}function a(u,h){try{c(o[u](h))}catch(w){f(i[0][3],w)}}function c(u){u.value instanceof ot?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,h){u(h),i.shift(),i.length&&a(i[0][0],i[0][1])}}function so(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof ue=="function"?ue(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function k(e){return typeof e=="function"}function pt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Wt=pt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=ue(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(A){t={error:A}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(k(l))try{l()}catch(A){i=A instanceof Wt?A.errors:[A]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=ue(f),h=u.next();!h.done;h=u.next()){var w=h.value;try{co(w)}catch(A){i=i!=null?i:[],A instanceof Wt?i=z(z([],V(i)),V(A.errors)):i.push(A)}}}catch(A){o={error:A}}finally{try{h&&!h.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Wt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)co(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Er=Ie.EMPTY;function Dt(e){return e instanceof Ie||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function co(e){k(e)?e():e.unsubscribe()}var ke={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var lt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?Er:(this.currentObservers=null,a.push(r),new Ie(function(){o.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new vo(r,o)},t}(j);var vo=function(e){se(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Er},t}(v);var St={now:function(){return(St.delegate||Date).now()},delegate:void 0};var Ot=function(e){se(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=St);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(ut.cancelAnimationFrame(o),r._scheduled=void 0)},t}(zt);var yo=function(e){se(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(qt);var de=new yo(xo);var L=new j(function(e){return e.complete()});function Kt(e){return e&&k(e.schedule)}function _r(e){return e[e.length-1]}function Je(e){return k(_r(e))?e.pop():void 0}function Ae(e){return Kt(_r(e))?e.pop():void 0}function Qt(e,t){return typeof _r(e)=="number"?e.pop():t}var dt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Yt(e){return k(e==null?void 0:e.then)}function Bt(e){return k(e[ft])}function Gt(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function Jt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Di(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Xt=Di();function Zt(e){return k(e==null?void 0:e[Xt])}function er(e){return ao(this,arguments,function(){var r,o,n,i;return Ut(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ot(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ot(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ot(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function tr(e){return k(e==null?void 0:e.getReader)}function N(e){if(e instanceof j)return e;if(e!=null){if(Bt(e))return Ni(e);if(dt(e))return Vi(e);if(Yt(e))return zi(e);if(Gt(e))return Eo(e);if(Zt(e))return qi(e);if(tr(e))return Ki(e)}throw Jt(e)}function Ni(e){return new j(function(t){var r=e[ft]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Vi(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?g(function(n,i){return e(n,i,o)}):ce,ye(1),r?Qe(t):jo(function(){return new or}))}}function $r(e){return e<=0?function(){return L}:x(function(t,r){var o=[];t.subscribe(S(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new v}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,h=0,w=!1,A=!1,Z=function(){f==null||f.unsubscribe(),f=void 0},te=function(){Z(),l=u=void 0,w=A=!1},J=function(){var C=l;te(),C==null||C.unsubscribe()};return x(function(C,ct){h++,!A&&!w&&Z();var Ne=u=u!=null?u:r();ct.add(function(){h--,h===0&&!A&&!w&&(f=Pr(J,c))}),Ne.subscribe(ct),!l&&h>0&&(l=new it({next:function(Pe){return Ne.next(Pe)},error:function(Pe){A=!0,Z(),f=Pr(te,n,Pe),Ne.error(Pe)},complete:function(){w=!0,Z(),f=Pr(te,s),Ne.complete()}}),N(C).subscribe(l))})(p)}}function Pr(e,t){for(var r=[],o=2;oe.next(document)),e}function R(e,t=document){return Array.from(t.querySelectorAll(e))}function P(e,t=document){let r=me(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function me(e,t=document){return t.querySelector(e)||void 0}function Re(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var la=T(d(document.body,"focusin"),d(document.body,"focusout")).pipe(be(1),q(void 0),m(()=>Re()||document.body),B(1));function vt(e){return la.pipe(m(t=>e.contains(t)),Y())}function Vo(e,t){return T(d(e,"mouseenter").pipe(m(()=>!0)),d(e,"mouseleave").pipe(m(()=>!1))).pipe(t?be(t):ce,q(!1))}function Ue(e){return{x:e.offsetLeft,y:e.offsetTop}}function zo(e){return T(d(window,"load"),d(window,"resize")).pipe(Me(0,de),m(()=>Ue(e)),q(Ue(e)))}function ir(e){return{x:e.scrollLeft,y:e.scrollTop}}function et(e){return T(d(e,"scroll"),d(window,"resize")).pipe(Me(0,de),m(()=>ir(e)),q(ir(e)))}function qo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)qo(e,r)}function E(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)qo(o,n);return o}function ar(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function gt(e){let t=E("script",{src:e});return H(()=>(document.head.appendChild(t),T(d(t,"load"),d(t,"error").pipe(b(()=>Ar(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),ye(1))))}var Ko=new v,ma=H(()=>typeof ResizeObserver=="undefined"?gt("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>{for(let t of e)Ko.next(t)})),b(e=>T(qe,$(e)).pipe(_(()=>e.disconnect()))),B(1));function pe(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Ee(e){return ma.pipe(y(t=>t.observe(e)),b(t=>Ko.pipe(g(({target:r})=>r===e),_(()=>t.unobserve(e)),m(()=>pe(e)))),q(pe(e)))}function xt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function sr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Qo=new v,fa=H(()=>$(new IntersectionObserver(e=>{for(let t of e)Qo.next(t)},{threshold:0}))).pipe(b(e=>T(qe,$(e)).pipe(_(()=>e.disconnect()))),B(1));function yt(e){return fa.pipe(y(t=>t.observe(e)),b(t=>Qo.pipe(g(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function Yo(e,t=16){return et(e).pipe(m(({y:r})=>{let o=pe(e),n=xt(e);return r>=n.height-o.height-t}),Y())}var cr={drawer:P("[data-md-toggle=drawer]"),search:P("[data-md-toggle=search]")};function Bo(e){return cr[e].checked}function Be(e,t){cr[e].checked!==t&&cr[e].click()}function We(e){let t=cr[e];return d(t,"change").pipe(m(()=>t.checked),q(t.checked))}function ua(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function da(){return T(d(window,"compositionstart").pipe(m(()=>!0)),d(window,"compositionend").pipe(m(()=>!1))).pipe(q(!1))}function Go(){let e=d(window,"keydown").pipe(g(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:Bo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),g(({mode:t,type:r})=>{if(t==="global"){let o=Re();if(typeof o!="undefined")return!ua(o,r)}return!0}),le());return da().pipe(b(t=>t?L:e))}function ve(){return new URL(location.href)}function st(e,t=!1){if(G("navigation.instant")&&!t){let r=E("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function Jo(){return new v}function Xo(){return location.hash.slice(1)}function Zo(e){let t=E("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ha(e){return T(d(window,"hashchange"),e).pipe(m(Xo),q(Xo()),g(t=>t.length>0),B(1))}function en(e){return ha(e).pipe(m(t=>me(`[id="${t}"]`)),g(t=>typeof t!="undefined"))}function At(e){let t=matchMedia(e);return nr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function tn(){let e=matchMedia("print");return T(d(window,"beforeprint").pipe(m(()=>!0)),d(window,"afterprint").pipe(m(()=>!1))).pipe(q(e.matches))}function Ur(e,t){return e.pipe(b(r=>r?t():L))}function Wr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function De(e,t){return Wr(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),B(1))}function rn(e,t){let r=new DOMParser;return Wr(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),B(1))}function on(e,t){let r=new DOMParser;return Wr(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),B(1))}function nn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function an(){return T(d(window,"scroll",{passive:!0}),d(window,"resize",{passive:!0})).pipe(m(nn),q(nn()))}function sn(){return{width:innerWidth,height:innerHeight}}function cn(){return d(window,"resize",{passive:!0}).pipe(m(sn),q(sn()))}function pn(){return Q([an(),cn()]).pipe(m(([e,t])=>({offset:e,size:t})),B(1))}function pr(e,{viewport$:t,header$:r}){let o=t.pipe(X("size")),n=Q([o,r]).pipe(m(()=>Ue(e)));return Q([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function ba(e){return d(e,"message",t=>t.data)}function va(e){let t=new v;return t.subscribe(r=>e.postMessage(r)),t}function ln(e,t=new Worker(e)){let r=ba(t),o=va(t),n=new v;n.subscribe(o);let i=o.pipe(ee(),oe(!0));return n.pipe(ee(),$e(r.pipe(U(i))),le())}var ga=P("#__config"),Et=JSON.parse(ga.textContent);Et.base=`${new URL(Et.base,ve())}`;function we(){return Et}function G(e){return Et.features.includes(e)}function ge(e,t){return typeof t!="undefined"?Et.translations[e].replace("#",t.toString()):Et.translations[e]}function Te(e,t=document){return P(`[data-md-component=${e}]`,t)}function ne(e,t=document){return R(`[data-md-component=${e}]`,t)}function xa(e){let t=P(".md-typeset > :first-child",e);return d(t,"click",{once:!0}).pipe(m(()=>P(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function mn(e){if(!G("announce.dismiss")||!e.childElementCount)return L;if(!e.hidden){let t=P(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return H(()=>{let t=new v;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),xa(e).pipe(y(r=>t.next(r)),_(()=>t.complete()),m(r=>F({ref:e},r)))})}function ya(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function fn(e,t){let r=new v;return r.subscribe(({hidden:o})=>{e.hidden=o}),ya(e,t).pipe(y(o=>r.next(o)),_(()=>r.complete()),m(o=>F({ref:e},o)))}function Ct(e,t){return t==="inline"?E("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},E("div",{class:"md-tooltip__inner md-typeset"})):E("div",{class:"md-tooltip",id:e,role:"tooltip"},E("div",{class:"md-tooltip__inner md-typeset"}))}function un(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return E("aside",{class:"md-annotation",tabIndex:0},Ct(t),E("a",{href:r,class:"md-annotation__index",tabIndex:-1},E("span",{"data-md-annotation-id":e})))}else return E("aside",{class:"md-annotation",tabIndex:0},Ct(t),E("span",{class:"md-annotation__index",tabIndex:-1},E("span",{"data-md-annotation-id":e})))}function dn(e){return E("button",{class:"md-clipboard md-icon",title:ge("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Dr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,E("del",null,p)," "],[]).slice(0,-1),i=we(),s=new URL(e.location,i.base);G("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=we();return E("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},E("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&E("div",{class:"md-search-result__icon md-icon"}),r>0&&E("h1",null,e.title),r<=0&&E("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return E("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&E("p",{class:"md-search-result__terms"},ge("search.result.term.missing"),": ",...n)))}function hn(e){let t=e[0].score,r=[...e],o=we(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scoreDr(l,1)),...c.length?[E("details",{class:"md-search-result__more"},E("summary",{tabIndex:-1},E("div",null,c.length>0&&c.length===1?ge("search.result.more.one"):ge("search.result.more.other",c.length))),...c.map(l=>Dr(l,1)))]:[]];return E("li",{class:"md-search-result__item"},p)}function bn(e){return E("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>E("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ar(r):r)))}function Nr(e){let t=`tabbed-control tabbed-control--${e}`;return E("div",{class:t,hidden:!0},E("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function vn(e){return E("div",{class:"md-typeset__scrollwrap"},E("div",{class:"md-typeset__table"},e))}function Ea(e){let t=we(),r=new URL(`../${e.version}/`,t.base);return E("li",{class:"md-version__item"},E("a",{href:`${r}`,class:"md-version__link"},e.title))}function gn(e,t){return e=e.filter(r=>{var o;return!((o=r.properties)!=null&&o.hidden)}),E("div",{class:"md-version"},E("button",{class:"md-version__current","aria-label":ge("select.version")},t.title),E("ul",{class:"md-version__list"},e.map(Ea)))}var wa=0;function Ta(e,t){document.body.append(e);let{width:r}=pe(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=sr(t),n=typeof o!="undefined"?et(o):$({x:0,y:0}),i=T(vt(t),Vo(t)).pipe(Y());return Q([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Ue(t),l=pe(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function Ge(e){let t=e.title;if(!t.length)return L;let r=`__tooltip_${wa++}`,o=Ct(r,"inline"),n=P(".md-typeset",o);return n.innerHTML=t,H(()=>{let i=new v;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),T(i.pipe(g(({active:s})=>s)),i.pipe(be(250),g(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,de)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(_t(125,de),g(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ta(o,e).pipe(y(s=>i.next(s)),_(()=>i.complete()),m(s=>F({ref:e},s)))}).pipe(ze(ie))}function Sa(e,t){let r=H(()=>Q([zo(e),et(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=pe(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return vt(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),ye(+!o||1/0))))}function xn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return H(()=>{let i=new v,s=i.pipe(ee(),oe(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),yt(e).pipe(U(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),T(i.pipe(g(({active:a})=>a)),i.pipe(be(250),g(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,de)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(_t(125,de),g(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),d(n,"click").pipe(U(s),g(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),d(n,"mousedown").pipe(U(s),ae(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Re())==null||p.blur()}}),r.pipe(U(s),g(a=>a===o),Ye(125)).subscribe(()=>e.focus()),Sa(e,t).pipe(y(a=>i.next(a)),_(()=>i.complete()),m(a=>F({ref:e},a)))})}function Oa(e){return e.tagName==="CODE"?R(".c, .c1, .cm",e):[e]}function Ma(e){let t=[];for(let r of Oa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function yn(e,t){t.append(...Array.from(e.childNodes))}function lr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ma(t)){let[,c]=a.textContent.match(/\((\d+)\)/);me(`:scope > li:nth-child(${c})`,e)&&(s.set(c,un(c,i)),a.replaceWith(s.get(c)))}return s.size===0?L:H(()=>{let a=new v,c=a.pipe(ee(),oe(!0)),p=[];for(let[l,f]of s)p.push([P(".md-typeset",f),P(`:scope > li:nth-child(${l})`,e)]);return o.pipe(U(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?yn(f,u):yn(u,f)}),T(...[...s].map(([,l])=>xn(l,t,{target$:r}))).pipe(_(()=>a.complete()),le())})}function En(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return En(t)}}function wn(e,t){return H(()=>{let r=En(e);return typeof r!="undefined"?lr(r,e,t):L})}var Tn=jt(zr());var La=0;function Sn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Sn(t)}}function _a(e){return Ee(e).pipe(m(({width:t})=>({scrollable:xt(e).width>t})),X("scrollable"))}function On(e,t){let{matches:r}=matchMedia("(hover)"),o=H(()=>{let n=new v,i=n.pipe($r(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[];if(Tn.default.isSupported()&&(e.closest(".copy")||G("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${La++}`;let p=dn(c.id);c.insertBefore(p,e),G("content.tooltips")&&s.push(Ge(p))}let a=e.closest(".highlight");if(a instanceof HTMLElement){let c=Sn(a);if(typeof c!="undefined"&&(a.classList.contains("annotate")||G("content.code.annotate"))){let p=lr(c,e,t);s.push(Ee(a).pipe(U(i),m(({width:l,height:f})=>l&&f),Y(),b(l=>l?p:L)))}}return _a(e).pipe(y(c=>n.next(c)),_(()=>n.complete()),m(c=>F({ref:e},c)),$e(...s))});return G("content.lazy")?yt(e).pipe(g(n=>n),ye(1),b(()=>o)):o}function Aa(e,{target$:t,print$:r}){let o=!0;return T(t.pipe(m(n=>n.closest("details:not([open])")),g(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(g(n=>n||!o),y(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Mn(e,t){return H(()=>{let r=new v;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Aa(e,t).pipe(y(o=>r.next(o)),_(()=>r.complete()),m(o=>F({ref:e},o)))})}var Ln=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var qr,ka=0;function Ha(){return typeof mermaid=="undefined"||mermaid instanceof Element?gt("https://unpkg.com/mermaid@10.7.0/dist/mermaid.min.js"):$(void 0)}function _n(e){return e.classList.remove("mermaid"),qr||(qr=Ha().pipe(y(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Ln,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),B(1))),qr.subscribe(()=>ro(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${ka++}`,r=E("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),qr.pipe(m(()=>({ref:e})))}var An=E("table");function Cn(e){return e.replaceWith(An),An.replaceWith(vn(e)),$({ref:e})}function $a(e){let t=e.find(r=>r.checked)||e[0];return T(...e.map(r=>d(r,"change").pipe(m(()=>P(`label[for="${r.id}"]`))))).pipe(q(P(`label[for="${t.id}"]`)),m(r=>({active:r})))}function kn(e,{viewport$:t,target$:r}){let o=P(".tabbed-labels",e),n=R(":scope > input",e),i=Nr("prev");e.append(i);let s=Nr("next");return e.append(s),H(()=>{let a=new v,c=a.pipe(ee(),oe(!0));Q([a,Ee(e)]).pipe(U(c),Me(1,de)).subscribe({next([{active:p},l]){let f=Ue(p),{width:u}=pe(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let h=ir(o);(f.xh.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),Q([et(o),Ee(o)]).pipe(U(c)).subscribe(([p,l])=>{let f=xt(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),T(d(i,"click").pipe(m(()=>-1)),d(s,"click").pipe(m(()=>1))).pipe(U(c)).subscribe(p=>{let{width:l}=pe(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(U(c),g(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=P(`label[for="${p.id}"]`);l.replaceChildren(E("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),d(l.firstElementChild,"click").pipe(U(c),g(f=>!(f.metaKey||f.ctrlKey)),y(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return G("content.tabs.link")&&a.pipe(Le(1),ae(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let w of R("[data-tabs]"))for(let A of R(":scope > input",w)){let Z=P(`label[for="${A.id}"]`);if(Z!==p&&Z.innerText.trim()===f){Z.setAttribute("data-md-switching",""),A.click();break}}window.scrollTo({top:e.offsetTop-u});let h=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...h])])}}),a.pipe(U(c)).subscribe(()=>{for(let p of R("audio, video",e))p.pause()}),$a(n).pipe(y(p=>a.next(p)),_(()=>a.complete()),m(p=>F({ref:e},p)))}).pipe(ze(ie))}function Hn(e,{viewport$:t,target$:r,print$:o}){return T(...R(".annotate:not(.highlight)",e).map(n=>wn(n,{target$:r,print$:o})),...R("pre:not(.mermaid) > code",e).map(n=>On(n,{target$:r,print$:o})),...R("pre.mermaid",e).map(n=>_n(n)),...R("table:not([class])",e).map(n=>Cn(n)),...R("details",e).map(n=>Mn(n,{target$:r,print$:o})),...R("[data-tabs]",e).map(n=>kn(n,{viewport$:t,target$:r})),...R("[title]",e).filter(()=>G("content.tooltips")).map(n=>Ge(n)))}function Ra(e,{alert$:t}){return t.pipe(b(r=>T($(!0),$(!1).pipe(Ye(2e3))).pipe(m(o=>({message:r,active:o})))))}function $n(e,t){let r=P(".md-typeset",e);return H(()=>{let o=new v;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ra(e,t).pipe(y(n=>o.next(n)),_(()=>o.complete()),m(n=>F({ref:e},n)))})}function Pa({viewport$:e}){if(!G("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Ke(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=We("search");return Q([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:$(!1)),q(!1))}function Rn(e,t){return H(()=>Q([Ee(e),Pa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),B(1))}function Pn(e,{header$:t,main$:r}){return H(()=>{let o=new v,n=o.pipe(ee(),oe(!0));o.pipe(X("active"),je(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(R("[title]",e)).pipe(g(()=>G("content.tooltips")),re(s=>Ge(s)));return r.subscribe(o),t.pipe(U(n),m(s=>F({ref:e},s)),$e(i.pipe(U(n))))})}function Ia(e,{viewport$:t,header$:r}){return pr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=pe(e);return{active:o>=n}}),X("active"))}function In(e,t){return H(()=>{let r=new v;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=me(".md-content h1");return typeof o=="undefined"?L:Ia(o,t).pipe(y(n=>r.next(n)),_(()=>r.complete()),m(n=>F({ref:e},n)))})}function Fn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Ee(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),X("bottom"))));return Q([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function Fa(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(re(o=>d(o,"change").pipe(m(()=>o))),q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),B(1))}function jn(e){let t=R("input",e),r=E("meta",{name:"theme-color"});document.head.appendChild(r);let o=E("meta",{name:"color-scheme"});document.head.appendChild(o);let n=At("(prefers-color-scheme: light)");return H(()=>{let i=new v;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;a{let s=Te("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(Oe(ie)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Fa(t).pipe(U(n.pipe(Le(1))),at(),y(s=>i.next(s)),_(()=>i.complete()),m(s=>F({ref:e},s)))})}function Un(e,{progress$:t}){return H(()=>{let r=new v;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(y(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Kr=jt(zr());function ja(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Wn({alert$:e}){Kr.default.isSupported()&&new j(t=>{new Kr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ja(P(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(y(t=>{t.trigger.focus()}),m(()=>ge("clipboard.copied"))).subscribe(e)}function Dn(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function Ua(e,t){let r=new Map;for(let o of R("url",e)){let n=P("loc",o),i=[Dn(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of R("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(Dn(new URL(a),t))}}return r}function mr(e){return on(new URL("sitemap.xml",e)).pipe(m(t=>Ua(t,new URL(e))),he(()=>$(new Map)))}function Wa(e,t){if(!(e.target instanceof Element))return L;let r=e.target.closest("a");if(r===null)return L;if(r.target||e.metaKey||e.ctrlKey)return L;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(new URL(r.href))):L}function Nn(e){let t=new Map;for(let r of R(":scope > *",e.head))t.set(r.outerHTML,r);return t}function Vn(e){for(let t of R("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function Da(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...G("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=me(o),i=me(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=Nn(document);for(let[o,n]of Nn(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Te("container");return Fe(R("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),L}),ee(),oe(document))}function zn({location$:e,viewport$:t,progress$:r}){let o=we();if(location.protocol==="file:")return L;let n=mr(o.base);$(document).subscribe(Vn);let i=d(document.body,"click").pipe(je(n),b(([c,p])=>Wa(c,p)),le()),s=d(window,"popstate").pipe(m(ve),le());i.pipe(ae(t)).subscribe(([c,{offset:p}])=>{history.replaceState(p,""),history.pushState(null,"",c)}),T(i,s).subscribe(e);let a=e.pipe(X("pathname"),b(c=>rn(c,{progress$:r}).pipe(he(()=>(st(c,!0),L)))),b(Vn),b(Da),le());return T(a.pipe(ae(e,(c,p)=>p)),e.pipe(X("pathname"),b(()=>e),X("hash")),e.pipe(Y((c,p)=>c.pathname===p.pathname&&c.hash===p.hash),b(()=>i),y(()=>history.back()))).subscribe(c=>{var p,l;history.state!==null||!c.hash?window.scrollTo(0,(l=(p=history.state)==null?void 0:p.y)!=null?l:0):(history.scrollRestoration="auto",Zo(c.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),d(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(X("offset"),be(100)).subscribe(({offset:c})=>{history.replaceState(c,"")}),a}var Qn=jt(Kn());function Yn(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,Qn.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Ht(e){return e.type===1}function fr(e){return e.type===3}function Bn(e,t){let r=ln(e);return T($(location.protocol!=="file:"),We("search")).pipe(He(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:G("search.suggest")}}})),r}function Gn({document$:e}){let t=we(),r=De(new URL("../versions.json",t.base)).pipe(he(()=>L)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>d(document.body,"click").pipe(g(i=>!i.metaKey&&!i.ctrlKey),ae(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?L:(i.preventDefault(),$(c))}}return L}),b(i=>{let{version:s}=n.get(i);return mr(new URL(i)).pipe(m(a=>{let p=ve().href.replace(t.base,"");return a.has(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>st(n,!0)),Q([r,o]).subscribe(([n,i])=>{P(".md-header__topic").appendChild(gn(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of ne("outdated"))a.hidden=!1})}function Ka(e,{worker$:t}){let{searchParams:r}=ve();r.has("q")&&(Be("search",!0),e.value=r.get("q"),e.focus(),We("search").pipe(He(i=>!i)).subscribe(()=>{let i=ve();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=vt(e),n=T(t.pipe(He(Ht)),d(e,"keyup"),o).pipe(m(()=>e.value),Y());return Q([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),B(1))}function Jn(e,{worker$:t}){let r=new v,o=r.pipe(ee(),oe(!0));Q([t.pipe(He(Ht)),r],(i,s)=>s).pipe(X("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(X("focus")).subscribe(({focus:i})=>{i&&Be("search",i)}),d(e.form,"reset").pipe(U(o)).subscribe(()=>e.focus());let n=P("header [for=__search]");return d(n,"click").subscribe(()=>e.focus()),Ka(e,{worker$:t}).pipe(y(i=>r.next(i)),_(()=>r.complete()),m(i=>F({ref:e},i)),B(1))}function Xn(e,{worker$:t,query$:r}){let o=new v,n=Yo(e.parentElement).pipe(g(Boolean)),i=e.parentElement,s=P(":scope > :first-child",e),a=P(":scope > :last-child",e);We("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(ae(r),Ir(t.pipe(He(Ht)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?ge("search.result.none"):ge("search.result.placeholder");break;case 1:s.textContent=ge("search.result.one");break;default:let u=ar(l.length);s.textContent=ge("search.result.other",u)}});let c=o.pipe(y(()=>a.innerHTML=""),b(({items:l})=>T($(...l.slice(0,10)),$(...l.slice(10)).pipe(Ke(4),jr(n),b(([f])=>f)))),m(hn),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(re(l=>{let f=me("details",l);return typeof f=="undefined"?L:d(f,"toggle").pipe(U(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(g(fr),m(({data:l})=>l)).pipe(y(l=>o.next(l)),_(()=>o.complete()),m(l=>F({ref:e},l)))}function Qa(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ve();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Zn(e,t){let r=new v,o=r.pipe(ee(),oe(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),d(e,"click").pipe(U(o)).subscribe(n=>n.preventDefault()),Qa(e,t).pipe(y(n=>r.next(n)),_(()=>r.complete()),m(n=>F({ref:e},n)))}function ei(e,{worker$:t,keyboard$:r}){let o=new v,n=Te("search-query"),i=T(d(n,"keydown"),d(n,"focus")).pipe(Oe(ie),m(()=>n.value),Y());return o.pipe(je(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(g(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(g(fr),m(({data:a})=>a)).pipe(y(a=>o.next(a)),_(()=>o.complete()),m(()=>({ref:e})))}function ti(e,{index$:t,keyboard$:r}){let o=we();try{let n=Bn(o.search,t),i=Te("search-query",e),s=Te("search-result",e);d(e,"click").pipe(g(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>Be("search",!1)),r.pipe(g(({mode:c})=>c==="search")).subscribe(c=>{let p=Re();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of R(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,h])=>h-u);f.click()}c.claim()}break;case"Escape":case"Tab":Be("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...R(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Re()&&i.focus()}}),r.pipe(g(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Jn(i,{worker$:n});return T(a,Xn(s,{worker$:n,query$:a})).pipe($e(...ne("search-share",e).map(c=>Zn(c,{query$:a})),...ne("search-suggest",e).map(c=>ei(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,qe}}function ri(e,{index$:t,location$:r}){return Q([t,r.pipe(q(ve()),g(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>Yn(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=E("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function Ya(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return Q([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function Qr(e,o){var n=o,{header$:t}=n,r=to(n,["header$"]);let i=P(".md-sidebar__scrollwrap",e),{y:s}=Ue(i);return H(()=>{let a=new v,c=a.pipe(ee(),oe(!0)),p=a.pipe(Me(0,de));return p.pipe(ae(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(He()).subscribe(()=>{for(let l of R(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:h}=pe(f);f.scrollTo({top:u-h/2})}}}),fe(R("label[tabindex]",e)).pipe(re(l=>d(l,"click").pipe(Oe(ie),m(()=>l),U(c)))).subscribe(l=>{let f=P(`[id="${l.htmlFor}"]`);P(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),Ya(e,r).pipe(y(l=>a.next(l)),_(()=>a.complete()),m(l=>F({ref:e},l)))})}function oi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Lt(De(`${r}/releases/latest`).pipe(he(()=>L),m(o=>({version:o.tag_name})),Qe({})),De(r).pipe(he(()=>L),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Qe({}))).pipe(m(([o,n])=>F(F({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return De(r).pipe(m(o=>({repositories:o.public_repos})),Qe({}))}}function ni(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return De(r).pipe(he(()=>L),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Qe({}))}function ii(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return oi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return ni(r,o)}return L}var Ba;function Ga(e){return Ba||(Ba=H(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(ne("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return L}return ii(e.href).pipe(y(o=>__md_set("__source",o,sessionStorage)))}).pipe(he(()=>L),g(t=>Object.keys(t).length>0),m(t=>({facts:t})),B(1)))}function ai(e){let t=P(":scope > :last-child",e);return H(()=>{let r=new v;return r.subscribe(({facts:o})=>{t.appendChild(bn(o)),t.classList.add("md-source__repository--active")}),Ga(e).pipe(y(o=>r.next(o)),_(()=>r.complete()),m(o=>F({ref:e},o)))})}function Ja(e,{viewport$:t,header$:r}){return Ee(document.body).pipe(b(()=>pr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),X("hidden"))}function si(e,t){return H(()=>{let r=new v;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(G("navigation.tabs.sticky")?$({hidden:!1}):Ja(e,t)).pipe(y(o=>r.next(o)),_(()=>r.complete()),m(o=>F({ref:e},o)))})}function Xa(e,{viewport$:t,header$:r}){let o=new Map,n=R(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=me(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(X("height"),m(({height:a})=>{let c=Te("main"),p=P(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Ee(document.body).pipe(X("height"),b(a=>H(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let h=f.offsetParent;for(;h;h=h.offsetParent)u+=h.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),je(i),b(([c,p])=>t.pipe(Rr(([l,f],{offset:{y:u},size:h})=>{let w=u+h.height>=Math.floor(a.height);for(;f.length;){let[,A]=f[0];if(A-p=u&&!w)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),q({prev:[],next:[]}),Ke(2,1),m(([a,c])=>a.prev.length{let i=new v,s=i.pipe(ee(),oe(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),G("toc.follow")){let a=T(t.pipe(be(1),m(()=>{})),t.pipe(be(250),m(()=>"smooth")));i.pipe(g(({prev:c})=>c.length>0),je(o.pipe(Oe(ie))),ae(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=sr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:h}=pe(f);f.scrollTo({top:u-h/2,behavior:p})}}})}return G("navigation.tracking")&&t.pipe(U(s),X("offset"),be(250),Le(1),U(n.pipe(Le(1))),at({delay:250}),ae(i)).subscribe(([,{prev:a}])=>{let c=ve(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Xa(e,{viewport$:t,header$:r}).pipe(y(a=>i.next(a)),_(()=>i.complete()),m(a=>F({ref:e},a)))})}function Za(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),Ke(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return Q([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),U(o.pipe(Le(1))),oe(!0),at({delay:250}),m(s=>({hidden:s})))}function pi(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new v,s=i.pipe(ee(),oe(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(U(s),X("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),d(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Za(e,{viewport$:t,main$:o,target$:n}).pipe(y(a=>i.next(a)),_(()=>i.complete()),m(a=>F({ref:e},a)))}function li({document$:e}){e.pipe(b(()=>R(".md-ellipsis")),re(t=>yt(t).pipe(U(e.pipe(Le(1))),g(r=>r),m(()=>t),ye(1))),g(t=>t.offsetWidth{let r=t.innerText,o=t.closest("a")||t;return o.title=r,Ge(o).pipe(U(e.pipe(Le(1))),_(()=>o.removeAttribute("title")))})).subscribe(),e.pipe(b(()=>R(".md-status")),re(t=>Ge(t))).subscribe()}function mi({document$:e,tablet$:t}){e.pipe(b(()=>R(".md-toggle--indeterminate")),y(r=>{r.indeterminate=!0,r.checked=!1}),re(r=>d(r,"change").pipe(Fr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ae(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function es(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function fi({document$:e}){e.pipe(b(()=>R("[data-md-scrollfix]")),y(t=>t.removeAttribute("data-md-scrollfix")),g(es),re(t=>d(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function ui({viewport$:e,tablet$:t}){Q([We("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(Ye(r?400:100))),ae(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ts(){return location.protocol==="file:"?gt(`${new URL("search/search_index.js",Yr.base)}`).pipe(m(()=>__index),B(1)):De(new URL("search/search_index.json",Yr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var rt=No(),Rt=Jo(),wt=en(Rt),Br=Go(),_e=pn(),ur=At("(min-width: 960px)"),hi=At("(min-width: 1220px)"),bi=tn(),Yr=we(),vi=document.forms.namedItem("search")?ts():qe,Gr=new v;Wn({alert$:Gr});var Jr=new v;G("navigation.instant")&&zn({location$:Rt,viewport$:_e,progress$:Jr}).subscribe(rt);var di;((di=Yr.version)==null?void 0:di.provider)==="mike"&&Gn({document$:rt});T(Rt,wt).pipe(Ye(125)).subscribe(()=>{Be("drawer",!1),Be("search",!1)});Br.pipe(g(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=me("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=me("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Re();o instanceof HTMLLabelElement&&o.click()}});li({document$:rt});mi({document$:rt,tablet$:ur});fi({document$:rt});ui({viewport$:_e,tablet$:ur});var tt=Rn(Te("header"),{viewport$:_e}),$t=rt.pipe(m(()=>Te("main")),b(e=>Fn(e,{viewport$:_e,header$:tt})),B(1)),rs=T(...ne("consent").map(e=>fn(e,{target$:wt})),...ne("dialog").map(e=>$n(e,{alert$:Gr})),...ne("header").map(e=>Pn(e,{viewport$:_e,header$:tt,main$:$t})),...ne("palette").map(e=>jn(e)),...ne("progress").map(e=>Un(e,{progress$:Jr})),...ne("search").map(e=>ti(e,{index$:vi,keyboard$:Br})),...ne("source").map(e=>ai(e))),os=H(()=>T(...ne("announce").map(e=>mn(e)),...ne("content").map(e=>Hn(e,{viewport$:_e,target$:wt,print$:bi})),...ne("content").map(e=>G("search.highlight")?ri(e,{index$:vi,location$:Rt}):L),...ne("header-title").map(e=>In(e,{viewport$:_e,header$:tt})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Ur(hi,()=>Qr(e,{viewport$:_e,header$:tt,main$:$t})):Ur(ur,()=>Qr(e,{viewport$:_e,header$:tt,main$:$t}))),...ne("tabs").map(e=>si(e,{viewport$:_e,header$:tt})),...ne("toc").map(e=>ci(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})),...ne("top").map(e=>pi(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})))),gi=rt.pipe(b(()=>os),$e(rs),B(1));gi.subscribe();window.document$=rt;window.location$=Rt;window.target$=wt;window.keyboard$=Br;window.viewport$=_e;window.tablet$=ur;window.screen$=hi;window.print$=bi;window.alert$=Gr;window.progress$=Jr;window.component$=gi;})(); +//# sourceMappingURL=bundle.bd41221c.min.js.map + diff --git a/assets/javascripts/bundle.bd41221c.min.js.map b/assets/javascripts/bundle.bd41221c.min.js.map new file mode 100644 index 0000000..1663dab --- /dev/null +++ b/assets/javascripts/bundle.bd41221c.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2024 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an + + + + + \ No newline at end of file diff --git a/core/architecture/contracts/inbound_state_sender/index.html b/core/architecture/contracts/inbound_state_sender/index.html new file mode 100644 index 0000000..b59b73f --- /dev/null +++ b/core/architecture/contracts/inbound_state_sender/index.html @@ -0,0 +1,3530 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Inbound State Sender - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Inbound State Sender

+ +

The Inbound State Sender Contract

+

The Inbound State Sender Contract is a specialized smart contract. +Its primary function is to assist developers of decentralized applications +(dApps) in transmitting state updates from the source chain to the Dojima Chain. +This contract operates on the source chain, +enabling transactions to be carried out from the source chain to the Dojima Chain.

+

To utilize the State Sender Contract, follow these straightforward steps:

+

Step 1: Copy the Inbound State Sender Contract interface from GitHub

+
    +
  • Get the Inbound State Sender Contract Interface from the GitHub repository here.
  • +
  • Copy the contract interface into its corresponding folder, typically located in, ’. /interfaces/’ or as per your project structure.
  • +
+

Step 2: Obtain the Inbound State Sender Contract Address

+
    +
  • Retrieve the Inbound State Sender Contract address from the Dojima Chain Explorer.
  • +
+

⚠️ Warning: The Inbound State Sender Contract address may vary for different chains. Ensure that you select the appropriate chain i.e. (Ethereum, Avalanche) and the appropriate network i.e. (mainnet or testnet).

+

Step 3: Register the Destination Contract

+

Before you can send state transaction to the Dojima Chain, you need to register the destination contract. This is done using the register function in the State Sender Contract. This function takes two parameters:

+
    +
  • sender: This is the address of the contract that is sending the state update. In most cases, this will be the address of your contract.
  • +
  • receiver: This is the address of the contract that will receive the state update. This is what we call the destination contract.
  • +
+
+
+

Warning

+

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer. These steps will be added later.

+
+

Step 4: Call the transferPayload function

+
    +
  • +

    After registering the destination contract, you can now send state updates to it. This is done using the transferPayload function in the State Sender Contract. This function takes two parameters:

    +
  • +
  • +

    destinationContract: This is the address of the contract that will receive the state update. This is what we call the destination contract.

    +
  • +
  • payload: This is the ABI-encoded contract call that you want to send to the destination contract.
  • +
+
+
+

Warning

+

DISCLAIMER:Below provided code example is for educational purposes only. It is not intended for use in a production environment or with real assets. Please exercise caution and ensure proper testing and validation of your code before deploying it in a production environment.

+
+
// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.19;
+
+// Import the interface from the GitHub repository
+import { IInboundStateSender } from './interfaces/IInboundStateSender.sol';
+import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract App {
+    // Declare a variable to hold the address of the StateSender contract
+    address public stateSender;
+    uint256 public maxErc20Amount = 100 * (10**18);
+    IInboundStateSender public stateSender;
+    // Destination chain contract address (Polygon, Avalanche, etc.)
+    address public destinationContract;
+
+    constructor(address _stateSender, address _destContract) {
+        // Create an instance of the IStateSender interface using the StateSender address
+        stateSender = IInboundStateSender(_stateSender);
+        require(_destContract != address(0), "Invalid destination contract address");
+        destinationContract = _destContract;
+    }
+
+    function depositERC20(
+        address _token,
+        uint256 _amount
+    ) public {
+        require(_amount <= maxErc20Amount, "exceed maximum deposit amount");
+        require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "TOKEN_TRANSFER_FAILED");
+
+        // Call the transferPayload function
+        stateSender.transferPayload(
+          destinationContract, abi.encode(msg.sender, _token, _amount)
+        );
+    }
+}
+
+

Step 5: Event emitted by the State Sender Contract TokenTransferWithPayload

+
    +
  • Once the State Sender Contract executes the transferPayload function, it emits an event called DataTransfer. This event plays a vital role in the interaction with Narada.
  • +
  • The DataTransfer event furnishes essential information in its parameters:
  • +
  • depositID - This identifier uniquely identifies deposits on the Dojima chain. It is relevant only when the destinationChain is Dojima.
  • +
  • destinationContract - It signifies the target contract to which the tokens and payload are delivered.
  • +
  • payload - This field holds the ABI-encoded contract call that was transmitted.
  • +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/architecture/contracts/outbound_state_sender/index.html b/core/architecture/contracts/outbound_state_sender/index.html new file mode 100644 index 0000000..4fb5a64 --- /dev/null +++ b/core/architecture/contracts/outbound_state_sender/index.html @@ -0,0 +1,3610 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Outbound State Sender - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Outbound State Sender

+ +

The Outbound State Sender Contract

+

The Outbound State Sender Contract is a specialized smart contract. +Its primary function is to assist developers of decentralized applications (dApps) in transmitting state updates and
+asset transfer from the Dojima Chain to the destination chain. +This contract operates on the dojima chain, +enabling transactions to be carried out from the Dojima Chain to the destination chain.

+

To utilize the State Sender Contract, follow these straightforward steps:

+

Step 1: Copy the Inbound State Sender Contract interface from GitHub

+
    +
  • Get the Outbound State Sender Contract Interface from the GitHub repository here.
  • +
  • Copy the contract interface into its corresponding folder, typically located in, ’. /interfaces/’ or as per your project structure.
  • +
+

Step 2: Obtain the Outbound State Sender Contract Address

+
    +
  • Retrieve the Outbound State Sender Contract address from the Dojima Chain Explorer.
  • +
+

Step 3: Register the Destination Contract, Destination Asset and Destination Chain

+

Before you can send a state transaction or asset transaction to the destination chain, +you need to make sure that everything is registered.

+
    +
  • To use transferPayload function, you need to make sure that the following things are registered:
  • +
  • Destination Contract: This is the address of the contract that will receive the state update.
  • +
  • Destination Chain: This is the name chain that will receive the state update.
  • +
  • Steps to register destination address and chain:
  • +
+
+

Warning

+

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer.

+
+
    +
  • To use transferAsset function, you need to make sure that the following things are registered:
  • +
  • Destination Address: This is the address of the user that will receive the transferred asset.
  • +
  • Destination Asset: This is the address of the asset that will be transferred to the destination chain.
  • +
  • Destination Chain: This is the name chain that will receive the asset update.
  • +
  • Steps to register destination address, asset and chain:
  • +
+
+

Warning

+

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer. These steps will be added later.

+
+

Step 4: Calling the functions to transfer payload and asset

+
    +
  • Once you have registered all the details, you can now send state updates or transfer asset to the destination chain. This is done using the transferPayload and transferAsset functions in the Outbound State Sender Contract.
  • +
  • Fees for both function calls will be deducted from the caller’s (in this case contract) account in the form of Dojima tokens. The caller needs to make sure that they have enough Dojima tokens in their account to pay the fees.
  • +
  • Transfer Payload function takes four parameters:
  • +
  • Destination Chain: This is the name of the destination chain in bytes32 format, that will receive the state update.
  • +
  • Destination Contract: This is the address of the contract in bytes format, that will receive the state update on a destination chain.
  • +
  • Refund Address : This is the address of the user in ETH address format that will receive the refund if the transaction fails.
  • +
  • +

    Payload: This is the abi encoded contract call that in bytes format you want to send to the destination contract.

    +
      +
    • Note: The payload should be encoded as per the destination contract function.
    • +
    +
  • +
  • +

    Transfer Asset function takes five parameters:

    +
  • +
  • Destination Chain: This is the name of the destination chain in bytes32 format, that will receive the asset.
  • +
  • Destination Address: This is the address of the user in bytes format, that will receive the asset on destination chain.
  • +
  • Refund Address : This is the address of the user in ETH address format that will receive the refund if the transaction fails.
  • +
  • Destination Asset: This is the address of the asset in bytes format that will be transferred to the destination chain.
  • +
  • Asset Amount: This is the amount of asset in uint256 format that will be transferred to the destination chain.
  • +
+
+

Warning

+

DISCLAIMER:Below provided code examples is for educational purposes only. It is not intended for use in a production environment or with real assets. Please exercise caution and ensure proper testing and validation of your code before deploying it in a production environment.

+
+
    +
  • Example for how to use transferPayload function in contract-based chains:
  • +
+

// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.19;
+
+// Import the interface from the GitHub repository
+import {IOutboundStateSender} from './interfaces/IOutboundStateSender.sol';
+import {IERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
+
+contract ChildChain {
+
+  // mapping for (withdraw ID => true/false)
+  mapping(uint256 => bool) public withdraws;
+
+  // outbound state sender contract
+  IOutboundStateSender public outboundStateSender;
+
+  constructor(address _outboundStateSender) {
+    require(_outboundStateSender != address(0x0), 'Child Chain: Invalid OutboundStateSender address');
+
+    // Create an instance of the IOutboundStateSender interface using the OutboundStateSender address
+    outboundStateSender = IOutboundStateSender(_outboundStateSender);
+  }
+  /*
+   * @notice withdrawTokens
+   * @dev: amountOrTokenId: tokenId for ERC721 and amount for ERC20
+   * @param user address for deposit
+   * @param rootToken root token address
+   * @param withdrawId
+   */
+  function withdrawTokens(
+    address rootToken,
+    address user,
+    uint256 amountOrTokenId,
+    uint256 withdrawId,
+    bytes32 destinationChain,
+    bytes memory destinationContract
+  ) public onlyOwner {
+    // check if withdrawal happens only once
+    require(withdraws[withdrawId] == false, 'Child Chain: already withdrawal for the given Id');
+
+    // set withdrawal flag
+    withdraws[withdrawId] = true;
+
+    // Create an instance of the ERC20Burnable contract
+    IERC20Burnable erc20Token = IERC20Burnable(rootToken);
+
+    // Burn the tokens from the user's account
+    erc20Token.burn(amountOrTokenId);
+
+    outboundStateSender.transferPayload(
+      destinationChain,
+      destinationContract,
+      user,
+      abi.encode(rootToken, user, amountOrTokenId, withdrawId)
+    );
+  }
+}
+
+* Example for how to use transferAsset function in account-based chains: +
// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.19;
+// Import the interface from the GitHub repository
+import {IOutboundStateSender} from './interfaces/IOutboundStateSender.sol';
+import {IERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
+
+contract ChildChain {
+  // mapping for (withdraw ID => true/false)
+  mapping(uint256 => bool) public withdraws;
+
+  // outbound state sender contract
+  IOutboundStateSender public outboundStateSender;
+
+  constructor(address _outboundStateSender) {
+    require(_outboundStateSender != address(0x0), 'Child Chain: Invalid OutboundStateSender address');
+
+    // Create an instance of the IOutboundStateSender interface using the OutboundStateSender address
+    outboundStateSender = IOutboundStateSender(_outboundStateSender);
+  }
+  /*
+   * @notice withdrawTokens
+   * @dev: amountOrTokenId: tokenId for ERC721 and amount for ERC20
+   * @param user address for deposit
+   * @param rootToken root token address
+   * @param withdrawId
+   */
+  function withdrawTokens(
+    bytes memory rootToken,
+    address user,
+    uint256 amountOrTokenId,
+    uint256 withdrawId,
+    bytes32 destinationChain,
+    bytes memory destinationAddress,
+    bytes memory destinationAsset
+  ) public onlyOwner {
+    // check if withdrawal happens only once
+    require(withdraws[withdrawId] == false, 'Child Chain: already withdrawal for the given Id');
+
+    // set withdrawal flag
+    withdraws[withdrawId] = true;
+
+      // Create an instance of the ERC20Burnable contract
+      IERC20Burnable erc20Token = IERC20Burnable(address(rootToken));
+
+      // Burn the tokens from the user's account
+      erc20Token.burn(amountOrTokenId);
+
+      outboundStateSender.transferAsset(
+        destinationChain,
+        destinationAddress,
+        user,
+        destinationAsset,
+        amountOrTokenId
+      );
+  }
+}
+

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/architecture/dojimachain/index.html b/core/architecture/dojimachain/index.html new file mode 100644 index 0000000..e947901 --- /dev/null +++ b/core/architecture/dojimachain/index.html @@ -0,0 +1,3368 @@ + + + + + + + + + + + + + + + + + + + + + + + Dojima Chain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Dojima Chain

+ +

medium

+

Introduction

+

The Dojima Chain is a critical component of the Dojima Network ecosystem, serving as a foundational layer for the seamless integration of assets, NFTs, and decentralized finance (DeFi) applications from various interconnected blockchains. Designed with security, interoperability, and scalability in mind, the Dojima Chain is powered by a decentralized network of Proof-of-Stake (PoS) validators.

+

Key Features

+

1. Interoperability:

+

The Dojima Chain is designed to bridge the divide between multiple layer 1 and layer 2 blockchains. It acts as a pivotal middle-ground where assets and data from diverse blockchain ecosystems converge, fostering cross-chain compatibility.

+

2. Validator Network:

+

Security is paramount, and the Dojima Chain relies on a network of validators to ensure the integrity and trustworthiness of transactions and data. Validators within the Dojima Network ecosystem play multifaceted roles, including running full nodes, block production, transaction validation, consensus participation, relayer and oracle services, and checkpoint commitment.

+

3. Ethereum Virtual Machine (EVM) Compatibility:

+

The Dojima Chain seamlessly integrates with the Ethereum Virtual Machine (EVM), enabling developers to deploy and execute smart contracts using familiar languages such as Solidity. This compatibility empowers developers to leverage existing Ethereum-based applications and tools within the Dojima ecosystem.

+

4. Dojima Token (DOJ):

+

Transactions within the Dojima Chain are facilitated using the native token, Dojima (DOJ). DOJ operates both as an ERC-20 token and as the native token for the Dojima network. This dual functionality allows users to pay gas fees, participate in staking, and transfer value within the ecosystem.

+

5. Block Producer Selection:

+

The Dojima Chain employs a committee of Block Producers, selected from the validator pool, to ensure efficient block generation and validation. The selection process is based on the validators’ staked tokens, with regular shuffling to maintain fairness and security.

+

Block Producer Selection Process

+

The Block Producer selection process in the Dojima Chain is designed to ensure fairness and security. Here’s a simplified example of how it works:

+

Imagine a validator pool with 4 validators: Validator1, Validator2, Validator3, and Validator4. Each validator has staked a different amount of DOJ tokens. Validator1 has staked 200 DOJ tokens, Validator2 has staked 150 DOJ tokens, Validator3 has staked 100 DOJ tokens, and Validator4 has staked 50 DOJ tokens.

+

Validators are assigned slots proportionally to their stake. The total number of slots allocated is 10. Here’s the distribution of slots:

+
    +
  • Validator1: 4 slots
  • +
  • Validator2: 3 slots
  • +
  • Validator3: 2 slots
  • +
  • Validator4: 1 slot
  • +
+

Now, let’s shuffle the slots using a random seed. After shuffling, we get the following sequence: [Validator3, Validator1, Validator2, Validator2, Validator4, Validator1, Validator3, Validator1, Validator2, Validator3].

+

Next, based on the number of producers to be selected (let’s say we need to select 3 producers), we pick validators from the top of the shuffled list. In this case, the producer set for the next span is defined as:

+
    +
  • Producer1: Validator3
  • +
  • Producer2: Validator1
  • +
  • Producer3: Validator2
  • +
+

These selected validators will take on the role of Block Producers for the next span in the DojimaChain network. This illustrates the producer selection process in the DojimaChain ecosystem.

+

System Call Interface

+

Within the Dojima Chain’s EVM, the System Call Interface plays a vital role. It serves as an internal operator address, enabling the maintenance of Block Producer states at specified block intervals. System Calls trigger requests for updated Block Producer lists, ensuring the network’s smooth operation.

+

State Syncing

+

The Dojima Chain maintains synchronization with different blockchains through the Hermes Chain. This synchronization process ensures that state data from various native chains is securely integrated into the Dojima ecosystem. Validators validate the data using a Threshold Signature Scheme before it is stored in the Hermes Chain.

+

Conclusion

+

The Dojima Chain is at the core of the Dojima Network’s mission to provide developers with a powerful, secure, and interoperable platform for building cross-chain applications. With EVM compatibility, robust validator networks, and advanced features, it stands as a key element in the evolution of the blockchain and Web3 space.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/architecture/hermeschain/index.html b/core/architecture/hermeschain/index.html new file mode 100644 index 0000000..d7e9512 --- /dev/null +++ b/core/architecture/hermeschain/index.html @@ -0,0 +1,3456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Hermes Chain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Hermes Chain

+ +

Hermes Layer

+

The Hermes layer is a vital component within the Dojima Network’s multi-layer architecture, playing a crucial role in ensuring seamless cross-chain interoperability and efficient liquidity management. +Its primary responsibilities include managing native token liquidity from all blockchains, overseeing staking and rewards management for liquidity providers. +It ensures the proper functioning of validators, enforces slashing mechanisms for network security, collects transaction fees, and, most importantly, offers developers universal access to cross-chain liquidity. +This layer plays a pivotal role in enabling seamless interoperability and efficient liquidity management across the Dojima Network.

+ +

medium

+ + +

Main modules inside Hermes Chain are: + - Narada + - Threshold signature scheme + - Fortunas + - Sors

+

Narada

+

Narada functions as a central hub connecting clients to the Hermes chain. Its primary responsibility is to monitor blockchain +events i.e. swapping of Arweave -> Ethereum, Arweave -> Dojima and other custom messages. It also transforms these events into Hermes layer-compatible messages and relays them to the hermes layer.

+ + +
    +
  • +

    Chain clients

    +

    Chain clients are responsible for reading events from their respective blockchains. Client will listen to hermes wallet address transactions as destination/target address. + Currently supported chain clients are Arweave, Bitcoin, Binance, Cosmos, Ethereum, Solana, Polkadot.

    +
  • +
  • +

    Observer

    +

    Observer is responsible for transforming and transmitting observed events to the hermes layer.

    +
  • +
  • +

    Signer

    +

    Signer is responsible for signing transactions onto the destination chain that received from the Hermes chain.

    +
  • +
+

Threshold signature scheme ( TSS )

+

Threshold signature scheme is responsible for securing the liquidity which is being held in the Hermes chain. Liquidity is holded by fortunas vaults. Dojima has written many articles on tss, please checkout https://medium.com/@dojimanetwork for more on tss. Each chain supports certains signature mechanism for signing wallet transactions like secp256k1 curve of ECDSA algorithm for Ethereum, Binance, Cosmos, Binance and RSA for Arweave and ed25519 for Solana, Polkadot. Currently, dojima has support for ecdsa, rsa, ed25519 signature algorithms.

+

Fortunas

+

Fortunas are responsible for holding liquidity of multiple tokens at single place which are generated by dojima tss. Security of liquidity depends on the number of validators managed by tss. When swapping of tokens are involved ( Binance -> Arweave), ⅔ of validators will sign to release the desired token amount on the destination chain requested for swap received from the hermes chain. Since tss is a slow process, for small swap amounts is a drawback. To overcome this, Sors is introduced.

+

Sors

+

Sors are responsible for sending small amounts of requested swap tokens onto the destination chain. Each validator can be a sors. Validator will be assigned 25% of total amount supported tokens based on validator staked amount.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/architecture/overview/index.html b/core/architecture/overview/index.html new file mode 100644 index 0000000..a313cde --- /dev/null +++ b/core/architecture/overview/index.html @@ -0,0 +1,3262 @@ + + + + + + + + + + + + + + + + + + + + + + + Overview - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Overview

+

Dojima Architecture

+

medium +Dojima Network is built on a multi-layer architecture comprising two blockchains that collaboratively interact with other blockchains. +This design enables liquidity access and serves as a cross-chain development platform for creating cross-chain applications. These layers include the Hermes layer and the DojimaChain.

+
    +
  • +

    The Hermes layer is built on top of the Cosmos SDK and tendermint. It is the buffer layer that is connected to various independent blockchains.

    +
  • +
  • +

    DojimaChain operates as the intermediate layer where developers deploy applications and access the Hermes layer to establish connections with all chains.

    +
  • +
+

In simple terms, we will create a buffer layer on top of Cosmos SDK and Tendermint, establishing connections with major blockchains while maintaining liquidity pools for the Dojima native token(DOJ) and other tokens of prominent blockchain platforms. +Liquidity data will be available and verified by all validators at the end of each block and supplied to contracts on the intermediate layer, Dojima chain. +This data can be accessed by smart contracts developed by cross-chain DApp creators.

+

Some of the features that Dojima Network offers include:

+
    +
  1. +

    Universal Liquidity Access: This enables developers to access the liquidity of all blockchains directly from their protocols.

    +
  2. +
  3. +

    Cross-Chain Execution and Transfer: This enables users to execute contract code on multiple platforms and also enables cross-chain data transfer to communicate with custom smart contracts.

    +
  4. +
  5. +

    Cross-Chain Liquidity Pools: This feature enables developers and users to access cross-chain liquidity pools for executing various custom cross-chain actions

    +
  6. +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/evm/client/index.html b/core/chain-clients/evm/client/index.html new file mode 100644 index 0000000..f83b39f --- /dev/null +++ b/core/chain-clients/evm/client/index.html @@ -0,0 +1,3439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Client - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Client

+ +

Introduction

+

The EVM (Ethereum Virtual Machine) client is a crucial component designed to facilitate interactions between EVM-compatible chains and the Dojima chain. It is responsible for processing transactions initiated by users and forwarding them to the Dojima chain. Additionally, it receives state updates from the Dojima chain and relays them to the destination chain. The EVM client is particularly useful for handling all interactions that occur on EVM-related chains, such as transactions from AVAX C-chain to Dojima or vice versa.

+

Architecture

+

The EVM client is composed of two main services: + - Listener service + - Parser service.

+

Listener Service

+

The Listener service is responsible for monitoring all events emitted by EVM-related contracts, including the State Sender contract, Outbound State Sender contract, and Router contract. It filters out the relevant events and forwards them to the Parser service for further processing.

+

Parser Service

+

The Parser service takes the events forwarded by the Listener service, parses these events, and sends them in batches to the Observer. The Observer then processes these batches further. This architecture allows the EVM client to efficiently handle a large volume of transactions and state updates, ensuring that all relevant data is accurately relayed between the source chain, the Dojima chain, and the destination chain.

+

Usage

+

To use the EVM client, you need to initiate a transaction or a state update on an EVM-compatible chain. The Listener service of the EVM client will automatically detect the event emitted by the transaction or state update. It will filter out the relevant events and forward them to the Parser service. The Parser service will then parse these events and send them in batches to the Observer. The Observer will process these batches and update the state of the Dojima chain or the destination chain accordingly. By using the EVM client, you can ensure that all interactions between EVM-compatible chains and the Dojima chain are handled efficiently and accurately.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/evm/hermes-bridge/index.html b/core/chain-clients/evm/hermes-bridge/index.html new file mode 100644 index 0000000..940fea1 --- /dev/null +++ b/core/chain-clients/evm/hermes-bridge/index.html @@ -0,0 +1,3563 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Hermes Bridge - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Hermes Bridge

+ +

Introduction

+

The Hermes chain is a Cosmos-based blockchain responsible for connecting the Dojima chain to other chains, both EVM (Ethereum Virtual Machine) and non-EVM chains. Within Hermes, there are three distinct modules + Narada the Hermes and the DojimaChain module.

+

Narada serves as a hub for clients connected to the Hermes chain. Its primary role is to monitor all events and convert them into a format suitable for transmission to the Hermes chain. After observing transactions, Narada relays them to the Hermes chain.

+

The Hermes module functions as a storage system for the Dojima chain. It stores transactions sent by Narada, ensuring they are readily accessible when needed.

+

The DojimaChain module acts as a client of the Dojima chain, facilitating interactions between the Dojima chain and the Hermes chain.

+
type Tx struct {
+  ID          TxID    `protobuf:"bytes,1,opt,name=id,proto3,casttype=TxID" json:"id,omitempty"`
+  Chain       Chain   `protobuf:"bytes,2,opt,name=chain,proto3,casttype=Chain" json:"chain,omitempty"`
+  FromAddress Address `protobuf:"bytes,3,opt,name=from_address,json=fromAddress,proto3,casttype=Address" json:"from_address,omitempty"`
+  ToAddress   Address `protobuf:"bytes,4,opt,name=to_address,json=toAddress,proto3,casttype=Address" json:"to_address,omitempty"`
+  Coins       Coins   `protobuf:"bytes,5,rep,name=coins,proto3,castrepeated=Coins" json:"coins"`
+  Gas         Gas     `protobuf:"bytes,6,rep,name=gas,proto3,castrepeated=Gas" json:"gas"`
+  Memo        string  `protobuf:"bytes,7,opt,name=memo,proto3" json:"memo,omitempty"`
+  Payload     []byte  `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+// Transaction ID is a unique identifier for a transaction
+type TxID string
+
+// Chain is an alias of string , represent a blockchain name
+type Chain string
+
+type Address string
+
+type Coin struct {
+  Asset    Asset                                   `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset"`
+  Amount   github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"`
+  Decimals int64                                   `protobuf:"varint,3,opt,name=decimals,proto3" json:"decimals,omitempty"`
+}
+
+type Asset struct {
+  Chain  Chain  `protobuf:"bytes,1,opt,name=chain,proto3,casttype=Chain" json:"chain,omitempty"`
+  Symbol Symbol `protobuf:"bytes,2,opt,name=symbol,proto3,casttype=Symbol" json:"symbol,omitempty"`
+  Ticker Ticker `protobuf:"bytes,3,opt,name=ticker,proto3,casttype=Ticker" json:"ticker,omitempty"`
+  Synth  bool   `protobuf:"varint,4,opt,name=synth,proto3" json:"synth,omitempty"`
+}
+
+// Symbol represent an asset
+type Symbol string
+
+// Ticker The trading 'symbol' or shortened name (typically in capital letters)
+// that refer to a coin on a trading platform. For example: BNB
+type Ticker string
+
+

Narada

+

Narada’s operations can be summarized in the following steps:

+
    +
  • Narada observes the events emitted by the State Sender Contract. The State Sender Contract is a contract that is deployed on the Ethereum chain.
  • +
  • The State Sender Contract generates an event known as TokenTransfer, containing transaction information destined for the Dojima chain.
  • +
  • Narada captures and transforms the TokenTransfer event into a common format referred to as XMsgObservedTx, which is compatible with the Hermes chain.
  • +
+
type XMsgObservedTx struct {
+  Tx             Tx         `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx"`
+  Status         Status    `protobuf:"varint,2,opt,name=status,proto3,enum=types.Status" json:"status,omitempty"`
+  BlockHeight    int64     `protobuf:"varint,3,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
+  Signers        []string  `protobuf:"bytes,4,rep,name=signers,proto3" json:"signers,omitempty"`
+  KeysignMs      int64     `protobuf:"varint,5,opt,name=keysign_ms,json=keysignMs,proto3" json:"keysign_ms,omitempty"`
+  FinaliseHeight int64     `protobuf:"varint,6,opt,name=finalise_height,json=finaliseHeight,proto3" json:"finalise_height,omitempty"`
+}
+
+

Hermes

+

The Hermes module is responsible for validating and storing transactions sent by Narada. It operates with its set of validators responsible for transaction validation. These validators are chosen through the Tendermint consensus algorithm. Once a sufficient number of validators approve a transaction, its data is validated. Subsequently, based on memo data, transaction data is converted into the Hermes chain message format.

+

For Ethereum chain State Sender Contract events, event data is converted into the following format:

+
type MsgEVMTransferNative struct {
+  Txn                  Tx                                      `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx"`
+  Signer              github_com_cosmos_cosmos_sdk_types.AccAddress  `protobuf:"bytes,2,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"signer,omitempty"`
+  DestinationContract github_com_dojimanetwork_hermes_common.Address `protobuf:"bytes,3,opt,name=destination_contract,json=destinationContract,proto3,casttype=github.com/dojimanetwork/hermes/common.Address" json:"destination_contract,omitempty"`
+  DepositId           uint64                                         `protobuf:"varint,4,opt,name=depositId,proto3" json:"depositId,omitempty"`
+}
+
+

The MsgEVMTransferNative format is stored within the Hermes chain and later converted into the DojimaInput format, which is used by the Dojima chain. +

type DojimaInput struct {
+  ID           uint64                                              `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+  Contract     github_com_dojimanetwork_dojimachain_common.Address `protobuf:"bytes,2,opt,name=contract,proto3,casttype=github.com/dojimanetwork/dojimachain/common.Address" json:"contract"`
+  Data         []byte                                              `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
+  TxHash       string                                              `protobuf:"bytes,4,opt,name=txHash,proto3" json:"txHash,omitempty"`
+  ObservedTime time.Time                                           `protobuf:"bytes,5,opt,name=observedTime,proto3,stdtime" json:"observedTime"`
+  ChainID      string                                              `protobuf:"bytes,6,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+}
+
+func (h EvmTransferNativeHandler) handleV89(ctx cosmos.Context, msg *MsgEVMTransferNative) (*cosmos.Result, error) {
+  ctx.Logger().Info("message evm transfer", "received message", msg)
+
+  ctx.Logger().Debug("✅ Validating EvmTransferNative msg",
+    "Id", msg.Tx.ID,
+    "Destination Contract", msg.DestinationContract,
+    "Chain", msg.Tx.Chain,
+    "Deposit Id", msg.DepositId,
+  )
+
+  // check if event record exists
+  if exists := h.mgr.Keeper().HasLayer1TransferNativeMsg(ctx, msg.Tx.ID.String()); exists {
+    return sdk.WrapServiceResult(ctx, nil, common.ErrEventRecordAlreadySynced(types.DefaultCodespace))
+  }
+
+  hermesKeeper := h.mgr.Keeper()
+  lastDepositId, err := hermesKeeper.GetDojimaLastDepositId(ctx)
+  if err != nil {
+    ctx.Logger().Error("Unable to fetch Dojima Chain Last Deposit ID", "error", err)
+    return nil, err
+  }
+
+  // create Dojima Input
+  inRecord := dtypes.NewDojimaInput(
+    lastDepositId+1, // ID generated on Hermes
+    dcommon.HexToAddress(msg.DestinationContract.String()), // Contract address should be updated in chain params
+    msg.Tx.Payload,
+    msg.Tx.ID.String(),
+    ctx.BlockTime(),
+    hermesKeeper.GetChainId(ctx),
+  )
+
+  if err := hermesKeeper.StoreDojimaInput(ctx, inRecord); err != nil {
+    ctx.Logger().Error("Unable to update event record", "id", msg.Tx.ID, "error", err)
+    return sdk.WrapServiceResult(ctx, nil, common.ErrDojimaInputUpdate(types.DefaultCodespace))
+  }
+
+  // Storing Dojima Input Message with Unique TxHash
+  if err = hermesKeeper.StoreEVMTransferNativeMsg(ctx, msg); err != nil {
+    ctx.Logger().Error("unable to store dojima input evm transfer message",
+    "id", msg.Tx.ID, "error", err)
+    return sdk.WrapServiceResult(ctx, nil, common.ErrDojimaInputMessageUpdate(types.DefaultCodespace))
+  }
+
+  return &sdk.Result{
+    Events: ctx.EventManager().Events().ToABCIEvents(),
+  }, nil
+}
+

+

Dojima Chain Module

+

The Dojima Chain module provides a querying mechanism to retrieve transactions from the Hermes chain.

+

Transactions are fetched from the Hermes chain using the following query format:

+
  // Queries a list of DojimaInput items.
+  rpc DojimaInput(QueryDojimaInputRequest) returns (QueryDojimaInputResponse) {
+    option (google.api.http).get = "/dojimanetwork/hermes/dojimachain/dojima_input/{id}";
+  }
+
+  message QueryDojimaInputRequest {
+    uint64 id = 1;
+  }
+
+  message QueryDojimaInputResponse {
+    DojimaInput input = 1;
+  }
+
+  message DojimaInput {
+    option (gogoproto.goproto_stringer) = false;
+    uint64 id = 1 [(gogoproto.customname) = "ID"]; //to be changed to sequence number from hash - @akhilpune
+    common.DcAddress contract = 2 [(gogoproto.casttype) = "github.com/dojimanetwork/dojimachain/common.Address",(gogoproto.nullable) = false];
+    bytes data = 3;
+    string txHash = 4;
+    google.protobuf.Timestamp observedTime = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+    string chain_id = 6 [(gogoproto.customname) = "ChainID"];
+  }
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/evm/state-sender-contract/index.html b/core/chain-clients/evm/state-sender-contract/index.html new file mode 100644 index 0000000..41c84da --- /dev/null +++ b/core/chain-clients/evm/state-sender-contract/index.html @@ -0,0 +1,3523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Ethereum State Sender Contract - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Ethereum State Sender Contract

+ +

Introduction

+

Ethereum, a pioneering decentralized platform, empowers developers to create and deploy smart contracts. These self-executing pieces of code automate intricate processes and agreements, akin to digital agreements that trigger automatically when predefined conditions are met.

+

However, Ethereum’s significance transcends its technological prowess. It has cultivated a vibrant ecosystem where global developers converge to craft decentralized applications (dApps). Leveraging Ethereum’s smart contracts, these dApps provide a wide array of services. These range from decentralized finance (DeFi) and non-fungible tokens (NFTs) to decentralized governance and beyond.

+

The State Sender Contract

+

The State Sender Contract is a smart contract designed to facilitate Ethereum (dApp) developers in sending tokens and payloads to the Dojima Chain.

+

To utilize the State Sender Contract, follow these straightforward steps:

+

Step 1: Copy the State Sender Contract from GitHub

+
    +
  • Access the State Sender Contract Interface and Contract on the GitHub repository here and here respectively.
  • +
  • Copy both the Interface and Contract into their corresponding folders, typically located in ’. /contracts/’, ’. /interfaces/’ or as per your project structure.
  • +
+

Step 2: Obtain the State Sender Contract Address

+
    +
  • Retrieve the State Sender Contract address from the Dojima Chain Explorer.
  • +
+

Note: The State Sender Contract address may vary for different chains. + Ensure that you select the Ethereum chain and the appropriate mainnet or testnet.

+

Step 3: Initialize the State Sender Contract

+
    +
  • Initialize the State Sender Contract in your dapp by passing the State Sender Contract address as a parameter.
  • +
+
// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.19;
+
+// Import the interface from the GitHub repository
+import { IStateSender } from './interfaces/IStateSender.sol';
+
+contract App {
+    // Declare a variable to hold the address of the StateSender contract
+    address public stateSender;
+
+    constructor(address _stateSender) {
+        stateSender = _stateSender;
+    }
+
+    /**
+    * @dev Function to call the tokenTransferWithPayload function from the StateSender contract
+    * @param destinationChain The chain to which the tokens and payload are to be sent.
+    * @param destinationContract The contract to which the tokens and payload are to be sent.
+    * @param asset The address of the token to be sent.
+    * @param tokenAmount The amount of tokens to be sent.
+    * @param payload The abi encoded contract call to be sent.
+    * @notice destinationChain and destinationContract should be registered with the state sender contract before sending the tokens and payload.
+    */
+    function sendState(
+        bytes32 destinationChain,
+        address destinationContract,
+        address asset,
+        uint256 tokenAmount,
+        bytes calldata payload
+    ) public {
+        // Create an instance of the IStateSender interface using the StateSender address
+        IStateSender stateSenderInstance = IStateSender(stateSender);
+
+        // Call the tokenTransferWithPayload function
+        stateSenderInstance.tokenTransferWithPayload(
+            destinationChain,
+            destinationContract,
+            asset,
+            tokenAmount,
+            payload
+        );
+    }
+}
+
+

Step 4: Event emitted by the State Sender Contract TokenTransferWithPayload

+
    +
  • Once the State Sender Contract executes the TokenTransferWithPayload function, it emits an event called TokenTransfer. This event plays a vital role in the interaction with Narada.
  • +
  • The TokenTransfer event furnishes essential information in its parameters:
      +
    • depositID - This identifier uniquely identifies deposits on the Dojima chain. It is relevant only when the destinationChain is Dojima.
    • +
    • destinationChain - This denotes the specific chain to which the tokens and payload have been dispatched.
    • +
    • destinationContract - It signifies the target contract to which the tokens and payload are delivered.
    • +
    • asset - This parameter contains the address of the token that was sent.
    • +
    • tokenAmount - The amount of tokens sent.
    • +
    • payload - This field holds the ABI-encoded contract call that was transmitted. + Step 4: Processing the Event Emitted by the State Sender Contract - TokenTransferWithPayload + Once the State Sender Contract executes the TokenTransferWithPayload function, it emits an event called TokenTransfer. This event plays a vital role in the interaction with Narada.
    • +
    +
  • +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/nonevm/arweave/index.html b/core/chain-clients/nonevm/arweave/index.html new file mode 100644 index 0000000..0ccb8bf --- /dev/null +++ b/core/chain-clients/nonevm/arweave/index.html @@ -0,0 +1,3509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Arweave Chain Client - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Arweave

+ +

Introduction

+

Arweave is a new type of storage that backs data with sustainable and perpetual endowments, allowing users and developers to truly store data forever – for the very first time.

+

As a collectively owned hard drive that never forgets, Arweave allows us to remember and preserve valuable information, apps, and history indefinitely. By preserving history, it prevents others from rewriting it.

+

Scanning Blocks

+

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

+
      txInfo, err := c.client.GetTransactionByID(tx)
+
+      // if tx is not found, invalid
+      if err == argo.ErrNotFound || err == argo.ErrInvalidId {
+      return types.TxInItem{}, err
+      }
+
+      // converting signature data to owner address
+      sender, err := arutils.OwnerToAddress(txInfo.Owner)
+
+      if err != nil {
+      return types.TxInItem{}, err
+      }
+
+      winstonQtyStr := txInfo.Quantity
+      winstonFeeStr := txInfo.Reward
+
+      winstonQty, ok := cosmos.ParseUint(winstonQtyStr)
+
+      if ok != nil {
+      err = fmt.Errorf("invalid amount: %v", winstonQtyStr)
+      return types.TxInItem{}, err
+      }
+
+      _, ok = cosmos.ParseUint(winstonFeeStr)
+
+      if ok != nil {
+      err = fmt.Errorf("invalid fee: %v", winstonFeeStr)
+      return types.TxInItem{}, err
+      }
+
+      // when value is less than or equal to zero, it is data transaction not a transfer
+      if winstonQty.IsZero() {
+      return types.TxInItem{}, fmt.Errorf("not a transfer transaction, its a data transaction, so ignoring")
+      }
+
+      client := argo.NewClient("https://arweave.net")
+      address := os.Getenv("AR_ADDRESS")
+      reward, err := client.GetTransactionPrice([]byte(""), &address)
+      convReward := cosmos.NewUint(uint64(reward))
+      // till here
+
+      if err != nil {
+      c.logger.Error().Err(err).Msg("failed to get arweave fee")
+      }
+
+      gasFee := common.Gas{
+      common.NewCoin(common.ARAsset, convReward).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),
+      }
+      // update memory cache
+      c.udpateARGasCache(convReward)
+
+      toAddr := txInfo.Target
+
+      //read memo from tags [{name, value}]
+      var memo string
+      for _, val := range txInfo.Tags {
+      if strings.EqualFold(val.Name, "memo") {
+      memo = val.Value
+      c.logger.Debug().Str("memo", memo).Msg("found memo field")
+      }
+      }
+
+      if memo == "" {
+      c.logger.Debug().Str("memo", memo).Msg("found empty memo")
+      }
+
+      return types.TxInItem{
+      BlockHeight: height,
+      Tx:          txInfo.ID,
+      Sender:      sender,
+      To:          toAddr,
+      Coins: common.Coins{
+      common.NewCoin(common.ARAsset, winstonQty).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),
+      },
+      Memo: memo,
+      Gas:  gasFee,
+      }, nil
+
+

Arweave Signer

+

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on arweave chain. Signing transactions are done in two ways: using rsa tss signing algo and single wallet signing.

+
      _, err := tx.VaultPubKey.GetAddress(c.GetChain())
+      //c.logger.Debug().Msgf("process outbound tx", fromAddr)
+      if err != nil {
+      return &types.Transaction{}, fmt.Errorf("failed to convert arweave address (%s): %w", tx.VaultPubKey.String(), err)
+      }
+
+      // initialise to collect all received txout substractFee coins
+      var coins = cosmos.NewUint(0)
+      for _, coin := range tx.Coins {
+      // handle sors return, leave enough coin to pay for gas.
+      if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {
+      if coin.Asset == c.cfg.ChainID.GetGasAsset() {
+      substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))
+      if coin.Amount.LT(substractFee) {
+      return &types.Transaction{}, fmt.Errorf("not enough to pay for transaction, Origal amount %d, Fee %d", coin.Amount.Uint64(), substractFee.Uint64())
+      }
+
+      coin.Amount = coin.Amount.Sub(substractFee)
+      }
+      }
+      coins = coins.Add(coin.Amount)
+      }
+
+      tag := types.Tag{
+        Name:  "memo",
+        Value: tx.Memo,
+      }
+
+      var tags []types.Tag
+      tags = append(tags, tag)
+      encodeTag := utils.TagsEncode(tags)
+
+      arTx := &types.Transaction{
+      Format:   2,
+      Quantity: coins.String(),
+      Data:     "",
+      DataSize: "0",
+      Reward:   c.averageFee().String(),
+      Target:   tx.ToAddress.String(),
+      Tags:     encodeTag,
+      }
+
+      return arTx, nil
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/nonevm/polkadot/index.html b/core/chain-clients/nonevm/polkadot/index.html new file mode 100644 index 0000000..d96a2a0 --- /dev/null +++ b/core/chain-clients/nonevm/polkadot/index.html @@ -0,0 +1,3569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Polkadot Chain Client - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Polkadot

+ +

Introduction

+

Polkadot unites and secures a growing ecosystem of specialized blockchains called parachains. Apps and services on Polkadot can securely communicate across chains, forming the basis for a truly interoperable decentralized web.

+

Scanning Blocks

+

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

+
    func (c *Client) convertToTxIn(dextrinsic *DecodedExtrinsic, height int64) (types.TxInItem, error) {
+      e := dextrinsic.Extrinsic
+      call, ok := e.Metadata.CallIndex[e.CallIndex]
+      if !ok {
+        return types.TxInItem{}, fmt.Errorf("failed to get call index from metadata")
+      }
+      // if extrinsic module is utility and function is batch all or batch with signed tx, gas class is normal
+      // https://docs.substrate.io/build/tx-weights-fees/
+      if e.Module == "Utility" && (call.Call.Name == "batch_all" || call.Call.Name == "batch") && e.ContainsTransaction && len(e.Signature) > 0 && dextrinsic.PaymentInfo.Class == "normal" {
+        dest := " "
+        dotQty := cosmos.ZeroUint()
+        memo := ""
+        calls := &[]UtilityBatchCall{}
+        err := unmarshalAny(calls, e.Params[0].Value)
+        gas := dextrinsic.PaymentInfo.PartialFee.BigInt().Uint64()
+        comsosGas := cosmos.NewUint(gas)
+        c.updateDOTGasCache(comsosGas)
+        if err != nil {
+          return types.TxInItem{}, err
+        }
+
+        for _, c := range *calls {
+          for _, a := range c.Params {
+            switch a.Name {
+            // decode destination address to ss58
+            case "dest":
+              dest = EncodeToSS58(a.Value.(map[string]interface{})["Id"].(string))
+              break
+              // get transacted value to dest address
+            case "value":
+              value := a.Value.(string)
+              dotQty, err = cosmos.ParseUint(value)
+              if err != nil {
+                return types.TxInItem{}, err
+              }
+              break
+              // get memo field
+            case "remark":
+              memoBeforeConv := a.Value.(string)
+              parts := strings.Split(memoBeforeConv, ":")
+              if len(parts) < 2 {
+                return types.TxInItem{}, fmt.Errorf("invalid memo of dot transaction %s, tx hash %s", memo, e.ExtrinsicHash)
+              }
+              if strings.EqualFold(parts[0], "memo") {
+                memo = strings.Join(parts[1:], ":")
+              } else {
+                return types.TxInItem{}, fmt.Errorf("invalid memo of dot transaction %s, tx hash %s", memo, e.ExtrinsicHash)
+              }
+              break
+            }
+          }
+        }
+
+        return types.TxInItem{
+          BlockHeight: height,
+          Tx:          e.ExtrinsicHash,
+          Sender:      EncodeToSS58(e.Address.(string)),
+          To:          dest,
+          Memo:        memo,
+          Coins: common.Coins{
+            common.NewCoin(common.DOTAsset, dotQty).WithDecimals(common.DOTCHAIN.GetGasAssetDecimal()),
+          },
+          Gas: common.Gas{
+            common.NewCoin(common.DOTAsset, comsosGas).WithDecimals(common.DOTCHAIN.GetGasAssetDecimal()),
+          },
+        }, nil
+      }
+
+      return types.TxInItem{}, nil
+    }
+
+

Polkadot Signer

+

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on arweave chain. Signing transactions are done in two ways: using ed25519/sr25519 tss signing algo and single wallet signing.

+
    func (c *Client) processOutboundTx(tx stypes.TxOutItem, hermeschainHeight int64) (gsrpcTypes.SignatureOptions, gsrpcTypes.Extrinsic, error) {
+      _, err := tx.VaultPubKey.GetAddress(c.GetChain())
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, fmt.Errorf("failed to convert polkadot address (%s): %w", tx.VaultPubKey.String(), err)
+      }
+
+      // initialise to collect all received txout substractFee coins
+      var coins = cosmos.NewUint(0)
+      for _, coin := range tx.Coins {
+        // handle sors return, leave enough coin to pay for gas.
+        if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {
+          if coin.Asset == c.cfg.ChainID.GetGasAsset() {
+            substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))
+            if coin.Amount.LT(substractFee) {
+              return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, fmt.Errorf("not enough to pay for transaction, Origal amount %d, Fee %d", coin.Amount.Uint64(), substractFee.Uint64())
+            }
+
+            coin.Amount = coin.Amount.Sub(substractFee)
+          }
+        }
+        coins = coins.Add(coin.Amount)
+      }
+
+      // fetch the latest metadata from chain
+      metadata, err := c.GetLatestMetadata()
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // convert from ss58 to hexadecimal address
+      hexAddr := DecodeFromSS58(tx.ToAddress.String())
+      appendX := strings.Join([]string{"0x", hexAddr}, "")
+      dest, err := gsrpcTypes.NewMultiAddressFromHexAccountID(appendX)
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // append memo string to tx.memo and join with ":"
+      memoArray := strings.Join([]string{"memo", tx.Memo}, ":")
+      memo := []byte(memoArray)
+
+      // prepare system::remark call
+      remarkCall, err := gsrpcTypes.NewCall(metadata, "System.remark", memo)
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // dest amount
+      valUint64 := coins.Uint64()
+      amount := gsrpcTypes.NewUCompactFromUInt(valUint64)
+
+      // prepare balances::transfer call
+      transferCall, err := gsrpcTypes.NewCall(metadata, "Balances.transfer", dest, amount)
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // prepare utility::batch_all
+      utilityBatchCall, err := gsrpcTypes.NewCall(metadata, "Utility.batch_all", []gsrpcTypes.Call{transferCall, remarkCall})
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // fetch genesis hash for immortal era.
+      genesisHash, err := c.gsrpc.RPC.Chain.GetBlockHash(0)
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // create storage key
+      storageKey, err := gsrpcTypes.CreateStorageKey(metadata, "System", "Account", c.dotKeysignWrapper.dotKP.PublicKey)
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // fetch account info for nonce value
+      var accountInfo gsrpcTypes.AccountInfo
+      ok, err := c.gsrpc.RPC.State.GetStorageLatest(storageKey, &accountInfo)
+      nonce := accountInfo.Nonce
+
+      if err != nil || !ok {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // fetch runtime version data
+      runtimeVersion, err := c.GetRuntimeVersion()
+
+      if err != nil {
+        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err
+      }
+
+      // prepare extrinsic for signing
+      extrinsic := gsrpcTypes.NewExtrinsic(utilityBatchCall)
+
+      return gsrpcTypes.SignatureOptions{
+        BlockHash:          genesisHash,
+        Era:                gsrpcTypes.ExtrinsicEra{IsMortalEra: false},
+        GenesisHash:        genesisHash,
+        Nonce:              gsrpcTypes.NewUCompactFromUInt(uint64(nonce)),
+        SpecVersion:        runtimeVersion.SpecVersion,
+        Tip:                gsrpcTypes.NewUCompactFromUInt(0),
+        TransactionVersion: runtimeVersion.TransactionVersion,
+      }, extrinsic, nil
+    }
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/nonevm/solana/solana-client/index.html b/core/chain-clients/nonevm/solana/solana-client/index.html new file mode 100644 index 0000000..1e19cde --- /dev/null +++ b/core/chain-clients/nonevm/solana/solana-client/index.html @@ -0,0 +1,3635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Solana Chain Client - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Solana Client

+ +

Introduction

+

Solana is a layer-1 blockchain similar to Ethereum and Bitcoin meaning other layer-2 blockchains can build on Solana. Solana has a similar concept of smart contracts on Ethereum called as Programs which also facilitates in development of dApps. Solana follows a consensus mechanism of Proof-of-History, which can be understood as a type of cryptographic timeclock which manages to timestamp a blockchain transaction. This helps in order of the blocks and transactions. The advantages of this can be understood on comparing the Bitcoin block validation time (10 mins) which uses Proof of Work and Solana block validation time (800 milliseconds).

+

Solana local test node

+

To build programs and test it on your local node, you need to run a local instance of Solana local validator. To run it, first install Solana CLI. Then start your own local validator node by running the command solana-test-validator after successfully installing Solana CLI. Further steps can be found here if you find the need to dive in-depth.

+

Solana-Client Overview

+

Solana client listens and parses the transactions included in solana blocks. +It will parse the transaction’s inner instructions field to know which programs were part of the execution. +If we find our state-sender program address in the inner-instruction, It means that some other program had to use our state-sender program for some sort of cross-chain operation. +The logs of the above transaction are parsed to see what type of event is emitted. +The event is extracted(termed as payload) and posted to the Hermes chain as a TxIn item. +At regular block intervals dojima chain will fetch TxIn items stored on hermes chain. +Based on the received payload, the dojima chain will be sending the payload to a destined contract on the dojima chain.

+

Filtering Transactions

+
func isDOJStateSenderTxn(tx *rpc.GetParsedTransactionResult, stateSenderContract string) (bool, string) {
+   log := tx.Meta.LogMessages
+   prog_add := ""
+   if len(tx.Meta.InnerInstructions) == 0 {
+      return false, ""
+   }
+   for i := 0; i < len(tx.Meta.InnerInstructions[0].Instructions); i++ {
+      prog_add += tx.Meta.InnerInstructions[0].Instructions[i].ProgramId.String()
+      prog_add += " "
+   }
+   if !strings.Contains(prog_add, "<sol_state_sender_prog>") {
+      return false, ""
+   }
+   log_str := fmt.Sprint(log)
+   if strings.Contains(log_str, "TokenTransfer") {
+      return true, "TokenTransfer"
+   } else if strings.Contains(log_str, "TransferPayload") {
+      return true, "TransferPayload"
+   }
+   return false, ""
+}
+
+
+

Info

+

The above code snippet allows the client to decide whether the picked transaction should be filtered and sent to hermes.

+
+
    +
  • isDOJStateSenderTxn - This function returns a boolean value stating whether the transaction is state-sender transaction or not.
  • +
  • tx.Meta.InnerInstructions[0].Instructions - This consists of the programs that were part of the first instruction execution.
  • +
  • TokenTransfer and TransferPayload are the types of events which are to be filtered and stored in the Hermes chain.
  • +
+
func GetUnpackedEvent(log []string, typ string) (StateSenderEvent, error) {
+   sse := StateSenderEvent{}
+   if typ == "TokenTransfer" {
+     return sse, nil
+   } else if typ == "TransferPayload" {
+      log_str := fmt.Sprintln(log)
+      log_str_arr := strings.Split(log_str, " ")
+      indx := -1
+      for i := 0; i < len(log_str_arr); i++ {
+         if log_str_arr[i] == typ {
+            indx = i
+            break
+         }
+      }
+    if indx == -1 {
+        return sse, fmt.Errorf("unable to parse TransferPayload event")
+    }
+      //Destination chain
+      sse.DestChain = "DOJ"
+      //Destination contract
+      sse.SourceDestContract = log_str_arr[1]
+      //destination chain destination contract
+      sse.DestinationDestContract = log_str_arr[indx+2]
+      //Destination counter nonce
+      counter_in_u64, err := strconv.ParseUint(log_str_arr[indx+1], 10, 64)
+      if err != nil {
+         return sse, &StateSenderError{}
+      }
+      sse.CounterNonce = counter_in_u64
+      //emitted data for child chain smart contract
+      sse.DataInBytes = log_str_arr[indx+3]
+      return sse, nil
+   }
+   return sse, nil
+}
+
+
+

Info

+

The above code snippet allows the client to parse log to extract payload .

+
+

Scanning Blocks

+

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

+
      client := rpc.NewClient("http://127.0.0.1:8899")
+      address := os.Getenv("SOL_ADDRESS")
+
+      txInfo, err := c.client.GetTransaction(
+        context.TODO(), 
+        txSig, 
+        &rpc.GetTransactionOpts{Encoding: solana.EncodingBase64}
+        )
+
+      // If Transaction is not found.
+      if err != nil {
+        return types.TxInItem{}, err
+      }
+
+      decodedTx, err := solana.TransactionFromDecoder(bin.NewBinDecoder(txInfo.Transaction.GetBinary()))
+
+      // If Transaction is not decoded. 
+      if err != nil {
+        return types.TxInItem{}, err
+      }
+
+      // Getting the transaction details from the decoded transaction.
+      sender := decodedTx.AccountMetaList()[0].PublicKey.String()
+      LamportQtyStr := cosmos.NewUint(txInfo.Meta.PostBalances[1] - txInfo.Meta.PreBalances[1])
+      LamportFeeStr := cosmos.NewUint(txInfo.Meta.Fee)
+
+      // Read memo from solana transaction.
+      solmemo := ""
+      if len(txInfo.Meta.LogMessages) > 4 {
+        solmemo = txInfo.Meta.LogMessages[4]
+        solmemo = strings.ReplaceAll(solmemo, "Program log: ", "")
+      }
+
+      gasFee := common.Gas{
+        common.NewCoin(common.SOLAsset, LamportFeeStr),
+      }
+      toAddr := decodedTx.Message.AccountKeys[1].String()
+
+      // update memory cache
+      c.udpateSOLGasCache(LamportFeeStr)
+
+      return types.TxInItem{
+        BlockHeight: height,
+        Tx:          tx,
+        Sender:      sender,
+        To:          toAddr,
+        Coins: common.Coins{
+          common.NewCoin(common.SOLAsset, LamportQtyStr),
+        },
+        Memo: solmemo,
+        Gas:  gasFee,
+      }, nil
+
+

Solana Signer

+

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on solana chain. Signing transactions are done in two ways: using ed25519 tss signing algo and single wallet signing.

+
    _, err := tx.VaultPubKey.GetAddress(c.GetChain())
+  if err != nil {
+    return &solana.Transaction{}, fmt.Errorf("failed to convert solana address (%s): %w", tx.VaultPubKey.String(), err)
+  }
+
+  var coins = cosmos.NewUint(0)
+  for _, coin := range tx.Coins {
+    // handle sors return, leave enough coin to pay for gas.
+    if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {
+        if coin.Asset == c.cfg.ChainID.GetGasAsset() {
+            substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))
+            if coin.Amount.LT(substractFee) {
+                return &solana.Transaction{}, fmt.Errorf("not enough to pay for transaction, Origal amount %d, Fee %d", coin.Amount.Uint64(), substractFee.Uint64())
+            }
+
+            coin.Amount = coin.Amount.Sub(substractFee)
+        }
+    }
+    coins = coins.Add(coin.Amount)
+  }
+  recent, err := c.GetRecentBlockhash()
+  if err != nil {
+
+  }
+
+  amt := coins.String()
+  instruction_data := []byte{0xaa, 0xbb}
+
+  instruction := []solana.Instruction{
+    &TransactionInstructions{
+        accounts: []*solana.AccountMeta{
+            {PublicKey: solana.MustPublicKeyFromBase58(tx.fromAddress.PublicKey()), IsSigner: true, IsWritable: true},
+            {PublicKey: solana.MustPublicKeyFromBase58(tx.ToAddress.String()), IsSigner: false, IsWritable: true},
+            {PublicKey: solana.SystemProgramID, IsSigner: false, IsWritable: false},
+        },
+        data:      instruction_data,
+        programID: solana.MustPublicKeyFromBase58(os.Getenv("SOL_PROGRAM")),
+    },
+  }
+
+  solTx, err := solana.NewTransaction(
+    instruction,
+    recent.Value.Blockhash,
+    solana.TransactionPayer(c.SolKeysignWrapper.privateKey.PublicKey()),
+  )
+  return solTx, err
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/chain-clients/nonevm/solana/solana-state-sender/index.html b/core/chain-clients/nonevm/solana/solana-state-sender/index.html new file mode 100644 index 0000000..20d3ea1 --- /dev/null +++ b/core/chain-clients/nonevm/solana/solana-state-sender/index.html @@ -0,0 +1,3454 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Solana State Sender - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Solana State Sender

+ +

The solana-state-sender program is named as solana-dojima-bridge. +This program maintains the mapping of registered programs on solana blockchain(Only registered programs can interact with state-sender program). +Solana programs should register and call this state-sender program to interact with other contracts on destination chains.

+
//admin will create the registry - (token mapping)
+   pub fn create_registry(
+ctx: Context<CreateRegistry>, 
+solanaprogaddress: Pubkey,
+dojimatoken: String, 
+authority: Pubkey) -> Result<()> 
+   {
+       if ctx.accounts.user.key() != ctx.accounts.admin.admin {
+           return  err!(MyError::NotOwner);
+       }
+       ctx.accounts.contract_mapping.dojimatokenaddress = dojimatoken;
+       ctx.accounts.contract_mapping.authority = authority;
+       Ok(())
+   }
+   //lock_program(eg;) => (dojimatoken+authority)
+   #[account]
+   pub struct ContractMapping {
+    dojimatokenaddress: String,
+    authority: Pubkey
+   }
+
+
+   #[derive(Accounts)]
+   #[instruction(solanaprogaddress: Pubkey)]
+   pub struct CreateRegistry<'info> {
+    //error handling
+    #[account(mut)]
+    pub user: Signer<'info>,
+    #[account(
+        init,
+        payer = user,
+        seeds = [solanaprogaddress.key().as_ref(), b"dojima_contract_mapping"],
+            bump,
+        space = 8 + 64 + 64,
+    )]
+    pub contract_mapping: Account<'info, ContractMapping>,
+    pub system_program: Program<'info, System>,
+    #[account(
+        seeds = [b"dojima_bridge_admin4"],
+        bump,
+    )]
+    pub admin: Account<'info, Admin>,
+  }
+
+
    +
  • Create_registry - Admin will register the programs and create a contract mapping for every program.
  • +
  • dojimatoken - This is the equivalent of solana token on dojima chain.
  • +
  • authority - PDA of a program which signs to interact with the state-sender contract should be passed as an authority.
  • +
+
pub fn transfer_payload(
+       ctx: Context<TransferPayload>,
+       destination_contract: String,
+       payload: String
+   ) -> Result<()> {
+       //only authority(ie; PDA of locking program) is allowed to call this function
+       if ctx.accounts.contract_mapping.authority.key() != ctx.accounts.user.key() {
+           return  err!(MyError::UnauthorizedContract);
+       }
+       if ctx.accounts.contract_mapping.dojimatokenaddress != destination_contract {
+           return  err!(MyError::UnauthorizedContract);
+       }
+       let nonce =  ctx.accounts.counter.count;
+       ctx.accounts.counter.count += 1;
+       msg!(
+           "{} {} {} {}",
+           "TransferPayload",
+           nonce,
+           destination_contract,
+           payload
+       );
+       Ok(())
+   }
+
+
    +
  • transfer_payload - This function is used to transfer abi-encoded payload to dojima chain contracts.
  • +
  • destination_contract - Which contract to call on the destination chain.
  • +
  • payload - abi-encoded data that should be passed to the destination chain.
  • +
  • A check will be made whether the calling program is registered in the registry or not.
  • +
  • destination_contract should be the same as the registered dojima token address.
  • +
  • Counter keeps track of the number of interactions happening with the state-sender program.
  • +
  • It will increment the counter by one for everytime a transfer_payload (or) token_transfer_from_solana function is called.
  • +
  • After incrementing the counter TransferPayload message(event) is emitted which is filtered by solana-client(narada) and submitted to hermes.
  • +
+
pub fn token_transfer_to_solana(
+ctx: Context<TokenTransferToSolana>, 
+destination_prog_data: Vec<u8>
+) -> Result<()> {
+       //check whether the signer is TSS
+
+
+       //Define seeds for signing
+       let seeds: &[&[u8]] = &[
+           b"dojima_bridge_authority",
+           &[254]
+       ]; 
+       let signer_seeds:&[&[&[u8]]] = &[&seeds[..]];
+
+
+       //unpack accounts
+       let destination_prog = &ctx.accounts.destination_program;
+       let sender_ATA = &ctx.accounts.from_token_account;
+       let receiver_ATA = &ctx.accounts.to_token_account;
+       let tkn_prog = &ctx.accounts.token_program;
+       let auth = &ctx.accounts.authority;
+       let bridge_owner_pda = &ctx.accounts.bridge_owner_pda;
+
+
+       //Construct accoount_metas for CPI invocation
+       let account_metas = vec![
+           AccountMeta::new(ctx.accounts.signing_pda.key(),true),
+           AccountMeta::new(sender_ATA.key(), false),
+           AccountMeta::new(receiver_ATA.key(), false),
+           AccountMeta::new_readonly(tkn_prog.key(), false),
+           AccountMeta::new_readonly(auth.key(), false),
+           AccountMeta::new_readonly(bridge_owner_pda.key(), false),
+       ];
+
+
+       //Instruction identifier of global:execute_state
+       let inst_identifier:Vec<u8> = vec![34, 26, 147, 217, 17, 18, 70, 124];
+
+
+       //Prepare data for CPI
+       let destination_prog_data_len = destination_prog_data.len() as u32;
+       let destnation_prog_data_len_bytes = destination_prog_data_len.to_le_bytes();
+       let mut data = inst_identifier.to_vec();
+       data.extend(destnation_prog_data_len_bytes.to_vec());
+       data.extend(destination_prog_data);
+
+
+
+
+
+       let account_infos = vec![
+           ctx.accounts.signing_pda.to_account_info(),
+           sender_ATA.to_account_info(),
+           receiver_ATA.to_account_info(),
+           tkn_prog.to_account_info(),
+           auth.to_account_info(),
+           bridge_owner_pda.to_account_info(),
+       ];
+
+
+       //Construct instruction
+        let inst = Instruction{
+           program_id: destination_prog.key(),
+           accounts: account_metas,
+           data: data,
+       };
+
+
+       //Invoke CPI
+       invoke_signed(&inst, &account_infos, signer_seeds);
+
+
+
+
+       Ok(())
+   }
+
+
    +
  • token_transfer_to_solana - This function will be used by cross-chain dapp developers to transfer (or) mint SPL tokens from the destination chain.
  • +
  • destination_prog_data - Encoded byte data that is passed from destination chain(Developer can choose the way data gets encoded on destination chain.)
  • +
  • All the accounts and encoded byte data passed from the destination chain are unpacked in this function and sent to a given destination contract on solana.
  • +
  • The unpacked data will be passed to the execute_state function of the destination contract(Destination contract should implement execute_state function).
  • +
  • Prepare the required data to construct instruction and CPI is done using invoke_signed.
  • +
  • The instruction will be signed using a PDA derived from defined seeds.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/concepts/code.liberies/index.html b/core/concepts/code.liberies/index.html new file mode 100644 index 0000000..13d00df --- /dev/null +++ b/core/concepts/code.liberies/index.html @@ -0,0 +1,3365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Code Libraries - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/concepts/connecting.doj.chain/index.html b/core/concepts/connecting.doj.chain/index.html new file mode 100644 index 0000000..b7ec282 --- /dev/null +++ b/core/concepts/connecting.doj.chain/index.html @@ -0,0 +1,3503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Connecting to HERMESChain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Connecting Doj Chain

+ +

How to connect to Hermesgard, HERMESNode and the base Tendermint layer.

+

The Network Information comes from four sources:

+
    +
  1. HERMESNode: Raw blockchain data provided by the HERMESChain state machine. HERMESChain wallets and block explorers will query HERMESChain-specific information here.
  2. +
  3. Cosmos RPC: Used to query for generic CosmosSDK information.
  4. +
  5. Tendermint RPC: Used to query for consensus-related information.
  6. +
+

Cosmos RPC

+

The Cosmos RPC allows Cosmos base blockchain information to be returned. However, not all endpoints have been enabled.

+

Endpoints guide

+

https://v1.cosmos.network/rpc/v0.45.1

+

Example URL

+

https://api-dev.h4s.dojima.network/cosmos/bank/v1beta1/balances/dojima1nh4y3gqxsn7ymm9t45zwsz3h8p9tm7pev8my62

+

Tendermint RPC

+

The Tendermint RPC allows Tendermint consensus information to be returned.

+

Any Node Ports

+
    +
  • MAINNET Port: 27147
  • +
  • STAGENET Port: 26657
  • +
  • TESTNET Port: 26657
  • +
+

Endpoints guide

+

https://docs.tendermint.com/master/rpc/#/

+ +

https://rpc-dev.h4s.dojima.network/

+

P2P

+

P2P is the network layer between nodes, useful for network debugging.

+

TESTNET Port: 26656

+

P2P Guide

+

https://docs.tendermint.com/master/spec/p2p/

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/concepts/querying/index.html b/core/concepts/querying/index.html new file mode 100644 index 0000000..053c3f0 --- /dev/null +++ b/core/concepts/querying/index.html @@ -0,0 +1,3466 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Querying HERMESChain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Querying

+ +

How to Query HERMESChain

+

Getting the Fortunas Vault

+

Vaults are fetched from the /inbound_addresses:

+

https://api-dev.h4s.dojima.network/hermeschain/inbound_addresses

+

You need to select the address of the Chain the inbound transaction will go to.

+

The address will be the current active Fortunas Address that accepts inbounds. Do not cache these address as they change regularly.

+

Example Output, each connected chain will be displayed.

+
[
+    {
+        "chain": "BTC",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "tb1qnh4y3gqxsn7ymm9t45zwsz3h8p9tm7pejmmxf5",
+        "halted": false,
+        "gas_rate": "2000000"
+    },
+    {
+        "chain": "BNB",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "tbnb1nh4y3gqxsn7ymm9t45zwsz3h8p9tm7pezkgkh4",
+        "halted": false,
+        "gas_rate": "2000000"
+    },
+    {
+        "chain": "ETH",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "0xd526d5f47f863eff32b99bc4f9e77ddb4bd2929b",
+        "router": "0x1e87989b0792c236c383Aa498E52770015af66cf",
+        "halted": false,
+        "gas_rate": "30"
+    },
+    {
+        "chain": "AR",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "2txTDSdb_RjG12uHZlVsB5jrfPzqxtzScKTtPef2KZ0",
+        "halted": false,
+        "gas_rate": "1412964922"
+    },
+    {
+        "chain": "SOL",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "82iP5jLLyiuTHbQRrSwUgZ6sKycT2mjbNkncgpm7Duvg",
+        "halted": false,
+        "gas_rate": "15000"
+    },
+    {
+        "chain": "DOT",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "5H16DLfWFLdpm5C4f9Qr6UkADsT1PtD9jELWF9WKuiC7St1T",
+        "halted": false,
+        "gas_rate": "2000000"
+    }
+]
+
+
+

Warning

+

If a chain has a router on the inbound address endpoint, then everything must be deposited via the router. The router is a contract that the user first approves, and the deposit call transfers the asset into the network and emits an event to HERMESChain.

+

This is done because “tokens” on protocols don’t support memos on-chain, thus need to be wrapped by a router which can force a memo.

+

Note: you can transfer the base asset, eg ETH, directly to the address and skip the router, but it is recommended to deposit everything via the router.

+
{
+        "chain": "ETH",
+        "pub_key": "dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f",
+        "address": "0xd526d5f47f863eff32b99bc4f9e77ddb4bd2929b",
+        "router": "0x1e87989b0792c236c383Aa498E52770015af66cf",
+        "halted": false,
+        "gas_rate": "30"
+    },
+
+
+
+

Danger

+

Never cache vault addresses, they churn regularly.

+
+
+

Danger

+

Check for the halted parameter and never send funds if it is set to true

+
+

Chain: Chain Name

+

Address: Fortunas Vault inbound address for that chain.,

+

Halted: Boolean, if the chain is halted. This should be monitored.

+

gas_rate: rate to be used, e.g. in Stats or GWei. See Fees.

+
+

Info

+

Only pools with “status”: “available” are available to trade

+
+
+

Info

+

Make sure to manually add Native $DOJ as a swappable asset.

+
+
+

Info

+

“assetPrice” tells you the asset’s price in DOJ (DOJ Depth/AssetDepth ). In the above example +1 BNB.BTCB-1DE = 11,205 DOJ

+
+

Decimals and Base Units

+

All values on HERMESChain are given in 1e8 eg, 100000000 base units (like Bitcoin), and unless postpended by “USD”, they are in units of DOJ. Even 1e18 assets, such as ETH.ETH, are shortened to 1e8. 1e6 Assets like ETH.USDC, are padded to 1e8. HERMESNode will tell you the decimals for each asset, giving you the opportunity to convert back to native units in your interface.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/concepts/transaction.memos/index.html b/core/concepts/transaction.memos/index.html new file mode 100644 index 0000000..a9dc4ba --- /dev/null +++ b/core/concepts/transaction.memos/index.html @@ -0,0 +1,4117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Transaction Memos - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Transaction Memos

+ +

Transaction Memo Details

+

Overview

+

A memo serves as additional data attached to a transaction, facilitating the communication of user intent to the Hermes Chain. +The memo field signifies the type of transaction being executed, such as SWAP, WITHDRAW, or RESERVE, among others. +Hermes Chain inspects the transaction object as well as the MEMO in order to process the transaction. +It is essential to ensure that both the memo and the transaction are valid; otherwise, Hermes Chain will automatically refund the assets.

+

Different chains employ various methods to include state information within a transaction. Long assets can be shortened using Asset abbreviations (below) +as well as Hermes Names to reduce the size of destination/affiliate addresses.

+

Format

+

Memos follow the format:

+

TYPE:PARAM1:PARAM2:PARAM3:PARAM4

+

The type is invoked by a string, which in turn calls a particular handler in the state machine. The state machine parses the memo looking for the parameters which is simply decodes from human-readable strings.

+

In addition, some parameters are optional. Simply leave them blank, but retain the : separator:

+

TYPE:PARAM1:::PARAM4

+

Permitted Memos

+

The following memos are permitted:

+
    +
  1. SWAP
  2. +
  3. ADD Liquidity
  4. +
  5. WITHDRAW Liquidity
  6. +
  7. BOND, UNBOND & LEAVE
  8. +
  9. DONATE & RESERVE
  10. +
  11. NOOP
  12. +
+

Swap

+

Perform a swap.

+

SWAP:ASSET:DESTADDR:LIM:AFFILIATE:FEE

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadSend the asset to swap.Must be an active pool on Hermes Chain.
SWAPThe swap handleralso s, =
:ASSETThe asset identifier.Can be shortened.
:DESTADDRThe destination address to send to.Can use HERMESName.
:LIMThe trade limit ie, set 100000000 to get a minimum of 1 full asset, else a refund.Optional, 1e8 format
:AFFILIATEThe affiliate address. DOJ is sent to Affiliate.Optional. Must be HERMESName or HERMES Address.
:FEEThe affiliate fee. Limited from 0 to 1000 Basis PointsOptional
+

Examples

+

SWAP:ASSET:DESTADDR simply swap

+

=:ASSET:DESTADDR:LIM swap with limit

+

s:ASSET:DESTADDR:LIM:AFFILIATE:FEE swap with limit and affiliate

+

=:DOJIMA.DOJ:dojima1el4ufmhll3yw7zxzszvfakrk66j7fx0tvcslym:19779138111

+

s:BNB/BUSD-BD1:dojima15s4apx9ap7lazpsct42nmvf0t6am4r3w0r64f2:628197586176

+

Adding and Removing Liquidity

+

Entering and Leaving a Pool

+

To deposit assets on Hermes Chain, you need a compatible wallet with your assets connected to one of the many User Interfaces. +Liquidity providers can add liquidity to any of the active or pending pools. There is no minimum deposit amount, however, +your deposit will have to cover the deposit and later a withdrawal fee costs. The ability to manage and withdraw assets is completely noncustodial +and does not require any KYC or permission process. Only the original depositor has the ability to withdraw them (based on the address used to deposit the assets). +Note, every time you add liquidity, Impermanent Loss Protection time resets.

+

While Symmetrically additions are recommended, Asymmetrical additions are supported, below are the rules:

+

If you add symmetrically first;

+
    +
  • +

    You will be able to add asymmetrically with DOJ later

    +
  • +
  • +

    You will be able to add asymmetrically with ASSET later but it would create a new LP position

    +
  • +
  • +

    You will be able to add symmetrically later

    +
  • +
+

If you add asymmetrically with ASSET first;

+
    +
  • +

    You will be able to add asymmetrically with DOJ later but it would create a new LP position

    +
  • +
  • +

    You will be able to add asymmetrically with ASSET later

    +
  • +
  • +

    You will be able to add symmetrically later but it would create a new LP position

    +
  • +
+

If you add asymmetrically with DOJ first:

+
    +
  • You will be able to add asymmetrically with DOJ later
  • +
  • You will be able to add asymmetrically with ASSET later but it would create a new LP position
  • +
  • You will not be able to add symmetrically later
  • +
+

ILP: How Hermes Chain protects its Liquidity Providers

+

Liquidity Providers will receive 100% Impermanent Loss Protection (ILP) after they have been in the pool for 100 days, getting 1% coverage for each day in the pool. Essentially this means you are adding 1% protection for every day that you provide liquidity. 49 days provided = 49% IL protection, 100 days = 100% IL protection.

+

Impermanent Loss Protection (ILP) ensures that you will not be worse off providing liquidity into Hermes Chain than just holding two assets, DOJ and ASSET, in your wallet. Protection is always recorded and applied symmetrically to both assets after the deposit is rebalanced to 50/50. Impermanent Loss Protection can also be thought of as deposit protection compared to holding both assets. Minimum withdrawal value will be the same as if you held both assets.

+

NOTE: The coverage will reset every time you add liquidity to the same pool and withdrawal fees will affect the withdrawal amount. Partial withdrawals do not reset the ILP counter.

+

Add Liquidity

+

There are rules for adding liquidity, see the rules here and regardless of how it is added, it is subject to Impermanent Loss Protection.

+

ADD:POOL:PAIREDADDR:AFFILIATE:FEE

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadThe asset to add liquidity with.Must be supported by Hermes Chain.
ADDThe Add Liquidity handler.also a, +
:POOLThe pool to add liquidity to.Can be shortened.
:PAIREDADDRThe other address to link with. If on external chain, link to HERMES address. If on Hermes Chain, link to external address. If a paired address is found, the LP is matched and added. If none is found, the liquidity is put into pending.Optional. If not specified, a single-sided add-liquidity action is created.
:AFFILIATEThe affiliate address. The affiliate is added in to the pool as an LP.Optional. Must be HERMESName or HERMES Address.
:FEEThe affiliate fee. Fee is allocated to the affiliate.Optional. Limited from 0 to 1000 Basis Points.
+

Examples

+

ADD:POOL single-sided add liquidity. If this is a position’s first add, liquidity can only be withdrawn to the same address.

+

+:POOL:PAIREDADDR add on both sides.

+

a:POOL:PAIREDADDR:AFFILIATE:FEE add with affiliate

+

+:BTC.BTC:

+

Withdraw Liquidity

+

Withdraw liquidity from a pool.

+

A withdrawal can be either dual-sided (wtihdrawn based on pool’s price) or entirely single-sided (converted to one side and sent out).

+

WITHDRAW:POOL:BASISPOINTS:ASSET

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadSend just enough of the asset to cause the transaction to be picked up by Hermes Chain.Caution Dust Limits: BTC,BCH,LTC chains 10k sats; DOGE 1m Sats; ETH 0 wei; HERMES 0 DOJ.
WITHDRAWThe withdraw handler.also -, wd
:POOLThe pool to withdraw liquidity fromCan be shortened.
:BASISPOINTSBasis points (0-10000, where 10000=100%)
:ASSETSingle-sided withdraw to one side.Optional. Can be shortened. Must be either DOJ or the ASSET.
+

Examples

+

WITHDRAW:POOL:10000 dual-sided 100% withdraw liquidity. If a single-address position, this withdraws single-sidedly instead.

+

-:POOL:1000 dual-sided 10% withdraw liquidity.

+

wd:POOL:5000:ASSET withdraw 50% liquidity as the asset specified while the rest stays in the pool, eg: +wd:BTC.BTC:5000:BTC.BTC

+ +

Donate to a pool or the RESERVE.

+

DONATE:POOL

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadThe asset to donate to a Hermes Chain pool.Must be supported by Hermes Chain. Can be DOJ or ASSET.
DONATEThe donate handler.also %
:POOLThe pool to withdraw liquidity from.Can be shortened.
+

RESERVE

+ + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadHERMES.DOJThe DOJ to credit to the RESERVE.
RESERVEThe reserve handler.
+

BOND, UNBOND & LEAVE

+

Perform node maintenance features.

+

BOND:NODEADDR:PROVDER:FEE

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadThe asset to bond to a Node.Must be DOJ.
BONDThe bond handler.Anytime
:NODEADDRThe node to bond with.
:PROVIDERWhitelist in a provider.Optional, add a provider
:FEESpecify an Operator Fee in Basis Points.Optional, default will be the mimir value (2000 Basis Points). Can be changed anytime.
+

UNBOND:NODEADDR:AMOUNT

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadNone requiredUse MsgDeposit
UNBONDThe unbond handler.
:NODEADDRThe node to unbond from.Must be in standby only.
:AMOUNTThe amount to unbond.In 1e8 format. If setting more than actual bond, then capped at bond.
+

LEAVE:NODEADDR

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadNone requiredUse MsgDeposit
LEAVEThe leave handler.
:NODEADDRThe node to force to leave.If in Active, request a churn out to Standby for 1 churn cycle. If in Standby, forces a permanent leave.
+

Examples

+

BOND:hermes1xd4j3gk9frpxh8r22runntnqy34lwzrdkazldh

+

LEAVE:hermes18r8gnfm4qjak47qvpjdtw66ehsx49w99c5wewd

+

NOOP

+

Dev-centric type to fix Hermes Chain state. Caution: may cause loss of funds if not done exactly right at the right time.

+

NOOP

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterNoteConditions
PayloadThe asset to credit to a vault.Must be ASSET or DOJ.
NOOPThe noop handlerAdds to the vault balance, but does not add to the pool.
:NOVAULTDo not credit the vault.Optional. Just fix the insolvency issue.
+

Refunds

+

The following are the conditions for refunds:

+ + + + + + + + + + + + + + + + + + + + + +
ConditionsNote
Invalid MEMOIf the MEMO is incorrect the user will be refunded.
Invalid AssetsIf the asset for the transaction is incorrect (adding an asset into a wrong pool) the user will be refunded.
Exceeding Price LimitIf the final value achieved in a trade differs to expected, they are refunded.
+

Refunds cost fees to prevent Denial of Service attacks. The user will pay the correct outbound fee for that chain.

+

Asset Notation

+

The following is the notation for Assets in Hermes Chain’s system:

+

medium

+

Note: CHAIN.ASSET denotes native asset. CHAIN/ASSET denotes a Synthetic Asset

+

Examples

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AssetsNotation
BitcoinBTC.BTC (Native)
BitcoinBTC/BTC (Synth)
EthereumETH.ETH
USDTETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7
BNBBNB.BNB (Native)
BNBBNB/BNB (Synth)
DOJ (BEP2)BNB.DOJ-B1A
DOJ (NATIVE)HERMES.DOJ
+

Asset Abbreviations

+

Assets can be abbreviated using fuzzy logic. The following will all be matched appropriately. If there are conflicts then the deepest pool is matched. (To prevent attacks).

+ + + + + + + + + + + + + + + + + + + + +
Notation
ETH.USDT
ETH.USDT-ec7
ETH.USDT-6994597c13d831ec7
ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7
+

Mechanism for Transaction Intent

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ChainMechanismNotes
BitcoinOP_RETURNLimited to 80 bytes.
EthereumSmart Contract InputUse deposit(vault, asset, amount, memo)function, where memo is string
Binance ChainMEMOEach transaction has an optional memo, limited to 128 bytes.
MoneroExtra DataEach transaction can have attached extra data field, that has no limits.
+

Each chain will have a unique way of adding state to a transaction. Long assets can be shortened using Asset abbreviations (below) as well as HERMESNames to reduce the size of destination/affiliate addresses.​

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/arweave/index.html b/core/d11kguide/arweave/index.html new file mode 100644 index 0000000..9da9e34 --- /dev/null +++ b/core/d11kguide/arweave/index.html @@ -0,0 +1,3808 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Arweave - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/arweave

+

Modules

+
    +
  • client - Custom client for communicating with arweave by using arweave
  • +
+

Installation

+
yarn add @d11k-ts/arweave
+
+

Documentation : Basic usage examples

+

Connect wallet to new ArweaveClient

+
    +
  • Create new Arweave client
  • +
  • Network default is Mainnet
  • +
+
// Imports
+import { ArweaveClient } from '@d11k-ts/arweave'
+import { Network } from '@d11k-ts/client'
+
+//Connect wallet, get address and check balance 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const arClient = new ArweaveClient({phrase})
+  // testnet
+  // const arClient = new ArweaveClient({
+  //   phrase,
+  //   network: Network.Testnet,
+  //   config:{
+    //   host: "ar-test.h4s.dojima.network",
+    //   protocol: "https",
+    //   timeout: 100000,
+    // }
+  // })
+  let address = arClient.getAddress()
+  try {
+      const balance = await arClient.getBalance(address)
+      console.log(`Adress: ${address} with balance ${balance}`)
+
+    } catch (error) {
+      console.log(`Caught: ${error} `)
+    }
+}
+
+

Mint testnet ‘ar’ tokens using ArweaveClient

+
    +
  • Create new Arweave client
  • +
  • Network is set to Testnet
  • +
  • By default 2 AR tokens were added to address on every call
  • +
  • Note: Testnet tokens are not useful in Mainnet
  • +
+
//Connect wallet, get address, mint tokens and check balance 
+const mintTokensToWallet = async () => {
+  let phrase = "phrase"
+  // testnet
+  const arClient = new ArweaveClient({
+    phrase,
+    network: Network.Testnet,
+    config:{
+      host: "ar-test.h4s.dojima.network",
+      protocol: "https",
+      timeout: 100000,
+    }
+  })
+  let address = arClient.getAddress()
+  try {
+      await arClient.mintArTokens(address)
+        const balance = await arClient.getBalance(address)
+      console.log(`Address: ${address} with balance ${balance}`)
+
+    } catch (error) {
+      console.log(`Caught: ${error} `)
+    }
+}
+
+

Transfer ar using ArweaveClient

+
    +
  • Create new ArweaveClient instance
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transferAr = async () => {
+  // First initiate ArweaveClient
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  console.log("Building transaction")
+  try {
+    const txid = await arClient.transfer({ 
+      recipient,
+      amount: amountToTransfer
+    })
+    console.log(`Transaction sent: ${txid}`)
+    return txid
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get transaction Data & transaction History

+
    +
  • Create new ArweaveClient instance
  • +
  • Call getTransactionData(hash) returns hash-details
  • +
  • Call getTransactionsHistory(address) returns list of transactions (if any)
  • +
+
// Retrieve transaction data for a particular hash
+const transactionData = async () => {
+  let hash = "insert hash"
+  let Address = arClient.getAddress()
+  try {
+    const txData = await arClient.getTransactionData(
+      hash
+    )
+    console.log(`Transaction data ${txData}`)
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+// Retrieve transaction history for a particular address
+const transactionHistory = async () => {
+  let Address = arClient.getAddress()
+  try {
+    const txHistory = await arClient.getTransactionsHistory({
+      address: Address
+    })
+    console.log(`Found ${txHistory.total.toString()}`)
+    txHistory.txs.forEach(tx => console.log(tx))
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get gas fee for transaction

+
    +
  • Retrieve gas fee for transaction from build tx
  • +
+
const fee = async () => {
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  try {
+    const rawTx = await arClient.createTransaction(
+        recipient, 
+       amountToTransfer
+    )
+    const fees = arClient.getFees(rawTx)
+    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get Arweave Inbound address

+
    +
  • Get Arweave Inbound address from hermes chain
  • +
  • Can be used in adding liquidity pool and swapping
  • +
+
const inboundAddr = async () => {
+  try {
+    const inboundAddress = await arClient.getArweaveInboundAddress()
+    console.log('Inbound Address :: ', inboundAddress)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get default liquidity pool gas fee

+
    +
  • Get Arweave default liquidity pool gas fee from hermes chain
  • +
+
const defaultLPGasFee = async () => {
+  try {
+    const LPDefaultGasFee = await arClient.getDefaultLiquidityPoolGasFee()
+    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Add AR token into liquidity pool

+
    +
  • Add AR tokens into liquidity pool
  • +
  • Get Arweave Inbound address from hermes chain
  • +
+
const addARToLiquidityPool = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await arClient.getArweaveInboundAddress()
+  try {
+    const liquidityPoolHash = await arClient.addLiquidityPool(
+      amountToTransfer,
+      inboundAddress,
+      dojAddress,           // optional dojima address
+    )
+    console.log('Liquidity pool hash : ', liquidityPoolHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Swap AR tokens

+
    +
  • Swap AR tokens to required token using receiver address
  • +
  • Get Arweave Inbound address from hermes chain
  • +
  • Supported tokens for swapping - ‘DOT’, ‘DOJ’, ‘ETH’, ‘SOL’
  • +
+
import {SwapAssetList} from '@d11k-ts/utils'
+
+const swapAR = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await arClient.getArweaveInboundAddress()
+  try {
+    const swapHash = await arClient.swap(
+       amountToTransfer,
+      SwapAssetList,
+      inboundAddress,
+      reciepient                // Respective receiver SwapAssetList token address
+    )
+    console.log('Swap tx hash : ', swapHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Example Code

+

For sample code check out example test case in Arweeave

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/binance-becon/index.html b/core/d11kguide/binance-becon/index.html new file mode 100644 index 0000000..e192ee7 --- /dev/null +++ b/core/d11kguide/binance-becon/index.html @@ -0,0 +1,3671 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binance-Beacon - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/binance-beacon

+

Modules

+ +

Installation

+
yarn add @d11k-ts/binance-beacon
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/binance-beacon.

+
yarn add @binance-chain/javascript-sdk
+
+

Service Providers

+

This package uses the following service providers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionServiceNotesRate limits
BalancesBinance Dexhttps://docs.binance.org/api-reference/dex-api/paths.html#apiv1accountaddress5 requests per IP per second.
Transaction historyBinance Dexhttps://docs.binance.org/api-reference/dex-api/paths.html#apiv1transactions60 requests per IP per minute
Transaction details by hashBinance Dexhttps://docs.binance.org/api-reference/dex-api/paths.html#apiv1txhash10 requests per IP per second
Transaction feesBinance Dexhttps://docs.binance.org/api-reference/dex-api/paths.html#apiv1fees1 request per IP per second
Transaction broadcastBinance Dexhttps://docs.binance.org/api-reference/dex-api/paths.html#apiv1broadcast5 requests per IP per second
ExplorerBinance Dex Explorerhttps://explorer.binance.org
+

This package gets the node information (https://docs.binance.org/api-reference/dex-api/paths.html#apiv1node-info) to +transfer tokens.

+

Documentation : Basic Usage Example

+

Connect wallet to new Binance-beacon Chain Client

+
    +
  • Create new BinanceBeaconChain client
  • +
  • Network default is Mainnet
  • +
+
//Imports 
+import {BinanceBeaconClient} from '@d11k-ts/binance-beacon'
+import {Network} from '@d11k-ts/client'
+import {AssetBNB, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'
+
+// Connect wallet to new btc client 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // mainnet
+  const bnbClient = new BinanceBeaconClient({phrase})
+  // testnet
+  // const bnbClient = new BinanceBeaconClient({ phrase, network: Network.Testnet })
+  let address = bnbClient.getAddress()
+  console.log(`Asset Address is: ${address}`)
+
+  let balances = await bnbClient.getBalance(address, [AssetBNB])
+  try {
+    let assetAmount = (baseToAsset(balances[0].amount)).amount()
+    console.log(`with balance: ${assetAmount}`)
+  } catch (error) {
+    console.log('no balance')
+  }
+}
+
+

Transfer bnb using Binance-beacon Client

+
    +
  • Default feeRate is fast
  • +
  • Create new Binance-beaconClient instance
  • +
  • Convert amount to transfer to base amount
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transferBnb = async () => {
+  // First initiate BinanceBeaconClient
+  let amountToTransfer = 0.0001
+  let recipient = 'insert address'
+  let amount = assetToBase(assetAmount(amountToTransfer, 8))
+  console.log("Building transaction")
+  try {
+    const txid = await bnbClient.transfer({
+      "amount": amount,
+      "recipient": recipient,
+      "memo": "memo",             // optional
+      "walletIndex": 0,            // optional (default)
+      "asset": AssetBNB,          // optional (default)
+
+    })
+    console.log(`Amount ${amount.amount().toString()} ${AssetBNB.symbol} TransactionId: ${txid}`)
+  } catch (error) {
+    console.log(`Transfer failed: ${error}`)
+  }
+}
+
+

Get transaction Data & transaction History

+
    +
  • Create new Binance-beaconClient instance
  • +
  • Call getTransactionData(hash) returns hash-details
  • +
  • Call getTransactions(address) returns list of transactions (if any)
  • +
+
let hash = "insert hash string"
+try {
+  const txData = await bnbClient.getTransactionData(hash)
+  console.log(txData)
+
+} catch (error) {
+  console.log(`Error: ${error}`)
+}
+
+// Retrieve transaction history for a set address
+// txHistoryParams > address, offset, startTime, asset? 
+try {
+  const txHistory = await bnbClient.getTransactions({address: Address, limit: 4})
+  console.log(`Found ${txHistory.total.toString()}`)
+  txHistory.txs.forEach(tx => console.log(tx))
+
+} catch (error) {
+  console.log(`Error: ${error}`)
+}
+
+

Get transfer fees

+
    +
  • Bnb has fixed fee client, average, fast and fastest return the same value.
  • +
  • getFees() returns current fees for the network
  • +
+
try {
+  const fee = await bnbClient.getFees()
+  console.log(`Fees average:  ${baseToAsset(fee.average).amount()}`)
+  console.log(`Fees fast:  ${baseToAsset(fee.fast).amount()}`)
+  console.log(`Fees fastest:  ${baseToAsset(fee.fastest).amount()}`)
+
+} catch (error) {
+  console.log(error)
+}
+
+

Example Code

+

For sample code check out example test case in Binance-Beacon

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/bitcoin/index.html b/core/d11kguide/bitcoin/index.html new file mode 100644 index 0000000..88be7cf --- /dev/null +++ b/core/d11kguide/bitcoin/index.html @@ -0,0 +1,3732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Bitcoin - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/bitcoin

+

Modules

+
    +
  • client - Client for communicating with Bitcoin using BIP39 + , bitcoinjs-lib and WIF
  • +
  • types - TypeScript type definitions based on @d11k-ts/client and @d11k-ts/utils
  • +
  • utils - Utitilies for using haskoin and sochain endpoints in Bitcoin client
  • +
+

Installation

+
yarn add @d11k-ts/bitcoin
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/bitcoin.

+
yarn add axios coinselect
+
+

Service Providers

+

This package uses the following service providers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionServiceNotes
BalancesSochainhttps://chain.so/api/v2#get-balance
Transaction historySochainhttps://chain.so/api/v2#get-display-data-address, https://chain.so/api/v2#get-tx
Transaction details by hashSochainhttps://chain.so/api/v2#get-tx
Transaction feesBitgohttps://app.bitgo.com/docs/#operation/v2.tx.getfeeestimate
Transaction broadcast / utxosSochain / Haskoinhttps://chain.so/api/v2#send-transaction, https://haskoin.ninerealms.com/btc
ExplorerBlockstreamhttps://blockstream.info
+

Sochain API rate limits: https://chain.so/api/v2#rate-limits (300 requests/minute)

+

Bitgo API rate limits: https://app.bitgo.com/docs/#section/Rate-Limiting (10 requests/second)

+

Haskoin API : https://haskoin.ninerealms.com/btc

+

Documentation : Basic Usage Example

+

Connect wallet to new BitcoinClient

+
    +
  • Create new Bitcoin client
  • +
  • Network default is Mainnet
  • +
+
//Imports
+import {BTC_DECIMAL, BitcoinClient} from '@d11k-ts/bitcoin'
+import {Network} from '@d11k-ts/client'
+import {AssetBTC, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'
+
+// Connect wallet to new btc client 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const btcClient = new BitcoinClient({phrase})
+  // testnet
+  // const bnbClient = new BitcoinClient({ phrase, network: Network.Testnet })
+  let address = btcClient.getAddress()
+  console.log(`Asset Address is: ${address}`)
+
+  let balances = await btcClient.getBalance(address, [AssetBTC])
+  try {
+    let assetAmount = (baseToAsset(balances[0].amount)).amount()
+    console.log(`Asset address balance: ${assetAmount}`)
+  } catch (error) {
+    console.log('Address has no balance')
+  }
+}
+
+

Transfer btc using BitcoinClient

+
    +
  • Default feeRate is fast
  • +
  • Create new BitcoinClient instance
  • +
  • Convert amount to transfer to base amount
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transfer = async () => {
+  // First initiate BitcoinClient
+  let amountToTransfer = 0.0001
+  let recipient = 'insert address'
+  let amount = assetToBase(assetAmount(amountToTransfer, BTC_DECIMAL))
+  try {
+    const txid = await btcClient.transfer({
+      asset: AssetBTC,
+      recipient: recipient,
+      amount: amount,
+      memo: "payment"         // optional
+    })
+    console.log(`Amount: ${amount.amount().toString()} ${AssetBTC.symbol} Transaction id: ${txid}`)
+  } catch (error) {
+    console.log(`Transfer failed ${error}`)
+  }
+}
+
+

Transfer by setting feeRate

+
    +
  • Build transaction using parameters
  • +
  • Set feeRate in transaction parameters Or use getFeeRates()
  • +
+
//Returns FeeRates > this allows for dynamic feeRate adjustment on selection
+const {fast, fastest, average} = await btcClient.getFeeRates()
+
+try {
+  const txid = await btcClient.transfer({
+    'asset': AssetBTC,
+    'recipient': recipient,
+    'amount': amount,
+    'memo': "test transfer",        // optional
+    feeRate: fast
+  })
+  console.log(`Amount ${baseToAsset(amount).amount()} ${AssetBTC.symbol} Transaction id ${txid}`)
+} catch (error) {
+  console.log(`Transfer failed ${error}`)
+}
+
+

Get Fees & FeeRates estimations

+
//Get Fees - returns FeeOption & fee in BaseAmount 
+` Fees Fast: 0.00001 Fastest: 0.0000468 Average: 0.00001 `
+try {
+  const {fast, fastest, average} = await btcClient.getFees()
+  console.log(`Fees Fast: ${baseToAsset(fast).amount()} Fastest: ${baseToAsset(fastest).amount()} Average: ${baseToAsset(average).amount()}`)
+
+} catch (error) {
+  console.log(error)
+}
+
+//Get FeeRates - returns FeeOption & rate  
+` Fast: 12, Fastest 60, Average: 6 `
+
+try {
+  const {fast, fastest, average} = await btcClient.getFeeRates()
+  console.log(`Fast: ${fast}, Fastest ${fastest}, Average: ${average}`)
+
+} catch (error) {
+  console.log(error)
+}
+
+

Get transaction data

+
    +
  • Create new BitcoinClient instance
  • +
  • Call getTransaction(hash) returns hashDetails
  • +
+
const transactionData = async () => {
+  let hash = "txhash string"
+  try {
+    const txData = await btcClient.getTransactionData(hash)
+    console.log(`From ${JSON.stringify(txData)}`)
+
+  } catch (error) {
+    console.log(`Error: ${error}`)
+  }
+}
+
+

Get Transaction History

+
    +
  • Create new Binance-beaconClient instance
  • +
  • Call getTransactions(address) returns list of transactions (if any)
  • +
+
const transactionHistory = async () => {
+  // Retrieve transaction history for a set address
+  // txHistoryParams > address, offset, startTime, asset?
+  try {
+    const txHistory = await btcClient.getTransactions({address: Address, limit: 4})
+    console.log(`Found ${txHistory.total.toString()}`)
+    txHistory.txs.forEach(tx => console.log(tx))
+
+  } catch (error) {
+    console.log(`Error: ${error}`)
+  }
+}
+
+

Example Code

+

For sample code check out example test case in Bitcoin

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/client/index.html b/core/d11kguide/client/index.html new file mode 100644 index 0000000..9057cdf --- /dev/null +++ b/core/d11kguide/client/index.html @@ -0,0 +1,3370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Client - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

@d11k-ts/client

+

Installation

+
yarn add @d11k-ts/client
+
+

Initialise and set up the client to connect to its necessary third-party services to fulfil basic functionality. The third-party services used must be at a minimum to fulfil the wallet functionality, such as displaying balances and sending transactions.

+

D11K-ts Wallet Client Interface

+

A specification for a generalised interface for crypto wallets clients, to be used by D11K-ts implementations. The client should not have any functionality to generate a key, instead, the asgardex-crypto library should be used to ensure cross-chain compatible keystores are handled. The client is only ever passed a master BIP39 phrase, from which a temporary key and address is decoded.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/cosmos/index.html b/core/d11kguide/cosmos/index.html new file mode 100644 index 0000000..e5ab8a9 --- /dev/null +++ b/core/d11kguide/cosmos/index.html @@ -0,0 +1,3455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Cosmos - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

@d11k-ts/cosmos

+

Cosmos Module for D11K clients

+

Installation

+
yarn add @d11k-ts/cosmos
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/cosmos.

+
yarn add axios @cosmos-client/core@^0.45.13
+
+
+

NOTE : Make sure to install same version of @cosmos-client/core as @d11k-ts/cosmos is using (currently “@cosmos-client/core”: “^0.45.13”, ). In other case things might break.

+
+

Cosmos Client Testing

+
yarn install
+yarn test
+
+

Documentation

+

Yet to be added.

+

Service Providers

+

This package uses the following service providers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionServiceNotes
BalancesCosmos RPChttps://cosmos.network/rpc/v0.37.9 (GET /bank/balances/{address})
Transaction historyCosmos RPChttps://cosmos.network/rpc/v0.37.9 (GET /txs)
Transaction details by hashCosmos RPChttps://cosmos.network/rpc/v0.37.9 (GET /txs/{hash})
Transaction broadcastCosmos RPChttps://cosmos.network/rpc/v0.37.9 (POST /txs)
ExplorerBigDipperhttps://cosmos.bigdipper.live
+

Rate limits: No

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/crypto/index.html b/core/d11kguide/crypto/index.html new file mode 100644 index 0000000..0432814 --- /dev/null +++ b/core/d11kguide/crypto/index.html @@ -0,0 +1,3490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Crypto - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

@d11k-ts/crypto

+

The D11K CRYPTO package is a crypto package used by all D11K clients.

+

D11K-CRYPTO encrypts a master phrase to a keystore. This keystore can then be exported to other D11K wallets or stored securely.

+

Users can export their phrase and import them into other wallets since it is a BIP39 compatible phrase.

+

Installation

+
    +
  • Install @d11k-ts/crypto from npm
  • +
+
yarn add @d11k-ts/crypto
+
+

Build

+
yarn build
+
+

Tests

+
yarn test
+
+

Constants

+
// Crypto Constants for chain
+const cipher = 'aes-128-ctr'
+const kdf = 'pbkdf2'
+const prf = 'hmac-sha256'
+const dklen = 32
+const c = 262144
+const hashFunction = 'sha256'
+const meta = 'd11k-keystore'
+
+

Keystore Type

+
export type Keystore = {
+  address: string,
+  crypto: {
+    cipher: string,
+    ciphertext: string,
+    cipherparams: {
+      iv: string
+    },
+    kdf: string,
+    kdfparams: {
+      prf: string,
+      dklen: number,
+      salt: string,
+      c: number,
+    },
+    mac: string,
+  },
+  id: string,
+  version: number,
+  meta: string,
+}
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/ethereum/index.html b/core/d11kguide/ethereum/index.html new file mode 100644 index 0000000..adf5d4a --- /dev/null +++ b/core/d11kguide/ethereum/index.html @@ -0,0 +1,3694 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Ethereum - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/ethereum

+

Modules

+
    +
  • client - Custom client for communicating with Ethereum by using ethers
  • +
+

Installation

+
yarn add @d11k-ts/ethereum
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/ethereum.

+
yarn add axios ethers
+
+

Service Providers

+

This package uses the following service providers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionServiceNotes
ETH balancesEtherscanhttps://etherscan.io/apis#accounts (module=account, action=balance)
Token balancesEtherscanhttps://etherscan.io/apis#tokens (module=account, action=tokenbalance)
ETH transaction historyEtherscanhttps://etherscan.io/apis#accounts (module=account, action=txlistinternal)
Token transaction historyEtherscanhttps://etherscan.io/apis#accounts (module=account, action=tokentx)
Transaction feesEtherscanhttps://etherscan.io/apis#gastracker (module=gastracker, action=gasoracle)
Transaction broadcastEtherscanhttps://sebs.github.io/etherscan-api/#eth_sendrawtransaction
ExplorerEtherscanhttps://etherscan.io/
+

Etherscan API rate limits: https://info.etherscan.com/api-return-errors/

+ +

Documentation : Basic usage examples

+

Connect wallet to new EthereumClient

+
    +
  • Create new EthereumChain client
  • +
  • Network default is Mainnet
  • +
+
// Imports
+import {Network} from '@d11k-ts/client'
+import {ETH_DECIMAL, EthereumClient} from '@d11k-ts/ethereum'
+import {assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'
+
+//Connect wallet, validate address and check balance 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const ethClient = new EthereumClient({phrase})
+  // testnet
+  // const bnbClient = new EthereumClient({ 
+  //    phrase, 
+  //    network: Network.Testnet,
+  //    etherscanApiKey: 'get-etherscan-api-key',
+  //    ethplorerApiKey: 'get-ethplorer-api-key',
+  //  })
+  let address = ethClient.getAddress()
+  let isValid = ethClient.validateAddress(address)
+  console.log(address)
+  if (isValid === true) {
+    try {
+      const balance = await ethClient.getBalance(address)
+      let assetAmount = (baseToAsset(balance[0].amount)).amount()
+      console.log(`Adress: ${address} with balance ${assetAmount}`)
+
+    } catch (error) {
+      console.log(`Caught: ${error} `)
+    }
+  } else {
+    console.log(`Address: ${address} is invalid`)
+  }
+}
+
+

Transfer eth using EthereumClient

+
    +
  • Create new EthereumClient instance
  • +
  • Convert amount to transfer to base amount
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
// Transfer ethereum other TxParams > feeOptionKey?, gasLimit?, gasPrice? 
+const transferEth = async () => {
+  // First initiate EthereumClient
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  let amount = assetToBase(assetAmount(amountToTransfer, ETH_DECIMAL))
+  console.log("Building transaction")
+  try {
+    const txid = await ethClient.transfer({
+      amount,
+      recipient,
+      "memo": "memo",               // optional
+      "walletIndex": 0,             // optional (default)
+      "asset": AssetETH,            // optional (default)
+    })
+    console.log(`Transaction sent: ${txid}`)
+    return txid
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get transaction Data & transaction History

+
    +
  • Create new EthereumClient instance
  • +
  • Call getTransactionData(hash) returns hash-details
  • +
  • Call getTransactions(address) returns list of transactions (if any)
  • +
+
// Retrieve transaction data for a particular hash
+const transactionData = async () => {
+  let hash = "insert hash"
+  let Address = ethClient.getAddress()
+  try {
+    const txData = await ethClient.getTransactionData(
+      hash,
+      Address         // optional
+    )
+    console.log(`Transaction data ${txData}`)
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+// Retrieve transaction history for a particular address
+const transactionHistory = async () => {
+  let Address = ethClient.getAddress()
+  try {
+    const txHistory = await ethClient.getTransactions({address: Address})
+    console.log(`Found ${txHistory.total.toString()}`)
+    txHistory.txs.forEach(tx => console.log(tx))
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get transfer Fees estimations

+
    +
  • Retrieve estimated gas prices and gas limits from ethereum client
  • +
+
// Retrieve fee estimations from transaction parameters
+const feeEstimations = async () => {
+  let amountToTransfer = 0.001
+  let amount = assetToBase(assetAmount(amountToTransfer, ETH_DECIMAL))
+  let recipient = "insert address"
+  try {
+    const fees = await ethClient.estimateFeesWithGasPricesAndLimits({
+      "amount": amount,
+      "recipient": recipient
+    })
+    console.log(`Fees average : ${baseToAsset(fees.fees.average).amount()}, gas limits: ${fees.gasLimit}, gas prices average: ${baseToAsset(fees.gasPrices.average).amount()}`)
+
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Example Code

+

For sample code check out example test case in Ethereum

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/hermes/index.html b/core/d11kguide/hermes/index.html new file mode 100644 index 0000000..8d16791 --- /dev/null +++ b/core/d11kguide/hermes/index.html @@ -0,0 +1,3714 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Hermes - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/hermes

+

Hermes Module for Dojima chain

+

Installation

+
yarn add @d11k-ts/hermes
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/hermes.

+
yarn add axios @cosmos-client/core@^0.45.13 bech32-buffer@^0.2.1
+
+
+

NOTE: Make sure to install same version of @cosmos-client/core and bech32-buffer as @d11k-ts/cosmos is using ( +currently “@cosmos-client/core”: “^0.45.13”, “bech32-buffer”: “^0.2.1”). In other case things might break.

+
+

Service Providers

+

This package uses the following service providers:

+ + + + + + + + + + + + + + + + + + + + +
NetworkNodeRPC
Testnethttps://api-dev.h4s.dojima.networkhttps://rpc-dev.h4s.dojima.network/
MainnetNANA
+
+

Note : ‘Mainnet’ is currently under process. Not applicable yet.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FunctionServiceNotes
BalancesCosmos RPChttps://cosmos.network/rpc/v0.37.9 (GET /bank/balances/{address})
Transaction historyTendermint RPChttps://docs.tendermint.com/master/rpc/#/Info/tx_search
Transaction details by hashCosmos RPChttps://cosmos.network/rpc/v0.37.9 (GET /txs/{hash})
Transaction broadcastCosmos RPChttps://cosmos.network/rpc/v0.37.9 (POST /txs)
+

Rate limits: No

+

Documentation: Basic usage example

+

Connect wallet to new Hermes Client

+
    +
  • Create new HermesChain client
  • +
  • Network default is Mainnet
  • +
+
// Imports 
+import {Network} from '@d11k-ts/client'
+import {DOJ_DECIMAL, HermesClient} from '@d11k-ts/hermes'
+import {AssetDOJNative, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'
+
+
+// Create new instance of the client and query chain for balances. 
+const connectWallet = async () => {
+
+  let phrase = "phrase"
+  // mainnet
+  const hermesClient = new HermesClient({phrase})
+  // testnet
+  // const hermesClient = new HermesClient({ phrase, network: Network.Testnet })
+
+  let address = hermesClient.getAddress()
+  console.log(`Address: ${address}`)
+  try {
+    const balance = await hermesClient.getBalance(address, [AssetDOJNative])
+    let assetAmount = (baseToAsset(balance[0].amount)).amount()
+    console.log(`With balance: ${assetAmount}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Transfer doj using Hermes Client

+
    +
  • Default feeRate is fast
  • +
  • Create new HermesChain client instance
  • +
  • Convert amount to transfer to base amount
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transferDoj = async () => {
+
+  // First initiate HermesClient
+  let amountToTransfer = 0.1
+  let amount = assetToBase(assetAmount(amountToTransfer, DOJ_DECIMAL))
+  let recipient = "insert address"
+  try {
+    const txid = await hermesClient.transfer({
+      "amount": amount,
+      "recipient": recipient,
+      "memo": "test",             // optional
+      "asset": AssetDOJNative,    // optional (default)
+      "walletIndex": 0            // optional (default)
+    })
+    console.log(`Transaction sent: ${txid}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get transaction Data & transaction History

+
    +
  • Create new HermesClient instance
  • +
  • Call getTransactionData(hash) returns hash-details
  • +
  • Call getTransactions(address) returns list of transactions (if any)
  • +
+
const transactionData = async () => {
+
+  // First initiate HermesClient
+  let hash = "insert hash"
+  let address = hermesClient.getAddress()
+  try {
+    const txData = await hermesClient.getTransactionData(hash, address)
+    console.log(txData)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+// By default getTransactions() returns the transactions for the current address
+// Optional param - any dojima address
+const transactionHistory = async () => {
+  try {
+    const txHistory = await hermesClient.getTransactions(address)
+    console.log(`Found ${txHistory.total}`)
+    txHistory.txs.forEach(tx => console.log(tx.hash))
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get transfer Fees

+
    +
  • Hermeschain runs on fee type of Flatfee set to 0.02 DOJ
  • +
+
// Returns Fees Fast: 0.02 Fastest: 0.02 Average: 0.02
+const fee = async () => {
+
+  // First initiate HermesClient
+  try {
+    const {fast, fastest, average} = await hermesClient.getFees()
+    console.log(`Fees Fast: ${baseToAsset(fast).amount()} Fastest: ${baseToAsset(fastest).amount()} Average: ${baseToAsset(average).amount()}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Deposit doj using Hermes Client

+
    +
  • Create new HermesChain client instance
  • +
  • Convert amount to transfer to base amount
  • +
  • Deposit transaction
  • +
  • Returns txHash as string
  • +
+
import {SwapAssetList} from '@d11k-ts/utils'
+
+const transferDoj = async () => {
+
+  // First initiate HermesClient
+  let amountToTransfer = 0.1
+  let amount = assetToBase(assetAmount(amountToTransfer, DOJ_DECIMAL))
+  // amount: number     Note: convert amount to 'BaseAmount' before passing to transfer function
+  // memo: string
+  'ADD:{SwapAssetList}:{respective-token-address}'
+  'SWAP:{SwapAssetList}:{receiver-token-address}'
+  try {
+    // 'memo' with ADD
+    const txid = await hermesClient.deposit({
+      amount,
+      memo: `ADD:{SwapAssetList}:{respective-token-address}`,
+    })
+    // 'memo' with SWAP
+    // const depositHash = await hermesClient.deposit({
+    //   amount,
+    //   memo: `SWAP:{SwapAssetList}:{receiver-token-address}`,
+    // })
+    console.log(`Deposit tx hash: ${txid}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Example Code

+

For sample code check out example test case in Hermes

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/polkadot/index.html b/core/d11kguide/polkadot/index.html new file mode 100644 index 0000000..8330e34 --- /dev/null +++ b/core/d11kguide/polkadot/index.html @@ -0,0 +1,3721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Polkadot - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/polkadot

+

Modules

+
    +
  • client - Custom client for communicating with polkadot by using @polkadot/api
  • +
+

Installation

+
yarn add @d11k-ts/polkadot
+
+

Documentation : Basic usage examples

+

Connect wallet to new PolkadotClient

+
    +
  • Create new Polkadot client
  • +
  • Network default is Mainnet
  • +
+
// Imports
+import { Network } from '@d11k-ts/client'
+import { PolkadotClient } from '@d11k-ts/polkadot'
+
+//Connect wallet, get address and check balance 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const polkaClient = new PolkadotClient({phrase})
+  // testnet
+  // const polkaClient = new PolkadotClient({ 
+  //    phrase, 
+  //    network: Network.Testnet 
+  //    provider: 'wss://dotws-test.h4s.dojima.network:9944'
+  // })
+  let address = polkaClient.getAddress()
+  try {
+      const balance = await polkaClient.getBalance(address)
+      console.log(`Adress: ${address} with balance ${balance}`)
+
+    } catch (error) {
+      console.log(`Caught: ${error} `)
+    }
+  process.exit()
+}
+
+

Transfer dot using PolkadotClient

+
    +
  • Create new PolkadotClient instance
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transferDot = async () => {
+  // First initiate PolkadotClient
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  console.log("Building transaction")
+  try {
+    const txid = await polkaClient.transfer({ 
+      recipient,
+      amount: amountToTransfer
+    })
+    console.log(`Transaction sent: ${txid}`)
+    return txid
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+  process.exit()
+}
+
+

Get transaction Data & transaction History

+
    +
  • No code for retrieving tx data and history in @d11k-ts/polkadot.
  • +
  • View tx details in explorer
  • +
  • Mainnet : polkadot-subscan
  • +
+

Get gas fee for transaction

+
    +
  • Retrieve gas fee for transaction from build tx
  • +
+
const fee = async () => {
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  try {
+    const fees = polkaClient.getFees({
+      recipient,
+      amount: amountToTransfer
+    })
+    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+  process.exit()
+}
+
+

Get Polkadot Inbound address

+
    +
  • Get Polkadot Inbound address from hermes chain
  • +
  • Can be used in adding liquidity pool and swapping
  • +
+
const inboundAddr = async () => {
+  try {
+    const inboundAddress = await polkaClient.getPolkadotInboundAddress()
+    console.log('Inbound Address :: ', inboundAddress)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+  process.exit()
+}
+
+

Get default liquidity pool gas fee

+
    +
  • Get Polkadot default liquidity pool gas fee from hermes chain
  • +
+
const defaultLPGasFee = async () => {
+  try {
+    const LPDefaultGasFee = await polkaClient.getDefaultLiquidityPoolGasFee()
+    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+  process.exit()
+}
+
+

Add DOT token into liquidity pool

+
    +
  • Add DOT tokens into liquidity pool
  • +
  • Get Polkadot Inbound address from hermes chain
  • +
+
const addDotToLiquidityPool = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await polkaClient.getPolkadotInboundAddress()
+  try {
+    const liquidityPoolHash = await polkaClient.addLiquidityPool(
+      amountToTransfer,
+      inboundAddress,
+      dojAddress,           // optional dojima address
+    )
+    console.log('Liquidity pool hash : ', liquidityPoolHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+  process.exit()
+}
+
+

Swap DOT tokens

+
    +
  • Swap DOT tokens to required token using receiver address
  • +
  • Get Polkadot Inbound address from hermes chain
  • +
  • Supported tokens for swapping - ‘AR’, ‘DOJ’, ‘ETH’, ‘SOL’
  • +
+
import {SwapAssetList} from '@d11k-ts/utils'
+
+const swapDOT = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await polkaClient.getPolkadotInboundAddress()
+  try {
+    const swapHash = await polkaClient.swap(
+       amountToTransfer,
+      SwapAssetList,
+      inboundAddress,
+      reciepient                // Respective receiver SwapAssetList token address
+    )
+    console.log('Swap tx hash : ', swapHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+  process.exit()
+}
+
+

Example Code

+

For sample code check out example test case in Polkadot

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/solana/index.html b/core/d11kguide/solana/index.html new file mode 100644 index 0000000..cb4bead --- /dev/null +++ b/core/d11kguide/solana/index.html @@ -0,0 +1,3795 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Solana - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

@d11k-ts/solana

+

Modules

+
    +
  • client - Custom client for communicating with solana by + using @solana/web3.js
  • +
+

Installation

+
yarn add @d11k-ts/solana
+
+

Following dependencies have to be installed into your project. These are not included in @d11k-ts/solana.

+
yarn add axios
+
+

Documentation : Basic usage examples

+

Connect wallet to new SolanaClient

+
    +
  • Create new Solana client
  • +
  • Network default is Mainnet
  • +
+
// Imports
+import {SolanaClient} from '@d11k-ts/solana'
+import {Network} from "@d11k-ts/client";
+
+//Connect wallet, get address and check balance 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const solClient = new SolanaClient({phrase})
+  // devnet
+  // const solClient = new SolanaClient({
+  //    phrase, 
+  //    network: Network.Stagenet
+  //    endpoint: 'https://sol-test.h4s.dojima.network:8899'
+  // })
+  let address = solClient.getAddress()
+  try {
+    const balance = await solClient.getBalance(address)
+    console.log(`Adress: ${address} with balance ${balance}`)
+
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Request airdrop - testnet ‘sol’ tokens using SolanaClient

+
    +
  • Create new Solana client
  • +
  • Network is set to devnet
  • +
  • By default 2 SOL tokens were added to address on every call
  • +
  • Note: Devnet tokens are not useful in Mainnet
  • +
+
// Imports
+import {SolanaClient} from '@d11k-ts/solana'
+import {Network} from "@d11k-ts/client";
+
+//Connect wallet, get address, request sol tokens and check balance 
+const connectWallet = async () => {
+  let phrase = "phrase"
+  // Mainnet
+  const solClient = new SolanaClient({phrase})
+  // devnet
+  // const solClient = new SolanaClient({
+  //    phrase, 
+  //    network: Network.Stagenet
+  //    endpoint: 'https://sol-test.h4s.dojima.network:8899'
+  // })
+  let address = solClient.getAddress()
+  try {
+    await solClient.requestSolTokens(address)
+    const balance = await solClient.getBalance(address)
+    console.log(`Address: ${address} with balance ${balance}`)
+
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Transfer sol using SolanaClient

+
    +
  • Create new SolanaClient instance
  • +
  • Build transaction
  • +
  • Returns txHash as string
  • +
+
const transferSol = async () => {
+  // First initiate SolanaClient
+  let amountToTransfer = 0.001
+  let recipient = 'insert address'
+  console.log("Building transaction")
+  try {
+    const txid = await solClient.transfer({
+      recipient,
+      amount: amountToTransfer
+    })
+    console.log(`Transaction sent: ${txid}`)
+    return txid
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get transaction Data & transaction History

+
    +
  • Create new SolanaClient instance
  • +
  • Call getTransactionData(hash) returns hash-details
  • +
  • Call getTransactionsHistory(address) returns list of transactions (if any)
  • +
+
// Retrieve transaction data for a particular hash
+const transactionData = async () => {
+  let hash = "insert hash"
+  let Address = solClient.getAddress()
+  try {
+    const txData = await solClient.getTransactionData(
+      hash
+    )
+    console.log(`Transaction data ${txData}`)
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+// Retrieve transaction history for a particular address
+const transactionHistory = async () => {
+  let Address = solClient.getAddress()
+  try {
+    const txHistory = await solClient.getTransactionsHistory({
+      address: Address
+    })
+    console.log(`Found ${txHistory.total.toString()}`)
+    txHistory.txs.forEach(tx => console.log(tx))
+  } catch (error) {
+    console.log(`Caught: ${error} `)
+  }
+}
+
+

Get gas fee for transaction

+
    +
  • Solana has fixed fee client, average, fast and fastest return the same value
  • +
+
const fee = async () => {
+  try {
+    const fees = solClient.getFees()
+    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get Solana Inbound address

+
    +
  • +

    Get Solana Inbound address from hermes chain

    +
  • +
  • +

    Can be used in adding liquidity pool and swapping

    +
  • +
+
const inboundAddr = async () => {
+  try {
+    const inboundAddress = await solClient.getSolanaInboundAddress()
+    console.log('Inbound Address :: ', inboundAddress)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Get default liquidity pool gas fee

+
    +
  • Get Solana default liquidity pool gas fee from hermes chain
  • +
+
const defaultLPGasFee = async () => {
+  try {
+    const LPDefaultGasFee = await solClient.getDefaultLiquidityPoolGasFee()
+    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Add SOL token into liquidity pool

+
    +
  • Add SOL tokens into liquidity pool
  • +
  • Get Solana Inbound address from hermes chain
  • +
+
const addSOLToLiquidityPool = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await solClient.getSolanaInboundAddress()
+  try {
+    const liquidityPoolHash = await solClient.addLiquidityPool(
+      amountToTransfer,
+      inboundAddress,
+      dojAddress,           // optional dojima address
+    )
+    console.log('Liquidity pool hash : ', liquidityPoolHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Swap SOL tokens

+
    +
  • Swap SOL tokens to required token using receiver address
  • +
  • Get Solana Inbound address from hermes chain
  • +
  • Supported tokens for swapping - ‘DOT’, ‘DOJ’, ‘ETH’, ‘AR’
  • +
+
import {SwapAssetList} from '@d11k-ts/utils'
+const swapSOL = async () => {
+  let amountToTransfer = 0.001
+  const inboundAddress = await solClient.getSolanaInboundAddress()
+  try {
+    const swapHash = await solClient.swap(
+      amountToTransfer,
+      SwapAssetList,
+      inboundAddress,
+      reciepient                // Respective receiver SwapAssetList token address
+    )
+    console.log('Swap tx hash : ', swapHash)
+  } catch (error) {
+    console.log(`Caught ${error}`)
+  }
+}
+
+

Example Code

+

For sample code check out example test case in Solana

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/d11kguide/utils/index.html b/core/d11kguide/utils/index.html new file mode 100644 index 0000000..2c4971e --- /dev/null +++ b/core/d11kguide/utils/index.html @@ -0,0 +1,3379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Utils - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

@d11k-ts/utils

+

Utility helpers for D11k clients

+

Modules (in alphabetical order)

+
    +
  • asset - Utilities for handling assets
  • +
  • async - Utilities for async handling
  • +
  • bn - Utilities for using bignumber.js
  • +
  • chain - Utilities for multi-chain
  • +
  • string - Utilities for strings
  • +
+

Installation

+

yarn add @d11k-ts/utils
+
+The following peer dependencies have to be installed into your project. These are not included in @d11k-ts/utils.

+
yarn add bignumber.js
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/dojima-chain/index.html b/core/dojima-chain/index.html new file mode 100644 index 0000000..be98cb1 --- /dev/null +++ b/core/dojima-chain/index.html @@ -0,0 +1,3298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Dojima Chain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Dojima Chain

+ +

“What is Dojima Chain?” +Dojima Chain is an integral layer of the Dojima Network, specifically tailored for seamless integration of assets, NFTs, and DeFi applications across various blockchains. It stands out for its commitment to security, interoperability, and scalability, powered by a decentralized network of validators.

+

The Dojima Chain offers users the unique capability to interact with major tokens from different blockchains directly on its platform. This feature eliminates the need for users to jump between different chains, as all crosschain assets are readily available on the Dojima Chain. This seamless integration and accessibility streamline the user experience, making Dojima Chain a convenient and efficient platform for managing and transacting with a variety of blockchain assets.

+
    +
  1. Seamless Interaction with Major Chains: It allows interaction with tokens from all major chains, providing a platform for protocols to engage comprehensively.
  2. +
  3. Simplified Omnichain DApp Development: The platform makes building omnichain DApps more accessible than ever.
  4. +
  5. Broad Connectivity: Developers can connect any chain to their omnichain DApp on the Dojima Chain, enhancing versatility and reach.
  6. +
  7. Formation of an Omnichain Hub: A central hub is being developed on the Dojima Network, further integrating diverse blockchain ecosystems.
  8. +
+

“Why Dojima Chain is an integral part of web3 expansion”

+

As blockchains become increasingly diverse and specialized, the ability to integrate and interact across these varied platforms becomes crucial. Dojima Chain addresses this by providing a unified, omnichain platform that simplifies the interaction between different blockchain ecosystems, making it essential for developers and users seeking to leverage the strengths of multiple chains in a single application. Its features like interoperability, robust validator network, EVM compatibility, the utility of the Dojima Token, and a fair block producer selection process make it an attractive choice for those looking to develop or use decentralized applications. By facilitating seamless integration and operation across various blockchains, the Dojima Chain stands as a key enabler in the evolution of a more interconnected and efficient blockchain environment.

+

The Dojima Chain, as an essential part of the Dojima Network, offers several key features:

+
    +
  1. Interoperability: By being connected to various blockchain layers, Dojima chain facilitates a unified environment where different blockchain ecosystems can interact seamlessly. This feature is crucial for asset and data integration across multiple platforms.
  2. +
  3. Validator Network: Ensures the security and integrity of transactions within the network. Validators play multiple roles such as block production, transaction validation, and participating in consensus mechanisms, which are vital for maintaining the network’s trustworthiness.
  4. +
  5. EVM Compatibility: Allows developers to deploy and execute smart contracts using popular programming languages like Solidity, making it easier to integrate existing Ethereum-based applications and tools into the Dojima ecosystem.
  6. +
  7. Block Producer Selection: This process is designed to maintain fairness and efficiency in block generation and validation, based on validators’ staked tokens. Block producers are more likely to be elected for block generation based on their stake, with embedded churning and shuffling mechanisms to enhance fairness and security.
  8. +
+

These features collectively contribute to making the Dojima Chain a powerful and versatile platform for the development and operation of decentralized applications, especially in the context of a rapidly evolving blockchain and Web3 landscape.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/hermes-chain/index.html b/core/hermes-chain/index.html new file mode 100644 index 0000000..758980e --- /dev/null +++ b/core/hermes-chain/index.html @@ -0,0 +1,3262 @@ + + + + + + + + + + + + + + + + + + + + + + + Hermes chain - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + +

Omnichain ERC20 Chain

+

OmniChainTokenContract Suite Documentation

+

Overview

+

The OmniChainTokenContract Suite is an advanced toolkit designed for the Dojima chain, facilitating the seamless transfer and management of tokens across multiple blockchain networks, including Ethereum, Solana, and others.

+

Components

+

OmniChainTokenContractActs as the central hub within the Dojima chain, managing the lifecycle of cross-chain tokens.

+

Key Functions:

+

transferToChain: This function enables the transfer of tokens from the Dojima chain to other blockchains. It involves burning tokens on the Dojima chain and initiating a state sync process to mint corresponding tokens on the target chain.

+
outboundStateSender.transferPayload( destinationChain, destinationContractAddress, msg.sender, abi.encode(user, amount, 0) // TODO: add depositId )
+
+

The transferPayload function in the transferToChain method has the following parameters:

+
    +
  • destinationChain: The target chain for the cross-chain transfer.
  • +
  • destinationContractAddress: This is the address of the contract on the target blockchain that will receive and process the payload. It’s usually the address of a smart contract that has a function to handle such incoming payloads.
  • +
  • msg.sender: This is the address of the entity (usually a user or another contract) that initiated the token transfer on the Dojima chain.
  • +
  • abi.encode(user, amount, 0): This is the payload that is being transferred to the target blockchain. It’s encoded using Ethereum’s ABI (Application Binary Interface) encoding. The payload includes:
  • +
  • user: The address of the user who will receive the tokens on the target blockchain
  • +
  • amount: The amount of tokens to be transferred.
  • +
  • 0: This is a placeholder for the depositId. It’s currently set to 0 as indicated by the TODO comment. The depositId could be used to track or identify individual token transfer operations.
  • +
+

onStateReceive: Executed by the _stateVerifier (Dojima system account), this function handles the minting of tokens on the Dojima chain based on the state received from other chains. It decodes the user address, amount, and deposit ID from the received encoded data.

+

Roles and Security:

+

_stateVerifier Role: A system-controlled account with exclusive rights to mint tokens on the Dojima chain, ensuring security in the token minting process.

+

Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.

+

XTokenContractAn ERC20 token contract on the Dojima chain, foundational for the cross-chain functionalities.

+ +

System Integration

+

OutboundStateSender

+

Functionality: The OutboundStateSender’s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) to the Dojima chain’s OmniChainTokenContract.

+

Significance: Ensures the synchronization of token states across chains, triggering corresponding actions (burn or mint) in the connected contracts.

+

Usage in transferToChain:

+
 outboundStateSender.transferPayload(
+   destinationChain,
+   destinationContractAddress,
+   msg.sender,
+   abi.encode(user, amount, 0) )
+
+
+

Info

+
+

Read More about how to interact with outbound state sender

+
+

Warning

+
+

*Note: The outboundStateSender contract is very crucial for the cross chain transfer make sure you follow the steps mentioned in the doc.## Contract Interaction Flow1. **Burning Tokens for Transfer: In transferToChain, tokens are burned on the Dojima chain to initiate cross-chain transfer.2. State Synchronization: The burning triggers a state sync process via the Hermes bridge, sending encoded data to the target chain.3. Minting Tokens on Dojima: In onStateReceive, tokens are minted on the Dojima chain for the specified user, amount, and deposit ID.## Security and Best PracticesAudit Compliance: Ensure all contracts undergo thorough security audits.Transaction Monitoring: Implement systems to monitor and verify cross-chain transactions regularly.Role Management: Strictly manage role assignments, especially for critical roles like _stateVerifier.**Gas Optimization**: Aim for efficiency in contract execution to minimize transaction costs.## ConclusionThe OmniChainTokenContract Suite represents a significant step towards seamless blockchain interoperability, with a focus on security, efficiency, and developer-friendliness. It is crucial for developers to understand the intricacies of the suite to leverage its full potential in their DApp development.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/index.html b/core/index.html new file mode 100644 index 0000000..ec071e5 --- /dev/null +++ b/core/index.html @@ -0,0 +1,3318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Core - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/sources/endpoints/index.html b/core/sources/endpoints/index.html new file mode 100644 index 0000000..058f5fb --- /dev/null +++ b/core/sources/endpoints/index.html @@ -0,0 +1,3430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Network Endpoints - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Network EndPoints

+ +

Testnet

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTestnet
Network NameHermes Dojima
Http Api URLhttps://api-dev.h4s.dojima.network/
New RPC URLhttps://rpc-dev.h4s.dojima.network/
Chain IDhermes-testnet
Currency symbolDOJ
+

Stagenet

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTestnet
Network NameHermes Dojima
Http Api URLhttps://api.h4s.dojima.network/
New RPC URLhttps://rpc.h4s.dojima.network/
Chain IDhermeschain-stagenet
Currency symbolDOJ
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/sources/faucet/index.html b/core/sources/faucet/index.html new file mode 100644 index 0000000..8ad304c --- /dev/null +++ b/core/sources/faucet/index.html @@ -0,0 +1,3499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Faucet - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Faucet

+ +

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

+

Prerequisites

+

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don’t have a seed phrase, follow these steps.

+

To request tokens using the faucet.

+

1. Before requesting TestNet tokens check the table for available faucet balances.

+

medium

+

2.  Select the Hermes token and copy the address.

+

medium

+

3. Choose a chain for token requests.

+

medium

+

4. Paste address in the address input or use self address checkbox.

+

medium

+

medium

+

5. Click the “submit” button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.

+

medium

+

6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.

+

medium

+

Stagenet

+

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/sources/transaction/index.html b/core/sources/transaction/index.html new file mode 100644 index 0000000..7d10aa5 --- /dev/null +++ b/core/sources/transaction/index.html @@ -0,0 +1,3538 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Transactions - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Transaction

+ +

Guide to sending a Dojima coin to any account

+

1. First, log into your Dojima Wallet. If you don’t have a seed phrase, follow these steps.

+
+

Info

+

If you don’t have Hermes Tokens, proceed to FAUCET to get testnet tokens.

+
+

2. Click on Send and Receive option.

+

medium

+

3. To send digital assets, just click on the “SEND” option beside your chosen token.

+

medium

+

4. Specify the amount of the token you want to transfer..

+

medium

+

5. To input an amount in USD, users should toggle the “Input USD” option on and then enter the desired amount in USD..

+

medium

+

6. To proceed with the sending process, users must input the recipient’s public address..

+

medium

+

7.Select the gas fee, users have the option to choose between fast, average, and slow gas fees and click on Continue.

+

medium

+

medium

+

8. The next step is the review page, where users can carefully examine all transaction details, including the amount they are sending, the chosen gas fee, and the total amount they are paying. If they wish to make any changes, they can click on the “EDIT” option. Otherwise, they should proceed by clicking on the “SEND” option to complete the transaction.

+

medium

+

8. That’s it! The transaction is complete. For more details on the transaction, users can click on the “View on Explorer” option.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/what-is-dojima-network/index.html b/core/what-is-dojima-network/index.html new file mode 100644 index 0000000..d59b7c4 --- /dev/null +++ b/core/what-is-dojima-network/index.html @@ -0,0 +1,3287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + What is Dojima Network? - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

What is Dojima Network?

+ +

Dojima Network is an omnichain Layer-1 designed to integrate the diverse Web3 ecosystem into a single, unified layer that revolutionizes the way decentralized applications (DApps) are developed and utilized across multiple blockchain networks.

+

It introduces a unique architecture composed of two primary components:

+
    +
  1. DojimaChain: An EVM-compatible blockchain that acts as a middle ground for developers. It enables the easy deployment of complex cross-chain applications, simplifying the development process by supporting commonly used programming languages and tools.
  2. +
  3. Hermes Layer: Built on the Cosmos SDK and Tendermint, this layer connects DojimaChain to various other blockchains, facilitating seamless interaction and liquidity sharing across different ecosystems.
  4. +
+

Together, DojimaChain and Hermes Layer empower developers to create versatile, cross-chain applications, overcoming the traditional barriers of isolated blockchain networks. This positions Dojima Network as a catalyst for the expansion and integration of Web3 technologies, appealing to a wide range of users, developers, and investors in the blockchain community.

+

Founded by experts with rich backgrounds in blockchain technology, Dojima Network is backed by significant industry players, reflecting its potential to shape the future of decentralized applications and cross-chain interoperability.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/MetaMask/config-dojima-on-metamask/index.html b/developer/Wallet/MetaMask/config-dojima-on-metamask/index.html new file mode 100644 index 0000000..55c122d --- /dev/null +++ b/developer/Wallet/MetaMask/config-dojima-on-metamask/index.html @@ -0,0 +1,3424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Add Dojima Network - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Add Dojima Network

+ +

In order to view the flow of funds in your accounts, on the Dojima Network, you will need to configure Dojima {testnet, mainnet} URL on Metamask.

+

There are two ways to do it:

+
    +
  1. Using Dojimascan
  2. +
  3. Add the Dojima network manually
  4. +
+

Using Dojimascan

+
+

Note

+

Please make sure you have already installed Metamask!

+
+
+
+
+
+
+

Please follow the steps to add Dojima’s Testnet:

+ + + +

Image title

+
    +
  • Scroll down to the bottom of the page and click on the button Add Dojima Network
  • +
+

Image title

+ + +
    +
  • Once you click the button you will see a Metamask Notification, now click on Approve. +You will be directly switched to Dojima’s Testnet now in the network dropdown list. You can now close the dialog.
  • +
+

If you are facing any issue, Add the Network Manually(steps given below)

+

Add the Dojima network manually

+
+
+
+
    +
  1. To add the Dojima Testnet to your Metamask extension for testing and development purposes, begin by launching the extension. +Image title
  2. +
  3. Click on the three dots icon to access additional options, then select “Settings” to proceed with configuring the Metamask extension. +Image title
  4. +
  5. Navigate to the “Networks” section and select “Add Network” to begin configuring a new network for integration with the Metamask extension. +Image title +Image title
  6. +
  7. Choose the “Add Network Manually” option to manually input the details of the Dojima Testnet network into the Metamask extension. +Image title
  8. +
  9. Enter Dojima Chain as the network name in the corresponding field to accurately identify the network within the Metamask extension settings. +Image title
  10. +
  11. Input the new RPC URL https://api-dev.d11k.dojima.network/ into the designated field to establish the connection with the Dojima Chain network. +Image title
  12. +
  13. Set the Chain ID to 1001 in the provided field to uniquely identify the Dojima Chain network within the Metamask extension. +Image title
  14. +
  15. Specify the Currency Symbol as DOJ to represent the native currency of the Dojima Chain network within the Metamask extension settings +Image title +Image title
  16. +
  17. Congratulations! You have successfully added the Dojima Testnet to your Metamask extension. You can now begin testing and developing on the Dojima Chain network with ease. +Image title +Image title
  18. +
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/MetaMask/custom-tokens/index.html b/developer/Wallet/MetaMask/custom-tokens/index.html new file mode 100644 index 0000000..a123750 --- /dev/null +++ b/developer/Wallet/MetaMask/custom-tokens/index.html @@ -0,0 +1,3310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Config Custom Tokens - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Config Custom Tokens

+ +

This page demonstrates the process of configuring/adding custom tokens to Metamask. Specifically, we have demonstrated adding the example TEST ERC20 and ERC721 tokens to the Görli testnet as well as the Dojima testnet,

+

You can use this process to add any custom ERC20 tokens to any network on Metamask.

+

Adding the TEST token (ERC20) to your Metamask account on the Görli Network

+

To display TEST tokens on your account on the Görli Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

+

The TEST token contract address on Görli is 0x3f152B63Ec5CA5831061B2DccFb29a874C317502. Note that the TEST token is an example ERC20 token contract that is used throughout Dojima developer docs for illustration purposes.

+

The other fields will auto-populate. Click on Save and then click on Add Tokens. The TEST token should now be displayed on your account on Metamask.

+

Configuring DOJ TST tokens to Metamask

+

You will also need to configure the TST tokens to Dojima’s Testnet for visualization if you are following the introductory D11.js tutorial. *Switch the network on Metamask to point to the Dojima testnet - https://api-dev.d11k.dojima.network/ *. On Metamask, this will be shown as Private Network or whatever you have named it when adding the custom rpc

+

The corresponding TST token address on Dojima testnet is 0x2d7882beDcbfDDce29Ba99965dd3cdF7fcB10A1e. Note that this token contract address is different from that of Goerli - since this is the TST token on the Dojima Network. A detailed, screen-by-screen guide to add custom tokens is shown here:

+

You can open Metamask and then click on the option for Add Token.

+

Image title

+

You will see a screen to either search from a list of already available tokens or add a custom token. Click on Custom Token.

+

You will see a field to add the Token Address. Paste the token address in the form, and configure the token name as TST.

+

Image title

+

You can then click on Next.

+

Image title

+

And then click on Add Tokens. You will be navigated back to the home screen and the new token will be displayed in the token list.

+

Adding the ERC721-TESTV4 token (ERC721) to your Metamask account on the Görli Network

+

To display ERC721-TESTV4 tokens on your account on the Görli Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

+

The ERC721-TESTV4 token contract address on Görli is 0xfA08B72137eF907dEB3F202a60EfBc610D2f224b. Note that the ERC721-TESTV4 token is an example ERC721 token contract.

+

The token symbol is ERC721-Testv4 and token of precision is 18. Click on Add Tokens. The ERC721-TESTV4 token should now be displayed on your account on Metamask.

+

Adding the ERC721-TESTV4 token (ERC721) to your Metamask account on the Dojima Testnet Network

+

*Switch the network on Metamask to point to the Dojima testnet - https://api-dev.d11k.dojima.network/ *. On Metamask, this will be shown as Private Network or whatever you have named it when adding the custom rpc .

+

To display ERC721-TESTV4 tokens on your account on the Dojima Testnet Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

+

The ERC721-TESTV4 token contract address on Dojima Testnet is 0x33FC58F12A56280503b04AC7911D1EceEBcE179c. Note that the ERC721-TESTV4 token is an example ERC721 token contract.

+

The token symbol is ERC721-Testv4 and token of precision is 18. Click on Add Tokens. The ERC721-TESTV4 token should now be displayed on your account on Metamask.

+

Adding a test ERC1155 token to your Metamask account

+

While the Dojima network supports ERC1155, Metamask does not yet support the standard. This update is expected in the fourth quarter of 2021.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/MetaMask/multiple-accounts/index.html b/developer/Wallet/MetaMask/multiple-accounts/index.html new file mode 100644 index 0000000..04efb3c --- /dev/null +++ b/developer/Wallet/MetaMask/multiple-accounts/index.html @@ -0,0 +1,3372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Create & Import Accounts - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Create & Import Accounts

+ +

In case you are new to Ethereum and Metamask, here is a guide on how to create multiple accounts and import them:

+

Create Account

+

To create multiple accounts, you click on Profile icon on Metamask and then click on Create Account

+

Image title

+

You can then add an account name and click on Create.

+

Image title

+

You can create more accounts this way. When you create multiple accounts, your addresses will be different at your end.

+

Import Account

+
    +
  • Open your wallet browser extension from your browser
  • +
  • Select Settings > Import Account
  • +
  • Copy the Private key(You can find this in the Account Details) from your local account, paste it into the window provided, and select Import
  • +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/MetaMask/overview/index.html b/developer/Wallet/MetaMask/overview/index.html new file mode 100644 index 0000000..87a09c4 --- /dev/null +++ b/developer/Wallet/MetaMask/overview/index.html @@ -0,0 +1,3526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Overview of MetaMask - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Overview of MetaMask

+ +

MetaMask is a crypto wallet that can be used in a web browser and on mobile devices to interact with the Ethereum blockchain. It allows you to run Ethereum Dapps (Decentralized Apps) right in your browser without running a full Ethereum node.

+

Type: Non-custodial/HD +Private Key Storage: User’s local browser storage +Communication to Ethereum Ledger: Infura +Private key encoding: Mnemonic

+
+

Danger

+

Please Backup your Secret Recovery Phrase, if your device breaks, is lost, stolen, or has data corruption, there is no other way to recover it. The Secret Recovery Phrase is the only way to recover your MetaMask accounts. Check more Basic Safety and Security Tips for MetaMask!

+
+

Guide to Setup Metamask for Dojima

+ +

Get Test Tokens - Dojima Faucet

+

1. Set up Web3

+

Step 1 +Install the following in your DApp:

+
npm install --save web3
+
+

Create a new file, name it web3.js and insert the following code in it:

+
import Web3 from 'web3';
+
+const getWeb3 = () => new Promise((resolve) => {
+  window.addEventListener('load', () => {
+    let currentWeb3;
+
+    if (window.ethereum) {
+      currentWeb3 = new Web3(window.ethereum);
+      try {
+        // Request account access if needed
+        window.ethereum.enable();
+        // Acccounts now exposed
+        resolve(currentWeb3);
+      } catch (error) {
+        // User denied account access...
+        alert('Please allow access for the app to work');
+      }
+    } else if (window.web3) {
+      window.web3 = new Web3(web3.currentProvider);
+      // Acccounts always exposed
+      resolve(currentWeb3);
+    } else {
+      console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
+    }
+  });
+});
+
+
+export default getWeb3;
+
+

The above file exports a function called getWeb3() - the purpose of which is to request metamask account’s access via detecting a global object (ethereum or web3) injected by Metamask.

+

According to Metamask’s API documentation:

+
+

MetaMask injects a global API into websites visited by its users at window.ethereum (Also available at window.web3.currentProvider for legacy reasons). This API allows websites to request user login, load data from blockchains the user has a connection to, and suggest the user sign messages and transactions. You can use this API to detect the user of a web3 browser.

+
+

In simpler terms, it basically means, having Metamask’s extension/add-on installed in your browser, you’d have a global variable defined, called ethereum (web3 for older versions) - using this variable we instantiate our web3 object.

+

Step 2

+

Now, in your client code, import the above file, +

  import getWeb3 from '/path/to/web3';
+
+and call the function: +
  getWeb3()
+    .then((result) => {
+      this.web3 = result;// we instantiate our contract next
+    });
+

+

2. Set up account

+

Now to send transactions (specifically those that alter the state of the blockchain) we’ll need an account to sign those transactions from We instantiate our contract instance from the web3 object we created above: +

  this.web3.eth.getAccounts()
+  .then((accounts) => {
+    this.account = accounts[0];
+  })
+
+The getAccounts() function returns an array of all the accounts on user’s metamask, and accounts[0] is the one currently selected by the user.

+

3. Instantiate your contracts

+

Once we have our web3 object in place, we’ll next instantiate our contracts > Assuming you have your contract ABI and address already in place :) +

  const myContractInstance = new this.web3.eth.Contract(myContractAbi, myContractAddress)
+

+

4. Call functions

+

Now for any function you’d want to call from your contract, we directly interact with our instantiated contract object (which is myContractInstance declared in Step 2)

+

A quick review: - Functions that alter the state of the contract are called send() functions - Functions that do not alter the state of the contract are called call() functions

+

Calling call() Functions +

  this.myContractInstance.methods.myMethod(myParams)
+  .call()
+  .then (
+    // do stuff with returned values
+  )
+
+Calling send() Functions +
  this.myContractInstance.methods.myMethod(myParams)
+  .send({
+    from: this.account,gasPrice: 0
+  })
+  .then (
+    (receipt) => {
+      // returns a transaction receipt}
+    )
+

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/MetaMask/tutorial-metamask/index.html b/developer/Wallet/MetaMask/tutorial-metamask/index.html new file mode 100644 index 0000000..94638e2 --- /dev/null +++ b/developer/Wallet/MetaMask/tutorial-metamask/index.html @@ -0,0 +1,3422 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + How to create a MetaMask Wallet? - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Hello Metamask

+ +

If you are wondering how to create a new cryptocurrency wallet, consider creating one by installing the MetaMask extension.

+

MetaMask is a free and secure browser extension that allows web applications to read and interact with the Ethereum blockchain.

+

Step 1. Install MetaMask on your browser

+

To create a new wallet with MetaMask you need to install the extension first. You can install Metamask for ChromeFirefox, Brave and Opera browsers.

+
    +
  1. Open https://metamask.io or search for “Metamask extension” using your favorite search engine.
  2. +
+

In this tutorial we will be using Google Chrome as an example, but the workflow is the same for all browsers.

+

https://miro.medium.com/max/1492/1*JCvnTXS3Xu0X-RExle77LA.png

+

https://miro.medium.com/max/2768/1*yO33yG60Vzht6n9L4JcXeA.png

+
    +
  1. +

    Click Chrome to install MetaMask as a Google Chrome extension.

    +
  2. +
  3. +

    Click Add to Chrome.

    +
  4. +
  5. +

    Click Add Extension.

    +
  6. +
+

https://miro.medium.com/max/2373/1*pGyNYTNmc_gZskdXH0enKQ.png

+

https://miro.medium.com/max/2251/1*ukli2LnKCQkMKT0TJFi5iQ.png

+

That’s it! You have successfully installed MetaMask extension!

+

Step 2. Create an account

+

The next step is to create an account.

+
    +
  1. Click on the MetaMask icon in the upper right corner to open the extension.
  2. +
  3. To install the latest version of MetaMask, click Try it now.
  4. +
  5. Click Continue.
  6. +
+

https://miro.medium.com/max/1486/1*5hrpXhzgQYNQMV2GhQl4-Q.gif

+
    +
  1. You will be asked to create a new password. Create a strong password and click Create.
  2. +
+
+

Don’t forget to store your password for safekeeping!

+
+

https://miro.medium.com/max/1433/1*FZEkwKijuGmIXMLfEHwtgg.png

+

https://miro.medium.com/max/1488/1*GY-dCrx6d2nXdJVT4g_STg.png

+
    +
  1. +

    Proceed by clicking Next, then accept Terms of Use.

    +
  2. +
  3. +

    Click Reveal secret words.

    +
  4. +
  5. +

    You will see a 12 words seed phrase. Save seed words as a file or copy them to a safe place and click Next.

    +
  6. +
+

Reveal secret words and copy your secret backup phrase to a safe place

+

https://miro.medium.com/max/1499/1*3Q9CtffF4SrXNpcjoEiPWw.png

+

https://miro.medium.com/max/1500/1*ZVGYYeUAhvWP3vx0MLyJvg.png

+
+

Security tips:Write this phrase on a piece of paper and store in a secure location. If you want even more security, write it down on multiple pieces of paper and store each in 2–3 different locations.Memorize this phrase.

+
+
    +
  1. Verify your secret phrase by selecting the previously generated phrase. When done, click Confirm.
  2. +
+

https://miro.medium.com/max/636/1*n6mJR5csvbgsBK-hcx6nBQ.gif

+

By “solving this puzzle” you are confirming that you know your secret phrase

+

Congratulations! You have successfully created your MetaMask account. A new Ethereum wallet address was automatically generated for you!

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/Wallet/getstarted/index.html b/developer/Wallet/getstarted/index.html new file mode 100644 index 0000000..1eab51c --- /dev/null +++ b/developer/Wallet/getstarted/index.html @@ -0,0 +1,3812 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Wallet - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Get Started

+ +
+

Tip

+

STAY IN THE KNOW

+

Keep up with the latest Wallet Suite updates from the Dojima team and community by subscribing to our Notifications.

+
+

Wallets that support Dojima allow for key management, access to accounts controlled by private keys, and interfaces that allow users to perform chain actions and sign transactions. The following page serves as a wallet index for wallets compatible with Dojima. Please note that this is not an exhaustive index.

+
+

Warning

+

THIRD-PARTY WALLETS

+

These third-party wallets have integrated Dojima and support a variety of features. You should do your own due diligence before using them. The official Dojima Support cannot provide assistance for issues with these wallets or other non-native wallets

+
+
+

Info

+

CENTRALIZED EXCHANGES (CEXS)

+

For a list of CEXs that support Dojima, visit a third-party tracking website such as CoinMarketCap.

+
+

Native Wallets

+

Dojima Support can provide assistance to users and address issues related to the following wallets:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WalletCustodyAccount TypeMulti-SigNFTdApp BrowserBridge SupportFiat On-RampPlatforms
1inchnon-custodialEOAnointerfaceyesyesnomobile
Alpha Wallet*non-custodialEOAnointerfaceyesyesyesmobile, api/sdk
Atomic Wallet*non-custodialEOAnonononoyesmobile, desktop, api/sdk
Ambirenon-custodialsmart contractnointerfacenoyesyesbrowser
BitKeepnon-custodialEOAnointerfacenoyesyesmobile
BitskicustodialEOAnointerfaceyesnobrowser, api/sdk
Coin98non-custodialEOAnointerfaceyesyesyesmobile, browser, api/sdk
CoinbasehybridEOAnointerfaceyesyesyesmobile, browser, api/sdk
CypherDnon-custodialEOAnonoyesmobile
D’Cent*hybridEOAnointerfaceyesyesnomobile
Exodus*non-custodialEOAnononoyesmobile, desktop
Gnosis Safe*non-custodialsmart contractyesinterfaceyesnonomobile, browser, api/sdk
Guardanon-custodialEOAnononoyesyesmobile, browser, desktop
Huobinon-custodialEOAnononoyesnomobile
Ledger*non-custodialEOAnointerfacenononohardware, mobile, desktop
Loopringnon-custodialsmart contractnononomobile, api/sdk
Magic*custodialEOAnononomobile, browser, api/sdk
MathWallet*custodialEOAnononoyesyesmobile, browser, api/sdk
MetaMask*non-custodialEOAnointerfaceyesnonomobile, browser, api/sdk
Multis*non-custodialEOAnononomobile, desktop
MyEtherWallet*non-custodialEOAnointerfacenomobile
Opera Crypto Browser*non-custodialEOAnosupportyesmobile, browser
Pillarnon-custodialEOAnointerfacenomobile
Rainbownon-custodialEOAnointerfaceyesmobile, api/sdk
SafePal*non-custodialEOAnonoyeshardware, mobile, api/sdk
Sequencenon-custodialsmart contractnointerfacenobrowser, api/sdk
SimpleHoldnon-custodialEOAnononomobile, api/sdk
SteakWalletnon-custodialEOAnointerfacenomobile, api/sdk
TokenPocketnon-custodialEOAnosupportyesyesnomobile, browser, api/sdk
Torusnon-custodialEOAnosupportnononobrowser, api/sdk
Trezor*non-custodialEOAnosupportnohardware, mobile
Trust Wallet*non-custodialEOAnosupportyesmobile
Unstoppablenon-custodialEOAnonoyesmobile, api/sdk
Venlyhybridsmart contractnointerfacenobrowser, api/sdk
Wirex*non-custodialEOAnononomobile
XDeFinon-custodialEOAnointerfacenononobrowser
Zerionnon-custodialEOAnonoyesmobile, browser
+
+

Warning

+

NON-NATIVE WALLET SUPPORT

+

Wallets denoted with * in the table above are not natively supported with the wallet software and require manual steps to add the Dojima network.

+
+

Key Management Strategy

+

The following basic steps allow for the integration of a client-side application with Dojima:

+
    +
  1. Set up Web3: web3.js is a javascript library that allows a client-side application to talk to the blockchain. We configure web3 to communicate via a developer-based wallet like MetaMask. Use the web3.js docs to learn about adding web3.js to your project.
  2. +
  3. Set up an Account: You will be able to send transactions (specifically ones that alter the state of the blockchain).
  4. +
  5. Instantiate Contracts: Once a web3 object in place, we next instantiate our deployed contract, with which we interact.
  6. +
  7. Call functions: Fetch data via functions in the contract - through our contract object.
  8. +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/contract/index.html b/developer/developer-dashboard/contract/index.html new file mode 100644 index 0000000..d9b4716 --- /dev/null +++ b/developer/developer-dashboard/contract/index.html @@ -0,0 +1,3262 @@ + + + + + + + + + + + + + + + + + + + + + + + Contract - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Contract

+ +

To deploy a smart contract using Dojima without any complications, you can follow these simplified steps designed for a seamless experience.By simplifying the process into a single-tap deployment, Dojima aims to enhance the user experience for deploying smart contracts on the supported chain (Ex. Dojima, Ethereum …). The platform streamlines the necessary inputs, providing a user-friendly environment for both beginners and experienced developers.

+

medium

+

Step1: Enter required inputs for contract deployment

+

Dojima introduces a unique feature that allows users to enter required inputs for contract deployment.By combining a user-friendly interface with dynamic code auto-generation, Dojima bridges the gap between beginners and experienced developers, making smart contract deployment accessible to a wider audience.

+

medium

+

Step2: Click on Deploy button to proceed to next step

+

medium

+

Step3: Review and Deploy

+

Certainly! Let’s enhance the explanation for the last step where developers review the smart contract details, add arguments if needed, and initiate the deployment. And it takes a moment to complete the deployment process for the selected chain.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/dashboard/new_project/index.html b/developer/developer-dashboard/dashboard/new_project/index.html new file mode 100644 index 0000000..1a62da5 --- /dev/null +++ b/developer/developer-dashboard/dashboard/new_project/index.html @@ -0,0 +1,3268 @@ + + + + + + + + + + + + + + + + + + + + + + + Create New Project - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Create New Project

+ +

Create new project:

+

Welcome to the Template-Driven Project Creation Platform! To begin a new project, navigate to the “Create New Project” section, where you’ll find a straightforward process to kickstart your endeavor. Follow these steps to initiate your project:

+

medium

+

Enter project details:

+

Enter project details such as Project Name, Project Type and Description of project. Before entering the next section user must enter Project Name and Project Type as they are mandatory fields.

+

medium

+

medium

+

Select Chain

+

It’s time to take the next step in your project creation. Select one chain from the options provided but Dojima is auto selected as it is a mandatory chain. After next button is clicked the developer is navigated to xchain-connection section.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/dashboard/templates/index.html b/developer/developer-dashboard/dashboard/templates/index.html new file mode 100644 index 0000000..aef5551 --- /dev/null +++ b/developer/developer-dashboard/dashboard/templates/index.html @@ -0,0 +1,3238 @@ + + + + + + + + + + + + + + + + + + + + + + + Templates - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Templates

+ +

Select from Templates

+

Navigate to the “Select from Templates” section to explore our range of existing templates. Each template is designed to address distinct project types, offering you a head start in achieving your project creation.

+

medium

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/index.html b/developer/developer-dashboard/index.html new file mode 100644 index 0000000..c431c1a --- /dev/null +++ b/developer/developer-dashboard/index.html @@ -0,0 +1,3210 @@ + + + + + + + + + + + + + + + + + + + + + + + Index - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Index

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/login/index.html b/developer/developer-dashboard/login/index.html new file mode 100644 index 0000000..f1ab35d --- /dev/null +++ b/developer/developer-dashboard/login/index.html @@ -0,0 +1,3237 @@ + + + + + + + + + + + + + + + + + + + + + + + Login - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Login

+ +

Single Sign-On with Google Account:

+

Seamlessly access to the Dojima Developer Dashboard by logging in with your Google account. Enjoy a secure and hassle-free authentication process, eliminating the need for multiple usernames and passwords.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/projects/index.html b/developer/developer-dashboard/projects/index.html new file mode 100644 index 0000000..08e0b7e --- /dev/null +++ b/developer/developer-dashboard/projects/index.html @@ -0,0 +1,3214 @@ + + + + + + + + + + + + + + + + + + + + + + + Projects List - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Projects List

+ +

Navigating through your projects has never been more straightforward. We’ve organized your projects in a clear and concise table format, providing you with an instant overview and easy access to vital project details.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/developer-dashboard/xchain_connections/index.html b/developer/developer-dashboard/xchain_connections/index.html new file mode 100644 index 0000000..2b63375 --- /dev/null +++ b/developer/developer-dashboard/xchain_connections/index.html @@ -0,0 +1,3282 @@ + + + + + + + + + + + + + + + + + + + + + + + XChain Connections - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

XChain Connections

+ +

Dojima has made user-friendly process to deploy single-tap deployment of contracts for selected chains in xchain-connections.

+

medium

+

Step1: Seclect Chain Layer

+

Select the chain layer and you can get the actions popup on the top-left of the screen.

+

medium

+

medium

+

Step2: Select types of chain

+

Select the type from provided contract types and enter Contract Name and Contract Symbol. Additional details can be added such as Features, Access Control, Upgradeability and License. We generate the automated code for you.

+

medium

+

medium

+

medium

+

Step3: Click on Save button

+

After entering the details and click on Save button. And Deploy button is activated on the bottom-right of the screen.

+

medium

+

medium

+

Step4: Click on Deploy button

+

After clicking on deploy button. Deploy popup is displayed to enter additional details for each chain one by one.

+

medium

+

medium

+

medium

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/faucet/index.html b/developer/faucet/index.html new file mode 100644 index 0000000..0edab0e --- /dev/null +++ b/developer/faucet/index.html @@ -0,0 +1,3495 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Faucet - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Faucet

+ +

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

+

Prerequisites

+

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don’t have a seed phrase, follow these steps.

+

To request tokens using the faucet.

+

1. Before requesting TestNet tokens check the table for available faucet balances.

+

medium

+

2.  Select the Hermes token and copy the address.

+

medium

+

3. Choose a chain for token requests.

+

medium

+

4. Paste address in the address input or use self address checkbox.

+

medium

+

medium

+

5. Click the “submit” button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.

+

medium

+

6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.

+

medium

+

Stagenet

+

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/index.html b/developer/index.html new file mode 100644 index 0000000..8e2181a --- /dev/null +++ b/developer/index.html @@ -0,0 +1,3317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Developer - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+

Developers

+

Your resource hub for seamless onboarding and support within our evolving ecosystem.

+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/quickstart/index.html b/developer/quickstart/index.html new file mode 100644 index 0000000..ed1b6cc --- /dev/null +++ b/developer/quickstart/index.html @@ -0,0 +1,3367 @@ + + + + + + + + + + + + + + + + + + + + + + + Dojima - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Introduction to Dojima PoS

+
+

Warning

+

UPDATING THE DEVELOP DOCS

+

The docs are being updated, enhanced, and improved. They are subject to change. Please feel free to raise an issue or pull request if you have any queries or suggestions.

+
+

Welcome to Dojima The most innovative and exciting platform to develop your blockchain application. Blockchain technology is poised to revolutionize how the digital world manages data and conducts business. You can join this revolution by getting a head start on Dojima’s decentralized application (dApp) development.

+

This guide will introduce you to the Dojima ecosystem. You’ll find links to valuable resources and websites that will bring you up to speed on building, not only on Dojima but also on general blockchain application development.

+
+

Tip

+

STAY IN THE KNOW

+

Keep up with the latest builder updates from the Dojima team and the community by subscribing to the .

+
+

Building on Dojima

+

If you are an Ethereum developer, you are already a Dojima developer. Simply switch to the Dojima RPC and get started. All the tools you are familiar with on the Ethereum blockchain are supported on Dojima by default, such as Truffle, Remix, and Web3js.

+

You can deploy decentralized applications to either Dojima Testnet or the Mainnet. The Dojima Testnet connects with the Ethereum Goërli Testnet, which acts as its ParentChain. You can find all the network-related details in the [network documentation].

+

Wallets

+

To interact with the Dojima Network, you need to have an Ethereum-based wallet because Dojima runs on Ethereum Virtual Machine (EVM). You can choose to set up a Metamask or Arkane Wallet. More on wallet-related information and why you need one can be found in our wallet documentation.

+

Smart Contracts

+

Dojima supports many services you can use to test, compile, debug, and deploy decentralized applications onto the Dojima Network. These include deployment using Alchemy, Chainstack, QuickNode, Remix, Truffle, Hardhat, and Replit.

+ + +

Building a new dApp on Dojima?

+

Decentralized applications (dApps) act as the bridge between users and their data privacy on the blockchain. The increasing number of dApps validates their usefulness within the blockchain ecosystem, solving challenges like executing transactions between two participants without the need for central authority via smart contracts.

+

Suppose you have no prior experience building decentralized applications (dApps). In that case, the below-mentioned resources will give you a head start on the tools required to build, debug, and deploy dApps on the Dojima Network.

+

Full Stack dApp: Tutorial Series +- Web3.js +- Ethers.js +- Remix +- Truffle +- Metamask +- Arkane +- Develop a dApp using Fauna, Dojima and React

+

Already have a dApp?

+

If you already have a decentralized application (dApp) and are looking for a platform to help you scale efficiently, then you are at the right place because Dojima allows you to:

+
    +
  1. +

    Easily migrate from Ethereum Virtual Machine (EVM) based chain: Dojima prides itself in being the ultimate Layer-2 scaling solution for Ethereum. You don’t have to worry about the underlying architecture while moving or deploying your dApps to the Dojima Network as long as it is EVM-compatible

    +
  2. +
  3. +

    Use Dojima as a faster transaction layer: Deploying your dApp to the Dojima Mainnet allows you to leverage Dojima as a faster transaction layer for your dApp. Additionally, you can get your tokens mapped by us. You can join our technical discussions group on Telegram to learn more.

    +
  4. +
+

Side Note

+

If this is overwhelming, that’s alright! You can jump right into the action and start hacking. Here are some notes before you start diving into resources, repositories, and docs:

+
    +
  1. +

    Beware the cost of being on the bleeding edge: Like typical niche programming, dApps and blockchain development moves very quickly. While researching, you may find complex code repositories, 404s on a documentation site, or even no documentation. Use that opportunity to reach out to us via any social media channel.

    +
  2. +
  3. +

    The learning curve may be daunting, but the barrier to entry is low: The community is very open and welcoming! Projects welcome pull requests from outsiders and resolve any blockers actively. We’re working on creating a better world and contribution in any form is appreciated. We’ll be grateful to onboard you into this amazing Web3 ecosystem.

    +
  4. +
+
+

Info

+

STAY UPDATED

+

Decentralized application development encourages network decentralization. Follow our social media handles for more insights and updates about the Dojima ecosystem. You can find the links to all the Dojima communities here.

+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/sources/basic/index.html b/developer/sources/basic/index.html new file mode 100644 index 0000000..b6bdd07 --- /dev/null +++ b/developer/sources/basic/index.html @@ -0,0 +1,3357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Basics of Web3 Development - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/sources/endpoints/index.html b/developer/sources/endpoints/index.html new file mode 100644 index 0000000..f03f888 --- /dev/null +++ b/developer/sources/endpoints/index.html @@ -0,0 +1,3429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Network Endpoints - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Network Endpoints

+ +

Testnet

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTestnet
Network NameDojima chain
RPC URLhttps://api-dev.d11k.dojima.network/
WS URLhttps://rpc-dev.d11k.dojima.network/
Chain ID1001
Currency symbolDOJ
Block Explorer URLhttps://explorer-dev.dojima.network/
+

Stagenet

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldStagenet
Network NameDojima chain
RPC URLhttps://api.d11k.dojima.network/
WS URLhttps://rpc.d11k.dojima.network/
Chain ID1401
Currency symbolDOJ
Block Explorer URLhttps://explorer.dojima.network/
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/sources/external/index.html b/developer/sources/external/index.html new file mode 100644 index 0000000..65837fb --- /dev/null +++ b/developer/sources/external/index.html @@ -0,0 +1,3378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + External Documentation - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/sources/faucet/index.html b/developer/sources/faucet/index.html new file mode 100644 index 0000000..ed09343 --- /dev/null +++ b/developer/sources/faucet/index.html @@ -0,0 +1,3323 @@ + + + + + + + + + + + + + + + + + + + + + + + Faucet - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Faucet

+ +

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

+

Prerequisites

+

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don’t have a seed phrase, follow these steps.

+

To request tokens using the faucet.

+

1. Before requesting TestNet tokens check the table for available faucet balances.

+

medium

+

2.  Select the Hermes token and copy the address.

+

medium

+

3. Choose a chain for token requests.

+

medium

+

4. Paste address in the address input or use self address checkbox.

+

medium

+

medium

+

5. Click the “submit” button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.

+

medium

+

6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.

+

medium

+

Stagenet

+

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/templates/deposit_manager/index.html b/developer/templates/deposit_manager/index.html new file mode 100644 index 0000000..8ddbbab --- /dev/null +++ b/developer/templates/deposit_manager/index.html @@ -0,0 +1,3833 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Deposit Manager Template Documentation - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Deposit Manager Template Documentation

+

Introduction

+

The Deposit Manager contract template is a pivotal tool for Dojima Chain developers, +designed to facilitate cross-chain functionalities within decentralized applications (DApps). +It emphasizes the management of token deposits across different blockchain networks.

+

Key Features:

+
    +
  • Cross-Chain Token Management: Efficiently tracks ERC20 tokens (or their equivalents) across multiple chains.
  • +
  • Deposit Tracking: Employs unique IDs for each token deposit, alongside the token amount and address.
  • +
  • State Synchronization with Inbound State Sender: Leverages inbound state sender for communicating from other chains to the Dojima Chain.
  • +
  • Multi-Chain Compatibility: While primarily designed for Ethereum, it’s adaptable for additional blockchain integrations.
  • +
+

Use Cases

+
    +
  • Cross-Chain DApps Development: Optimal for DApps that necessitate token fluidity across blockchain ecosystems.
  • +
  • Token Deposit Ledger: Ideal for platforms that require an accurate and detailed record of token deposits.
  • +
+

Prerequisites

+
    +
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all the cross-chain data. Read more about the Dojima chain here.
  • +
  • Destination Chain: A destination chain will refer to all the chains that are connected to the Dojima chain. + The destination chain could be Ethereum, Solana, or any other chain that is connected to the Dojima chain. + But it doesn’t represent the origin of transaction. + Transaction can originate either from Dojima chain or destination chain (Ethereum, Solana).
  • +
  • Hermes Client: The Hermes client is essential for cross-chain communication between Destination and the Dojima Chain and vice versa. Read more about Hermes here.
  • +
  • Inbound State Sender: The Inbound State Sender is a key component of the cross-chain data transfer. + It will be deployed on all the destination chains and will be responsible for facilitating the reception of encoded state + messages from destination chains to the Dojima Chain. Read more about inbound state sender and how to use it here.
  • +
  • Root Token: In the context of deposit manager contract, root token refers to any token on the destination chains.
  • +
  • Child Token: In the context of deposit manager contract, child token refers to the root-tokens counterpart on the Dojima chain.
  • +
  • Child Chain: The child chain refers to the contract that is deployed on the Dojima chain. It manages all the root token counterparts (child tokens) on the Dojima chain.
  • +
+

Contract Overview

+

ChildChain Contract (Dojima Chain)

+

Child chain contract will be deployed on the Dojima chain. +It is responsible for creating and managing child tokens on the Dojima chain. +Each Root Token will have a corresponding child token on the Dojima chain. +The child token will be used to track the token balance of users on the Dojima chain. +The child token will be minted when a user deposits tokens on the Ethereum chain. +The child token will be burned when a user withdraws tokens from the Ethereum chain.

+

Key Functionalities

+
    +
  • addToken: Creates and maps a child token on the Dojima chain for a specific root token for the specified chain.
  • +
  • onStateReceive: Executes the state sync process, minting tokens on the Dojima chain based on the incoming state information from the destination chains.
  • +
  • withdrawTokens: Manages tokens’ withdrawal requests, facilitating transfers back to the Destination chain.
  • +
  • _depositTokens: Credits tokens on the Dojima chain based on the incoming state information.
  • +
+

ChildERC20 and ChildToken Contracts

+
    +
  • Support ERC20 token functionalities on the Dojima chain, including standard and cross-chain transactions.
  • +
+

DepositManager Contract (Destination Chains)

+

Deposit manager contract will be deployed on the destination chains (Ethereum, Solana, etc.). +It is responsible for managing the deposit of tokens on the destination chains.

+

Constructor

+
    +
  • Set up the contract with a specific chain name, establishing a cross-chain context.
  • +
+

Key Functions

+
    +
  • updateChildChainAndStateSender: Modifies the child chain and inbound state sender contract addresses.
  • +
  • deposit: Facilitates the deposit of ERC20 tokens by users, accurately recording each transaction. It involves locking tokens + in deposit manager and initiate a state sync process to deposit tokens in child chain contract. +
    inboundStateSender.transferPayload(
    + _childChain,
    + abi.encode(_chainName, _user, _token, _amount, _depositId)
    +)
    +
    + The transferPayload function in the depositBlock method has the following parameters:
  • +
  • childChain: The target child chain contract address on the dojima chain for the cross-chain transfer.
  • +
  • balanceOf: Retrieves the specific token balance for an account.
  • +
  • abi.encode(_chainName, _user, _token, _amount, _depositId): This is the payload that is being transferred to the target blockchain. It’s encoded using Ethereum’s ABI (Application Binary Interface) encoding. The payload includes:
      +
    • _chainName: The name of the chain where the tokens will be deposited. + This will be same as the chain name passed to the constructor. + Basically the name of the chain where the deposit manager contract is deployed. + In this case Ethereum.
    • +
    • _user: The address of the user who will receive the tokens on the target blockchain
    • +
    • _token: The address of the token contract(root token) on the destination blockchain.
    • +
    • _amount: The number of tokens to be transferred.
    • +
    • _depositId: This is a unique identifier for the deposit operation. The depositId could be used to track or identify individual deposit operations.
    • +
    +
  • +
+

Events

+
    +
  • Deposit: Announced upon a successful token deposit.
  • +
  • Withdrawal: Announced during token withdrawal (yet to be implemented).
  • +
+

System Integration

+

InboundStateSender

+
    +
  • Functionality: The InboundStateSender’s transferPayload function is crucial in cross-chain communication. + It transmits the encoded state (chain name,user address, token amount, deposit ID) to the Dojima chain.
  • +
  • Usage in transferToChain:
  • +
+
  inboundStateSender.transferPayload(
+   _childChain,
+   abi.encode(_chainName, _user, _token, _amount, _depositId)
+  )
+
+

Note: Read more about inbound state sender and how to use it here.

+

Workflow

+
    +
  1. Token Registration: Utilizes ChildChain.addToken for mapping tokens on the Dojima chain.
  2. +
  3. Token Deposit (Ethereum): Users make token deposits into the DepositManager.
  4. +
  5. State Synchronization: Encoded deposit data is sent to the Dojima chain for synchronization.
  6. +
  7. Token Deposit (Dojima): ChildChain decodes the data, allocating tokens correspondingly.
  8. +
+

Interaction with Child Chain

+

The Deposit Manager ensures tokens deposited on Ethereum are mirrored on the Dojima Chain through:

+
    +
  • Inbound State Sender: Facilitates the reception of encoded state messages from Ethereum and other chains to the Dojima Chain, ensuring that deposit data is accurately transmitted for processing.
  • +
  • Token Minting on Dojima: Upon receiving deposit data, the Child Chain mints equivalent child tokens, crediting them to the respective user’s account on the Dojima Chain, maintaining consistency across chains.
  • +
  • Security and Verification: The State Syncer Verifier, exclusive to the Dojima Chain, authenticates the incoming state messages, permitting the Child Chain to mint tokens securely.
  • +
+

Security and Cautions

+
    +
  • Accurate State Sender Address: Essential verification of the state sender address for security.
  • +
  • Cross-Chain Protocol Security: Evaluate the security measures of the Hermes bridge and related platforms.
  • +
  • Comprehensive Smart Contract Audits: Essential to identify and mitigate potential vulnerabilities.
  • +
  • Robust User Authentication: Critical for ensuring secure user interaction with the DApp.
  • +
+

Conclusion

+

This template, alongside the Child Chain, establishes a foundational framework for developing cross-chain DApps, particularly for token transfers between Ethereum and the Dojima Chain. By leveraging this template, developers are equipped to enable streamlined and secure cross-chain token transfers, broadening the interoperability and utility of their applications.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/templates/omni_chain_ERC20/index.html b/developer/templates/omni_chain_ERC20/index.html new file mode 100644 index 0000000..63fbc7a --- /dev/null +++ b/developer/templates/omni_chain_ERC20/index.html @@ -0,0 +1,3866 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + OmniChain ERC20 Template Documentation - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

OmniChain ERC20 template Documentation

+

Introduction

+

The OmniChain ERC20 template is a pivotal tool for Dojima Chain developers, +facilitating the seamless transfer and management of a token across different blockchain networks, +including Ethereum, Solana, and others.

+

Key Features:

+
    +
  • Cross-Chain Transfer: Enables the transfer of tokens from the Dojima chain to other blockchains.
  • +
  • State Synchronization with Outbound State Sender: Leverages outbound state sender for communicating from the Dojima Chain to other chains.
  • +
  • Multi-Chain Compatibility: It allows user to transfer tokens from the Dojima chain to any other chain that is connected to the Dojima chain.
  • +
+

Use Cases

+
    +
  • Cross-Chain DApps Development: Optimal for DApps that necessitate token fluidity across blockchain ecosystems.
  • +
  • Multi-Chain Token Management: Ideal for platforms that require a single token to be used across multiple blockchains.
  • +
+

Prerequisites

+
    +
  • Primary Chain: The primary chain refers to the Dojima Chain.
  • +
  • Secondary Chain: The secondary chain refers to the chains other than the Dojima Chain. For example, Ethereum, Solana, Polkadot, etc.
  • +
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all cross-chain data. Read more about the Dojima chain here.
  • +
  • Source Chain: The source chain refers to the chain from which the cross-chain transfer originates. In the context of the OmniChainERC20Contract, the source chain is the Dojima chain.
  • +
  • Destination Chain: A destination chain will refer to all the chains that are connected to the Dojima chain. + The destination chain could be Ethereum, Solana, or any other chain that is connected to the Dojima chain. + It doesn’t represent the origin of transaction.
  • +
  • Hermes Client: The Hermes client is essential for cross-chain communication between the destination and the Dojima Chain and vice versa. Read more about Hermes here.
  • +
  • Outbound State Sender: The Outbound State Sender is a key component of the cross-chain data transfer. + It will be deployed on the Dojima chain and will be responsible + for facilitating the transmission of encoded state messages from the Dojima chain to destination chains. + Read more about outbound state sender and how to use it here.
  • +
  • XToken: The XToken is an ERC20 token that will be used for cross-chain transfer. + It will be deployed on the Dojima chain and will be used to track the token balance of users on the Dojima chain.
  • +
  • CrossChainERC20Contract: This token contract will be deployed on the Ethereum chain. + It will be used to manage the lifecycle of ERC20 tokens on the secondary chains (Ethereum, Solana, Polkadot, etc.). + and will be able to communicate with OmniChainERC20Contract through the Hermes Client.
  • +
+

Contract Overview

+

OmniChainERC20Contract

+

Omni chain ERC20 contract is a standard ERC20 contract deployed on the Dojima chain. +It is responsible for the minting and burning of XToken on the Dojima chain. +It facilitates the transfer of XTokens from the Dojima chain to other chains.

+

Requirements

+
    +
  • Outbound State Sender: This is the contract address that is used to send updates from the primary chain (Dojima Chain) to the Secondary Chain (Ethereum, Solana, Polkadot etc.).
  • +
  • OnStateReceive: This is a function that needs to be implemented in the primary chain (Dojima Chain) to process the state updates received from the secondary chain contract.
  • +
+

⚠️ Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. +Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

+

Key Functions:

+
    +
  • transferToChain: This function enables the transfer of tokens from the Dojima chain to other blockchains. + It involves burning tokens on the Source Chain (Dojima chain) + and initiates a state sync process to mint destination chain token. +
        function transferToChain(
    +      bytes32 destinationChain,
    +      bytes memory user,
    +      uint256 amount,
    +      bytes memory destinationContractAddress
    +  ) external nonReentrant {
    +      _burn(msg.sender, amount);
    +    outboundStateSender.transferPayload(
    +      destinationChain,
    +      destinationContractAddress,
    +      refundAddress,
    +      abi.encode(user, amount, depositID)
    +    );
    +  }
    +
    + The transferPayload function in the transferToChain method has the following parameters:
  • +
  • destinationChain: The destination chain will be either Ethereum, Polkadot, Solana etc. for the cross-chain transfer. Basically the name of the secondary chains where we want to send the state update.
  • +
  • destinationContractAddress: This is the address of the contract on the secondary chain (Ethereum, Polkadot, Solana etc.) that will receive, decode and process the payload. It’s usually the address of a smart contract that has a function to handle such incoming payloads.
  • +
  • refundAddress: This is the address of the entity on the primary chain (Dojima Chain) usually a user address or another contract that will be receiving the refund if the state update fails.
  • +
  • abi.encode(user, amount, depositID): This is the payload that is being transferred to the target blockchain. It’s encoded using Ethereum’s ABI (Application Binary Interface) encoding. The payload includes:
      +
    • user: The address of the user who will receive the tokens on the destination chain
    • +
    • amount: The number of tokens to be transferred.
    • +
    • depositID: The depositId could be used to track or identify individual token transfer operations.
    • +
    +
  • +
  • onStateReceive: + Executed by the _stateVerifier (Dojima system account), + this function handles the minting of tokens on the Dojima chain based on the state received from other chains. + It decodes the user address, amount, and deposit ID from the received encoded data.
  • +
+

Roles and Security:

+
    +
  • _stateVerifier Role: A system-controlled account with exclusive rights to mint tokens on the Dojima chain, ensuring security in the token minting process.
  • +
  • Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.
  • +
+

XERC20Contract

+

This contract represents the ERC20 tokens on the Dojima Chain, +detailing their properties and providing functions for their management within the Dojima ecosystem.

+

CrossChainERC20Contract

+

Manages the lifecycle of ERC20 tokens on the secondary chains (Ethereum, Solana, Polkadot, etc.). +And links with OmniChainERC20Contract through the Hermes Client. +The total supply of the token will be minted on during the contract initialization.

+
    +
  • Burn: The Contract will burn user token on the secondary chain (Ethereum, Solana, Polkadot etc.) + and will send the state update to the Dojima chain to mint the XERC20 token on the Dojima chain for the user.
  • +
  • Minting: The Contract will mint the ERC20 on the secondary chain based on the payload received from the Dojima chain by the executeState function.
  • +
+

Requirements

+
    +
  • Inbound State Sender: This is the contract used to send updates from the secondary chain (Ethereum, Solana, Polkadot etc.) to the primary chain (Dojima Chain).
  • +
  • ExecuteState: This is a function that needs to be implemented in the secondary chain contract to process the state updates received from the primary chain (Dojima Chain).
  • +
+

⚠️ Warning: +Only State Inbound State Sender contract address is allowed to call executeState function on secondary chains +(Ethereum, Solana, Polkadot etc.).

+

Workflow

+

Transfer From OmniChainERC20Contract to CrossChainERC20Contract

+
    +
  • Source Chain: The source chain here is Dojima Chain (Primary Chain).
  • +
  • Transfer From Source: ERC20 token transfers are initiated on the Dojima Chain through the OmniChainNFTContract, specifying the token amount, user address and destination contract address (CrossChainERC20 contract address).
  • +
  • +

    State Synchronization: The transfer’s state is encoded and transmitted across chains via the Hermes Client, utilizing the outbound state sender for secure communication.

    +
  • +
  • +

    Functionality: The OutboundStateSender’s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) from the Dojima chain’s OmniChainERC20Contract to destination chain contracts.

    +
  • +
  • Significance: Ensures the synchronization of token states across chains, triggering corresponding actions (burn or mint) in the connected contracts.
  • +
  • Usage in transferToChain: +
        outboundStateSender.transferPayload(
    +        destinationChain,
    +        destinationContractAddress,
    +        msg.sender,
    +        abi.encode(user, amount, depositID)
    +    )
    +
  • +
+

⚠️ Warning: + The outboundStateSender contract is very crucial for the cross-chain transfer make sure you follow the steps + mentioned in the doc.

+
    +
  • After transfer payload: Once above step is successfully executed on a primary chain (Dojima Chain) the state update will be sent to the secondary chains (Ethereum, Solana, Polkadot etc.).
  • +
  • Minting on Destination Chain: Upon receiving the state, the CrossChainERC20 contract on the secondary chain will mint the specified number of tokens for the intended recipient through executeState function, completing the cross-chain transfer. +
        function executeState(uint256 depositID, bytes calldata payload) external {
    +        // Decode the payload
    +        (address userAddress, uint256 amount, uint256 depositId) = abi.decode(
    +            stateData, (address, uint256, uint256)
    +        );
    +        // Mint the ERC20 token for the user
    +        // Process the state update
    +    }
    +
  • +
+

Transfer From CrossChainERC20Contract to OmniChainERC20Contract

+
    +
  • Destination Chain: The destination chain here is Secondary Chains (Ethereum, Solana, Polkadot).
  • +
  • Burn on Destination Chain: The CrossChainERC20 contract will burn the specified number of tokens for the user on the secondary chain.
  • +
  • Transfer From Destination Chain: Encode the payload (user address, amount, depositID) and transfer from the secondary chains (Ethereum, Solana, Polkadot etc.) to the Dojima chain through the Inbound State Sender + to mint the same amount of XERC20 token on the Dojima chain for the specified user.
  • +
  • Usage in transferToOmniChain: +
       function transferToOmniChain(bytes memory user, uint256 amount) external nonReentrant {
    +        _burn(senderAddress, amount);
    +        inboundStateSender.transferPayload(
    +          omniChainContractAddress,
    +          abi.encode(user, amount, depositID)
    +        );
    +    }
    +
  • +
  • After transfer payload: Once above step is successfully executed on secondary chains (Ethereum, Solana, Polkadot etc.) the state update will be sent to the Dojima chain.
  • +
  • State Receive on Source Chain: Upon receiving the state, + OmniChainERC20Contract which is on Dojima Chain will decode the user address, amount, + deposit ID will mint the specified number of tokens for the intended recipient, completing the cross-chain transfer. + and deposit IDand mints the XERC20 token for the user.
  • +
+

Security and Best Practices

+
    +
  • Audit Compliance: Ensure all contracts undergo thorough security audits.
  • +
  • Transaction Monitoring: Implement systems to monitor and verify cross-chain transactions regularly.
  • +
  • Role Management: Strictly manage role assignments, especially for critical roles like _stateVerifier.
  • +
  • Gas Optimization: Aim for efficiency in contract execution to minimize transaction costs.
  • +
+

Conclusion

+

The OmniChainERC20Contract Suite represents a significant step towards seamless blockchain interoperability, with a focus on security, efficiency, and developer-friendliness. It is crucial for developers to understand the intricacies of the suite to leverage its full potential in their DApp development.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/templates/omni_chain_NFT/index.html b/developer/templates/omni_chain_NFT/index.html new file mode 100644 index 0000000..acc4d6e --- /dev/null +++ b/developer/templates/omni_chain_NFT/index.html @@ -0,0 +1,3851 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + OmniChain NFT Template Documentation - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

OmniChain NFT Template Documentation

+

Introduction

+

The OmniChainNFT template provides a comprehensive framework for Dojima Chain developers to facilitate the cross-chain transfer of Non-Fungible Tokens (NFTs), +enabling seamless interoperability and utilization across various blockchain ecosystems.

+

Key Features

+
    +
  • Cross-Chain NFT Transfers: Allows for the seamless transfer of NFTs across different blockchain networks.
  • +
  • State Synchronization : Utilizes the outbound state sender for robust cross-chain communication.
  • +
  • Multi-Chain Compatibility: Ensures NFTs are accessible and transferable across a wide range of blockchain networks.
  • +
+

Use Cases

+
    +
  • Cross-Chain NFT Marketplaces: Allows NFTs to be listed, bought, and sold across different blockchain marketplaces.
  • +
  • NFT Collections: Enables collectors to move their NFTs across chains, broadening the exposure and utility of their collections.
  • +
+

Prerequisites

+
    +
  • Primary Chain: The primary chain refers to the Dojima Chain.
  • +
  • Secondary Chain: The secondary chain refers to the chains other than the Dojima Chain. For example, Ethereum, Solana, Polkadot, etc.
  • +
  • Source Chain: The source chain refers to the chain from which the cross-chain transfer originates.
  • +
  • Destination Chain: A destination chain will refer to the chains where the cross-chain transfer will be received.
  • +
  • Hermes Client: Proficiency with the Hermes Client, a crucial component for enabling the communication between the Dojima Chain and other blockchains. The Hermes Client facilitates the secure and efficient transfer of state information across chains.
  • +
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all cross-chain data. Read more about the Dojima chain here.
  • +
  • OutboundStateSender: The OutboundStateSender contract will be used to send state updates from the primary chain (Dojima Chain) to the secondary chain (Ethereum, Solana, Polkadot).
  • +
  • InboundStateSender: The InboundStateSender contract will be used to send state updates from the secondary chain (Ethereum, Solana, Polkadot) to the primary chain (Dojima Chain).
  • +
  • XNFTContract: The XNFTContract is an ERC721 standard token contract that will be used for cross-chain NFT transfer. + It will be deployed on the Dojima chain and will be used to track the NFTs’ of users on the Dojima chain.
  • +
  • CrossChainNFTContract: This NFT contract will be deployed on the secondary chains (Ethereum, Solana, Polkadot, etc.). + It will be used to manage the lifecycle of NFTs’ on the secondary chain (Ethereum, Solana, Polkadot, etc.) network + and will be able to communicate with OmniChainNFTContract through the Hermes Client.
  • +
+

Contract Overview

+

OmniChainNFTContract

+

A pivotal contract deployed on the primary chain (Dojima Chain) to manage the lifecycle of NFTs during the cross-chain transfer process, +including functionalities for burning and minting NFTs across chains.

+

Requirements

+
    +
  • Outbound State Sender: This is the contract address used to send updates from the primary chain (Dojima Chain) to the secondary chain (Ethereum, Solana, Polkadot).
  • +
  • OnStateReceive: This function is responsible for receiving the state updates from the secondary chain and processing them on the Dojima Chain.
  • +
+

⚠️ Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. +Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

+

Key Functions:

+
    +
  • transferToChain: This function enables the transfer of NFT from the Dojima chain to other blockchains. + It involves burning specified NFT on the Source Chain (Dojima chain) + and initiates a state sync process to mint the same NFT on the destination chain. +
      function transferToChain(
    +    bytes32 destinationChain,
    +    bytes memory user,
    +    uint256 amount,
    +    bytes memory destinationContractAddress
    +) external nonReentrant {
    +    _burn(msg.sender, amount);
    +  outboundStateSender.transferPayload(
    +    destinationChain,
    +    destinationContractAddress,
    +    refundAddress,
    +    abi.encode(user, amount, depositID)
    +  );
    +}
    +
    + The transferPayload function in the transferToChain method has the following parameters:
  • +
  • destinationChain: The destination chain will be either Ethereum, Polkadot, Solana etc. for the cross-chain transfer. Basically the name of the secondary chains where we want to send the state update.
  • +
  • destinationContractAddress: This is the address of the contract on the secondary chain (Ethereum, Polkadot, Solana etc.) that will receive, decode and process the payload. It’s usually the address of a smart contract that has a function to handle such incoming payloads.
  • +
  • refundAddress: This is the address of the entity on the primary chain (Dojima Chain) usually a user address or another contract that will be receiving the refund if the state update fails.
  • +
  • abi.encode(user, amount, depositId): This is the payload that is being transferred to the target blockchain. It’s encoded using Ethereum’s ABI (Application Binary Interface) encoding. The payload includes:
      +
    • user: The address of the user who will receive the tokens on the destination chain
    • +
    • amount: The number of tokens to be transferred.
    • +
    • depositID: The depositId could be used to track or identify individual token transfer operations.
    • +
    +
  • +
  • onStateReceive: + Executed by the _stateVerifier (Dojima system account), + this function handles the minting of tokens on the primary chain (Dojima chain) based on the state received from other chains. + It decodes the user address, amount, and deposit ID from the received encoded data.
  • +
+

Roles and Security:

+
    +
  • _stateVerifier Role: A system-controlled account with exclusive rights to mint NFTs’ on the Dojima chain, ensuring security in the token minting process.
  • +
  • Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.
  • +
+

XNFTContract

+

This contract represents the NFTs on the Dojima Chain, detailing their properties and providing functions for their management within the Dojima ecosystem.

+

CrossChainNFT

+

Manages the lifecycle of NFTs’ on the secondary chains (Ethereum, Solana, Polkadot, etc.). +And links with OmniChainNFTContract through the Hermes Client.

+
    +
  • Burn: The Contract will burn user NFT on the secondary chain (Ethereum, Solana, Polkadot etc.) + and will send the state update to the Dojima chain to mint the same NFT on the Dojima chain for the same user.
  • +
  • Minting: The Contract will mint the NFT on the secondary chain based on the payload received from the Dojima chain by the executeState function.
  • +
+

Requirements

+
    +
  • Inbound State Sender: This is the contract address that is used to send updates from the secondary chain (Ethereum, Solana, Polkadot) to the primary chain (Dojima Chain).
  • +
  • ExecuteState: This is a function that needs to be implemented in the secondary chain contract to process the state updates received from the primary chain (Dojima Chain).
  • +
+

⚠️ Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. +Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

+

Workflow

+

Transfer From OmniChainERC20Contract to CrossChainERC20Contract

+
    +
  • Source Chain: The source chain here is Dojima Chain (Primary Chain).
  • +
  • Burning NFT for Transfer: In transferToChain, NFT for the user are burned on the primary chain (Dojima chain) to initiate cross-chain transfer.
  • +
  • Transfer Initiation: NFT transfers are initiated on the Dojima Chain through the OmniChainNFTContract, specifying the NFT and its destination.
  • +
  • State Synchronization: The transfer’s state is encoded and transmitted across chains via the Hermes Client, utilizing the outbound state sender for secure communication.
  • +
  • Functionality: The OutboundStateSender’s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) from the Dojima chain’s OmniChainERC20Contract to the secondary chain (Ethereum, Solana, Polkadot, etc.) CrossChainNFT contracts.
  • +
  • Usage in transferToChain: +
    outboundStateSender.transferPayload(
    +    destinationChain,
    +    destinationContractAddress,
    +    msg.sender,
    +    abi.encode(user, tokenId, depositID)
    +)
    +
  • +
+

⚠️ Warning: +The outboundStateSender contract is very crucial for the cross-chain transfer make sure you follow the steps +mentioned in the doc.

+
    +
  • After transfer payload: Once above step is successfully executed on a primary chain (Dojima Chain) the state update will be sent to the secondary chains (Ethereum, Solana, Polkadot etc.).
  • +
  • Minting on Destination Chain: Upon receiving the state, the CrossChainNFT contract on the secondary chain will mint the NFT for the intended recipient, completing the cross-chain transfer. +
        function executeState(uint256 depositID, bytes calldata payload) external {
    +        // Decode the payload
    +        (address userAddress, uint256 tokenId, uint256 depositId) = abi.decode(
    +            stateData, (address, uint256, uint256)
    +        );
    +        // Mint the NFT for the user
    +        // Process the state update
    +    }
    +
  • +
+

Transfer From CrossChainERC20Contract to OmniChainERC20Contract

+
    +
  • Destination Chain: The destination chain here is Secondary Chains (Ethereum, Solana, Polkadot).
  • +
  • Burn on Destination Chain: The CrossChainNFT contract will burn the specified NFT for the user on the secondary chain.
  • +
  • Transfer From Destination Chain: Encode the payload (user address, tokenID, depositID) and transfer from the secondary chains (Ethereum, Solana, Polkadot etc.) to the Dojima chain through the Inbound State Sender
  • +
  • Usage in transferToOmniChain: +
       function transferToOmniChain(bytes memory user, uint256 amount) external nonReentrant {
    +        _burn(tokenId);
    +        inboundStateSender.transferPayload(
    +          omniChainContractAddress,
    +          abi.encode(user, tokenId, depositID)
    +        );
    +    }
    +
  • +
  • After transfer payload: Once above step is successfully executed on secondary chains (Ethereum, Solana, Polkadot etc.) the state update will be sent to the Dojima chain.
  • +
  • State Receive on Source Chain: Upon receiving the state, + OmniChainERC20Contract which is on Dojima Chain will decode the user address, amount, + deposit ID will mint the specified number of tokens for the intended recipient, completing the cross-chain transfer. + and deposit IDand mints the XERC20 token for the user.
  • +
+

Security and Best Practices

+
    +
  • Smart Contract Audits: Ensure comprehensive audits of all contracts involved in the NFT transfer process to identify and mitigate potential security risks.
  • +
  • Secure Communication Channels: Utilize secure and verified communication channels for the transmission of state information between chains.
  • +
  • Role-Based Access Control: Implement and strictly enforce role-based access control within contracts to prevent unauthorized actions.
  • +
+

Conclusion

+

The OmniChainNFT Suite marks a significant advancement towards achieving seamless NFT interoperability across blockchain networks. By providing a standardized framework for cross-chain NFT transfers, it opens up new possibilities for NFT utilization and enhances the overall blockchain ecosystem’s connectivity.

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/transactions/index.html b/developer/transactions/index.html new file mode 100644 index 0000000..81116ae --- /dev/null +++ b/developer/transactions/index.html @@ -0,0 +1,3493 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Transactions - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Transaction

+ +

Here’s the guide to sending a Dojima coin to any account

+

1. First, log into your Dojima Wallet account. If you don’t have a seed phrase, follow these steps.

+
+

Info

+
+

If you don’t have Doj Tokens, proceed to FAUCET to get testnet tokens.

+

2. Select Dojima coin and select ‘Send’.

+

medium

+

3. Enter the receiver’s Dojima Public Address.

+

medium

+

4. Enter the amount to send.

+

medium

+

5. Choose the network speed.

+

medium

+

7. Verify the details, like the receiver’s public address, the transfer amount, and the network speed

+

medium

+

8. Transaction completed anf details get displayed

+

medium

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/developer/verifying-smart-contract/index.html b/developer/verifying-smart-contract/index.html new file mode 100644 index 0000000..84abccb --- /dev/null +++ b/developer/verifying-smart-contract/index.html @@ -0,0 +1,3392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Verifying A Smart Contract - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Verifying A Smart Contract

+ +

Once verified, a smart contract or token contract’s source code becomes publicly available and verifiable. This creates transparency and trust. Plus, it’s easy to do! Verification is available for Solidity.

+

Smart Contract Verification with Blockscout

+

1) You will be given an address to check a pending transaction after the contract is created. If it doesn’t take you to https://doj-bex-test.dojima.network/, go to Dojima Chain block explorer, make sure you’re on the chain where the contract was set up, then type the address of the contract into the search field. Your contract details should come up. +medium +medium +medium

+

2) To view the bytecode, select the Code tab and press the Verify and Publish button. Several options for verification will be available to you. Please select the “via flattened source code” (solidity) option.

+

medium

+

Via Flattened Source Code

+

medium

+
    +
  1. Contract Address: The 0x address entered when the contract was created
  2. +
  3. Contract Name: The name of the class that was mentioned in the.sol files. In the contract MyContract {.. MyContract , for example, the contract’s name is MyContract.
  4. +
  5. Include Nightly Builds: If you wish to display nightly builds, then yes.
  6. +
  7. Compiler: Taken from the first line of the X.X.X. contract's pragma solidity. Use the appropriate compiler instead of the nightly build.
  8. +
  9. EVM Version: See EVM version details.
  10. +
  11. Optimization: Check yes if you made optimization available during compilation.
  12. +
  13. Optimization Runs: The default value for the Solidity Compiler is 200. change only if you modified this value during compilation.
  14. +
  15. Enter the Solidity Contract Code: If your solidity code uses a library or inherits dependencies from another contract, you might need to flatten it. The POA solidity flattener or the truffle flattener are our recommendations.
  16. +
  17. Try to fetch constructor arguments automatically: Similar contracts might be offered if they exist.
  18. +
  19. ABI-encoded Constructor Arguments: See this page for more info.
  20. +
  21. Add Contract Libraries: For any necessary libraries that must be called in the .sol file, enter their name and 0x address. +Choose "Verify and Publish" from the menu. +If everything is going well, you should notice a tick next to Code in the code tab and a new tab labelled "Read Contract."Any transactions related to your contract will now be listed in BlockScout with the contract name.
  22. +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/Core-Icon.png b/img/Core-Icon.png new file mode 100644 index 0000000..3cc12e8 Binary files /dev/null and b/img/Core-Icon.png differ diff --git a/img/Core-Icon.svg b/img/Core-Icon.svg new file mode 100644 index 0000000..156d42c --- /dev/null +++ b/img/Core-Icon.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/img/Core.png b/img/Core.png new file mode 100644 index 0000000..1a3263a Binary files /dev/null and b/img/Core.png differ diff --git a/img/Core.svg b/img/Core.svg new file mode 100644 index 0000000..34664a2 --- /dev/null +++ b/img/Core.svg @@ -0,0 +1,5572 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/Developer-Icon.png b/img/Developer-Icon.png new file mode 100644 index 0000000..2967bcf Binary files /dev/null and b/img/Developer-Icon.png differ diff --git a/img/Developer-Icon.svg b/img/Developer-Icon.svg new file mode 100644 index 0000000..8f314af --- /dev/null +++ b/img/Developer-Icon.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/Developer.png b/img/Developer.png new file mode 100644 index 0000000..2b3a4ca Binary files /dev/null and b/img/Developer.png differ diff --git a/img/Developer.svg b/img/Developer.svg new file mode 100644 index 0000000..2b247e6 --- /dev/null +++ b/img/Developer.svg @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/OBJECTS.svg b/img/OBJECTS.svg new file mode 100644 index 0000000..4f47070 --- /dev/null +++ b/img/OBJECTS.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/Tools-Icon.png b/img/Tools-Icon.png new file mode 100644 index 0000000..d146c9d Binary files /dev/null and b/img/Tools-Icon.png differ diff --git a/img/Tools-Icon.svg b/img/Tools-Icon.svg new file mode 100644 index 0000000..1e602aa --- /dev/null +++ b/img/Tools-Icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/img/Tools.png b/img/Tools.png new file mode 100644 index 0000000..bc73d70 Binary files /dev/null and b/img/Tools.png differ diff --git a/img/Tools.svg b/img/Tools.svg new file mode 100644 index 0000000..0570778 --- /dev/null +++ b/img/Tools.svg @@ -0,0 +1,2632 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/Validator-Icon.png b/img/Validator-Icon.png new file mode 100644 index 0000000..4f74caa Binary files /dev/null and b/img/Validator-Icon.png differ diff --git a/img/Validator-Icon.svg b/img/Validator-Icon.svg new file mode 100644 index 0000000..4acb219 --- /dev/null +++ b/img/Validator-Icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/img/Validator.png b/img/Validator.png new file mode 100644 index 0000000..fec15c6 Binary files /dev/null and b/img/Validator.png differ diff --git a/img/Validator.svg b/img/Validator.svg new file mode 100644 index 0000000..d333810 --- /dev/null +++ b/img/Validator.svg @@ -0,0 +1,616 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/developer-1.png b/img/developer-1.png new file mode 100644 index 0000000..c00c4fb Binary files /dev/null and b/img/developer-1.png differ diff --git a/img/dojimaicon.svg b/img/dojimaicon.svg new file mode 100644 index 0000000..e4841f1 --- /dev/null +++ b/img/dojimaicon.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/github.svg b/img/github.svg new file mode 100644 index 0000000..947b23d --- /dev/null +++ b/img/github.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/img/hermes.svg b/img/hermes.svg new file mode 100644 index 0000000..464175c --- /dev/null +++ b/img/hermes.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/img/hermes/awseks.png b/img/hermes/awseks.png new file mode 100644 index 0000000..b1c1413 Binary files /dev/null and b/img/hermes/awseks.png differ diff --git a/img/hermes/awsregion.png b/img/hermes/awsregion.png new file mode 100644 index 0000000..52ead67 Binary files /dev/null and b/img/hermes/awsregion.png differ diff --git a/img/hermes/dojimainvester.jpg b/img/hermes/dojimainvester.jpg new file mode 100644 index 0000000..a81884a Binary files /dev/null and b/img/hermes/dojimainvester.jpg differ diff --git a/img/hermes/helmdeploy.png b/img/hermes/helmdeploy.png new file mode 100644 index 0000000..fc51fd3 Binary files /dev/null and b/img/hermes/helmdeploy.png differ diff --git a/img/hermes/hermesdeploy.png b/img/hermes/hermesdeploy.png new file mode 100644 index 0000000..0ba17cb Binary files /dev/null and b/img/hermes/hermesdeploy.png differ diff --git a/img/hermes/seamless-deployment.svg b/img/hermes/seamless-deployment.svg new file mode 100644 index 0000000..538b0d4 --- /dev/null +++ b/img/hermes/seamless-deployment.svg @@ -0,0 +1,727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000..bd78521 Binary files /dev/null and b/img/logo.png differ diff --git a/img/rightimage.png b/img/rightimage.png new file mode 100644 index 0000000..86bf56f Binary files /dev/null and b/img/rightimage.png differ diff --git a/img/rightimage.svg b/img/rightimage.svg new file mode 100644 index 0000000..c7ed125 --- /dev/null +++ b/img/rightimage.svg @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/rightuparrow.svg b/img/rightuparrow.svg new file mode 100644 index 0000000..f3d8896 --- /dev/null +++ b/img/rightuparrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/img/rounded-right-arrow.svg b/img/rounded-right-arrow.svg new file mode 100644 index 0000000..0c9840b --- /dev/null +++ b/img/rounded-right-arrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/img/tools-1.png b/img/tools-1.png new file mode 100644 index 0000000..64ce150 Binary files /dev/null and b/img/tools-1.png differ diff --git a/img/validator-1.png b/img/validator-1.png new file mode 100644 index 0000000..f580212 Binary files /dev/null and b/img/validator-1.png differ diff --git a/img/wallet/send/enter_address.png b/img/wallet/send/enter_address.png new file mode 100644 index 0000000..80f2228 Binary files /dev/null and b/img/wallet/send/enter_address.png differ diff --git a/img/wallet/send/enter_amount.png b/img/wallet/send/enter_amount.png new file mode 100644 index 0000000..e6893e3 Binary files /dev/null and b/img/wallet/send/enter_amount.png differ diff --git a/img/wallet/send/receive_asset.png b/img/wallet/send/receive_asset.png new file mode 100644 index 0000000..c93b3b4 Binary files /dev/null and b/img/wallet/send/receive_asset.png differ diff --git a/img/wallet/send/review_details.png b/img/wallet/send/review_details.png new file mode 100644 index 0000000..4fd007b Binary files /dev/null and b/img/wallet/send/review_details.png differ diff --git a/img/wallet/send/select_asset.png b/img/wallet/send/select_asset.png new file mode 100644 index 0000000..5ccea1e Binary files /dev/null and b/img/wallet/send/select_asset.png differ diff --git a/img/wallet/send/select_gas.png b/img/wallet/send/select_gas.png new file mode 100644 index 0000000..c31de53 Binary files /dev/null and b/img/wallet/send/select_gas.png differ diff --git a/img/wallet/send/tx_details.png b/img/wallet/send/tx_details.png new file mode 100644 index 0000000..68ec35c Binary files /dev/null and b/img/wallet/send/tx_details.png differ diff --git a/img/wallet/wallet.svg b/img/wallet/wallet.svg new file mode 100644 index 0000000..a1cec1c --- /dev/null +++ b/img/wallet/wallet.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..4f6e5a8 --- /dev/null +++ b/index.html @@ -0,0 +1,3599 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+
+ +
+
+
+
+

The Layer of Dojima Knowledge

+
+

Welcome to the Dojima Network Documentation! As pioneers in the Web3 space, we're thrilled to guide you through the seamless world of crosschain connectivity.

+

Our documentation is crafted to empower you, whether you're developing innovative applications or diving into blockchain technology for the first time. Here, you'll find everything you need to harness the full potential of Dojima Network. Dive in, explore, and join us in shaping the future of a unified Web3 ecosystem. Your journey towards groundbreaking discoveries starts now! +

+
+ + + +
+
+
+
+
+
+
+
+
+
+
+ +

Core

+
+

Unveiling Dojima Network's essence, highlighting the innovative infrastructure of Hermes and Dojima chains.

+ +
+
+
+
+
+ +

Developers

+
+

Your resource hub for seamless onboarding and support within our evolving ecosystem.

+ +
+
+
+
+
+
+ +

Tools

+
+

Explore our versatile tools section featuring a cross-chain wallet, innovative FAAS solution, and developer dashboard for seamless integration.

+ +
+

Dojima Wallet

+ + + +
+

Dojima wallet lets you organise major layer 1 tokens in one place.

+
+ +
+

Dojima Fass

+ + +
+

Dojima FAAS offers blockchain services like transaction signing and history viewing.

+
+ + + +
+
+
+ +

Validator

+
+

Unlock the path to becoming a valued validator with our comprehensive documentation, empowering you to safeguard the integrity of our blockchain network.

+ +
+
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..90fa0d3 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"The Layer of Dojima Knowledge

Welcome to the Dojima Network Documentation! As pioneers in the Web3 space, we're thrilled to guide you through the seamless world of crosschain connectivity.

Our documentation is crafted to empower you, whether you're developing innovative applications or diving into blockchain technology for the first time. Here, you'll find everything you need to harness the full potential of Dojima Network. Dive in, explore, and join us in shaping the future of a unified Web3 ecosystem. Your journey towards groundbreaking discoveries starts now!

Get Started Core

Unveiling Dojima Network's essence, highlighting the innovative infrastructure of Hermes and Dojima chains.

What is Dojima Network? Hermes Chain Developers

Your resource hub for seamless onboarding and support within our evolving ecosystem.

Templates Faucet Developer Dashboard Coming Soon Tools

Explore our versatile tools section featuring a cross-chain wallet, innovative FAAS solution, and developer dashboard for seamless integration.

Dojima Wallet

Dojima wallet lets you organise major layer 1 tokens in one place.

Dojima Fass

Dojima FAAS offers blockchain services like transaction signing and history viewing.

Validator

Unlock the path to becoming a valued validator with our comprehensive documentation, empowering you to safeguard the integrity of our blockchain network.

"},{"location":"core/","title":"Core","text":"Core

Unveiling Dojima Network's essence, highlighting the innovative infrastructure of Hermes and Dojima chains.

What is Dojima Network?

Dojima Network is an omnichain Layer-1 designed to integrate the diverse Web3 ecosystem into a single, unified layer.

Dojima Chain

Dojima Chain serves as the backbone for developer transactions, facilitating seamless onboarding and efficient execution of all development-related activities on our platform

Hermes Chain

Hermes Chain powers staking, liquidity pools, and vital ecosystem functions, ensuring robust decentralised finance capabilities for our platform.

"},{"location":"core/about-us/","title":"About Us","text":"

The term Dojima has its origin in Japan. Dojima was derived from the name of the world\u2019s first derivative exchange in Japan in the 16th century and was adopted for the Dojima Network.

The Dojima Network was founded by Bhagath Reddy and Akhil Reddy in 2020 following the inherent problems associated with the new web 3 space. While working on a major Ethereum protocol between 2019 and 2020, Bhagath and Akhil were faced with daunting problems with regard to high gas fees and the limitation of only accessing tokens from the Ethereum blockchain. Based on this problem, they observed that all developers on every independent blockchain are limited by the ecosystem of that particular blockchain, thereby leading to non-provision for developers to access the best of all the blockchain platforms, hence the idea and birth of the Dojima Network.

Since its inception, the Dojima Network team has been working round the clock to build a robust cross-chain platform to bring in liquidity, Dapps, and users to a common middle ground, thereby eliminating the need to use multiple wallets and blockchains. This has been possible by organizing a team that is capable of building a decentralized product for the crypto space.

The Dojima Network founders have built the initial team and designed the architecture and also managed to bring together the initial components required for MVP and demoed it on Arweave Open Web Foundry and subsequently formed a few partnerships. Ever since the team has grown five times from what it used to be in the span of 6 months. But we have not stopped there. The team is continuously acquiring good and suitable talents as per requirement.

In 2021, we got incubated by the Arweave Open Web Foundry and we became the finalist. Shortly after that (precisely Q4 2021), we completed our seed round and got funding from the top VCs in the crypto space.

Based on requirements and value proposition alongside capital, the Dojima team would consider investors from the non-crypto space. But at the moment we are happy with the investors that are already on board to push this project to fruition.

Fast forward to the third quarter of 2022 we are gearing up to launch our testnet in Q3 of 2022. The launch of the testnet will also follow with the release of cross-chain platforms along with a cross-chain wallet and cross-chain applications for testing purposes. During this period, proper documentation would be implemented for deploying and establishing a cross-chain connection on the Dojima network. So, between the period of the testnet and mainnet, a suite of tools will be released for easy onboarding and deployment of Dapps onto the Dojima Network.

Also worthy of note is that during this period, our revamped website would be launched in preparation for the testnet and subsequently the mainnet launch in the first half of 2023. The new website will go live in Q3 2022. Do not hesitate to check our new website on https://www.dojima.network and familiarize yourself with it.

The aim of dojima network has been stated, the project is in the pipeline, the road map has been set, the team is working and growing, and something unique is coming. Dojima Network will surely be a catalyst in the blockchain and crypto cross-chain infrastructure space.

You can keep abreast of all Dojima Network activities prior to the test net and beyond the main net by following us on all our channels below. You are just a click away from reaching us.

"},{"location":"core/dojima-chain/","title":"Dojima Chain","text":"

\u201cWhat is Dojima Chain?\u201d Dojima Chain is an integral layer of the Dojima Network, specifically tailored for seamless integration of assets, NFTs, and DeFi applications across various blockchains. It stands out for its commitment to security, interoperability, and scalability, powered by a decentralized network of validators.

The Dojima Chain offers users the unique capability to interact with major tokens from different blockchains directly on its platform. This feature eliminates the need for users to jump between different chains, as all crosschain assets are readily available on the Dojima Chain. This seamless integration and accessibility streamline the user experience, making Dojima Chain a convenient and efficient platform for managing and transacting with a variety of blockchain assets.

  1. Seamless Interaction with Major Chains: It allows interaction with tokens from all major chains, providing a platform for protocols to engage comprehensively.
  2. Simplified Omnichain DApp Development: The platform makes building omnichain DApps more accessible than ever.
  3. Broad Connectivity: Developers can connect any chain to their omnichain DApp on the Dojima Chain, enhancing versatility and reach.
  4. Formation of an Omnichain Hub: A central hub is being developed on the Dojima Network, further integrating diverse blockchain ecosystems.

\u201cWhy Dojima Chain is an integral part of web3 expansion\u201d

As blockchains become increasingly diverse and specialized, the ability to integrate and interact across these varied platforms becomes crucial. Dojima Chain addresses this by providing a unified, omnichain platform that simplifies the interaction between different blockchain ecosystems, making it essential for developers and users seeking to leverage the strengths of multiple chains in a single application. Its features like interoperability, robust validator network, EVM compatibility, the utility of the Dojima Token, and a fair block producer selection process make it an attractive choice for those looking to develop or use decentralized applications. By facilitating seamless integration and operation across various blockchains, the Dojima Chain stands as a key enabler in the evolution of a more interconnected and efficient blockchain environment.

The Dojima Chain, as an essential part of the Dojima Network, offers several key features:

  1. Interoperability: By being connected to various blockchain layers, Dojima chain facilitates a unified environment where different blockchain ecosystems can interact seamlessly. This feature is crucial for asset and data integration across multiple platforms.
  2. Validator Network: Ensures the security and integrity of transactions within the network. Validators play multiple roles such as block production, transaction validation, and participating in consensus mechanisms, which are vital for maintaining the network\u2019s trustworthiness.
  3. EVM Compatibility: Allows developers to deploy and execute smart contracts using popular programming languages like Solidity, making it easier to integrate existing Ethereum-based applications and tools into the Dojima ecosystem.
  4. Block Producer Selection: This process is designed to maintain fairness and efficiency in block generation and validation, based on validators\u2019 staked tokens. Block producers are more likely to be elected for block generation based on their stake, with embedded churning and shuffling mechanisms to enhance fairness and security.

These features collectively contribute to making the Dojima Chain a powerful and versatile platform for the development and operation of decentralized applications, especially in the context of a rapidly evolving blockchain and Web3 landscape.

"},{"location":"core/hermes-chain/","title":"Hermes chain","text":""},{"location":"core/hermes-chain/#omnichain-erc20-chain","title":"Omnichain ERC20 Chain","text":""},{"location":"core/hermes-chain/#omnichaintokencontract-suite-documentation","title":"OmniChainTokenContract Suite Documentation","text":""},{"location":"core/hermes-chain/#overview","title":"Overview","text":"

The OmniChainTokenContract Suite is an advanced toolkit designed for the Dojima chain, facilitating the seamless transfer and management of tokens across multiple blockchain networks, including Ethereum, Solana, and others.

"},{"location":"core/hermes-chain/#components","title":"Components","text":""},{"location":"core/hermes-chain/#omnichaintokencontractacts-as-the-central-hub-within-the-dojima-chain-managing-the-lifecycle-of-cross-chain-tokens","title":"OmniChainTokenContractActs as the central hub within the Dojima chain, managing the lifecycle of cross-chain tokens.","text":""},{"location":"core/hermes-chain/#key-functions","title":"Key Functions:","text":"

transferToChain: This function enables the transfer of tokens from the Dojima chain to other blockchains. It involves burning tokens on the Dojima chain and initiating a state sync process to mint corresponding tokens on the target chain.

outboundStateSender.transferPayload( destinationChain, destinationContractAddress, msg.sender, abi.encode(user, amount, 0) // TODO: add depositId )\n

The transferPayload function in the transferToChain method has the following parameters:

  • destinationChain: The target chain for the cross-chain transfer.
  • destinationContractAddress: This is the address of the contract on the target blockchain that will receive and process the payload. It\u2019s usually the address of a smart contract that has a function to handle such incoming payloads.
  • msg.sender: This is the address of the entity (usually a user or another contract) that initiated the token transfer on the Dojima chain.
  • abi.encode(user, amount, 0): This is the payload that is being transferred to the target blockchain. It\u2019s encoded using Ethereum\u2019s ABI (Application Binary Interface) encoding. The payload includes:
  • user: The address of the user who will receive the tokens on the target blockchain
  • amount: The amount of tokens to be transferred.
  • 0: This is a placeholder for the depositId. It\u2019s currently set to 0 as indicated by the TODO comment. The depositId could be used to track or identify individual token transfer operations.

onStateReceive: Executed by the _stateVerifier (Dojima system account), this function handles the minting of tokens on the Dojima chain based on the state received from other chains. It decodes the user address, amount, and deposit ID from the received encoded data.

"},{"location":"core/hermes-chain/#roles-and-security","title":"Roles and Security:","text":"

_stateVerifier Role: A system-controlled account with exclusive rights to mint tokens on the Dojima chain, ensuring security in the token minting process.

Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.

"},{"location":"core/hermes-chain/#xtokencontractan-erc20-token-contract-on-the-dojima-chain-foundational-for-the-cross-chain-functionalities","title":"XTokenContractAn ERC20 token contract on the Dojima chain, foundational for the cross-chain functionalities.","text":""},{"location":"core/hermes-chain/#ethereumcrosschaintokencontractmanages-the-lifecycle-of-tokens-on-the-ethereum-network-and-links-with-omnichaintokencontract-through-the-hermes-bridge","title":"EthereumCrossChainTokenContractManages the lifecycle of tokens on the Ethereum network and links with OmniChainTokenContract through the Hermes bridge.","text":""},{"location":"core/hermes-chain/#system-integration","title":"System Integration","text":""},{"location":"core/hermes-chain/#outboundstatesender","title":"OutboundStateSender","text":"

Functionality: The OutboundStateSender\u2019s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) to the Dojima chain\u2019s OmniChainTokenContract.

Significance: Ensures the synchronization of token states across chains, triggering corresponding actions (burn or mint) in the connected contracts.

Usage in transferToChain:

 outboundStateSender.transferPayload(\n   destinationChain,\n   destinationContractAddress,\n   msg.sender,\n   abi.encode(user, amount, 0) )\n

Info

Read More about how to interact with outbound state sender

Warning

*Note: The outboundStateSender contract is very crucial for the cross chain transfer make sure you follow the steps mentioned in the doc.## Contract Interaction Flow1. **Burning Tokens for Transfer: In transferToChain, tokens are burned on the Dojima chain to initiate cross-chain transfer.2. State Synchronization: The burning triggers a state sync process via the Hermes bridge, sending encoded data to the target chain.3. Minting Tokens on Dojima: In onStateReceive, tokens are minted on the Dojima chain for the specified user, amount, and deposit ID.## Security and Best PracticesAudit Compliance: Ensure all contracts undergo thorough security audits.Transaction Monitoring: Implement systems to monitor and verify cross-chain transactions regularly.Role Management: Strictly manage role assignments, especially for critical roles like _stateVerifier.**Gas Optimization**: Aim for efficiency in contract execution to minimize transaction costs.## ConclusionThe OmniChainTokenContract Suite represents a significant step towards seamless blockchain interoperability, with a focus on security, efficiency, and developer-friendliness. It is crucial for developers to understand the intricacies of the suite to leverage its full potential in their DApp development.

"},{"location":"core/what-is-dojima-network/","title":"What is Dojima Network?","text":"

Dojima Network is an omnichain Layer-1 designed to integrate the diverse Web3 ecosystem into a single, unified layer that revolutionizes the way decentralized applications (DApps) are developed and utilized across multiple blockchain networks.

It introduces a unique architecture composed of two primary components:

  1. DojimaChain: An EVM-compatible blockchain that acts as a middle ground for developers. It enables the easy deployment of complex cross-chain applications, simplifying the development process by supporting commonly used programming languages and tools.
  2. Hermes Layer: Built on the Cosmos SDK and Tendermint, this layer connects DojimaChain to various other blockchains, facilitating seamless interaction and liquidity sharing across different ecosystems.

Together, DojimaChain and Hermes Layer empower developers to create versatile, cross-chain applications, overcoming the traditional barriers of isolated blockchain networks. This positions Dojima Network as a catalyst for the expansion and integration of Web3 technologies, appealing to a wide range of users, developers, and investors in the blockchain community.

Founded by experts with rich backgrounds in blockchain technology, Dojima Network is backed by significant industry players, reflecting its potential to shape the future of decentralized applications and cross-chain interoperability.

"},{"location":"core/architecture/dojimachain/","title":"Dojima Chain","text":""},{"location":"core/architecture/dojimachain/#introduction","title":"Introduction","text":"

The Dojima Chain is a critical component of the Dojima Network ecosystem, serving as a foundational layer for the seamless integration of assets, NFTs, and decentralized finance (DeFi) applications from various interconnected blockchains. Designed with security, interoperability, and scalability in mind, the Dojima Chain is powered by a decentralized network of Proof-of-Stake (PoS) validators.

"},{"location":"core/architecture/dojimachain/#key-features","title":"Key Features","text":""},{"location":"core/architecture/dojimachain/#1-interoperability","title":"1. Interoperability:","text":"

The Dojima Chain is designed to bridge the divide between multiple layer 1 and layer 2 blockchains. It acts as a pivotal middle-ground where assets and data from diverse blockchain ecosystems converge, fostering cross-chain compatibility.

"},{"location":"core/architecture/dojimachain/#2-validator-network","title":"2. Validator Network:","text":"

Security is paramount, and the Dojima Chain relies on a network of validators to ensure the integrity and trustworthiness of transactions and data. Validators within the Dojima Network ecosystem play multifaceted roles, including running full nodes, block production, transaction validation, consensus participation, relayer and oracle services, and checkpoint commitment.

"},{"location":"core/architecture/dojimachain/#3-ethereum-virtual-machine-evm-compatibility","title":"3. Ethereum Virtual Machine (EVM) Compatibility:","text":"

The Dojima Chain seamlessly integrates with the Ethereum Virtual Machine (EVM), enabling developers to deploy and execute smart contracts using familiar languages such as Solidity. This compatibility empowers developers to leverage existing Ethereum-based applications and tools within the Dojima ecosystem.

"},{"location":"core/architecture/dojimachain/#4-dojima-token-doj","title":"4. Dojima Token (DOJ):","text":"

Transactions within the Dojima Chain are facilitated using the native token, Dojima (DOJ). DOJ operates both as an ERC-20 token and as the native token for the Dojima network. This dual functionality allows users to pay gas fees, participate in staking, and transfer value within the ecosystem.

"},{"location":"core/architecture/dojimachain/#5-block-producer-selection","title":"5. Block Producer Selection:","text":"

The Dojima Chain employs a committee of Block Producers, selected from the validator pool, to ensure efficient block generation and validation. The selection process is based on the validators\u2019 staked tokens, with regular shuffling to maintain fairness and security.

"},{"location":"core/architecture/dojimachain/#block-producer-selection-process","title":"Block Producer Selection Process","text":"

The Block Producer selection process in the Dojima Chain is designed to ensure fairness and security. Here\u2019s a simplified example of how it works:

Imagine a validator pool with 4 validators: Validator1, Validator2, Validator3, and Validator4. Each validator has staked a different amount of DOJ tokens. Validator1 has staked 200 DOJ tokens, Validator2 has staked 150 DOJ tokens, Validator3 has staked 100 DOJ tokens, and Validator4 has staked 50 DOJ tokens.

Validators are assigned slots proportionally to their stake. The total number of slots allocated is 10. Here\u2019s the distribution of slots:

  • Validator1: 4 slots
  • Validator2: 3 slots
  • Validator3: 2 slots
  • Validator4: 1 slot

Now, let\u2019s shuffle the slots using a random seed. After shuffling, we get the following sequence: [Validator3, Validator1, Validator2, Validator2, Validator4, Validator1, Validator3, Validator1, Validator2, Validator3].

Next, based on the number of producers to be selected (let\u2019s say we need to select 3 producers), we pick validators from the top of the shuffled list. In this case, the producer set for the next span is defined as:

  • Producer1: Validator3
  • Producer2: Validator1
  • Producer3: Validator2

These selected validators will take on the role of Block Producers for the next span in the DojimaChain network. This illustrates the producer selection process in the DojimaChain ecosystem.

"},{"location":"core/architecture/dojimachain/#system-call-interface","title":"System Call Interface","text":"

Within the Dojima Chain\u2019s EVM, the System Call Interface plays a vital role. It serves as an internal operator address, enabling the maintenance of Block Producer states at specified block intervals. System Calls trigger requests for updated Block Producer lists, ensuring the network\u2019s smooth operation.

"},{"location":"core/architecture/dojimachain/#state-syncing","title":"State Syncing","text":"

The Dojima Chain maintains synchronization with different blockchains through the Hermes Chain. This synchronization process ensures that state data from various native chains is securely integrated into the Dojima ecosystem. Validators validate the data using a Threshold Signature Scheme before it is stored in the Hermes Chain.

"},{"location":"core/architecture/dojimachain/#conclusion","title":"Conclusion","text":"

The Dojima Chain is at the core of the Dojima Network\u2019s mission to provide developers with a powerful, secure, and interoperable platform for building cross-chain applications. With EVM compatibility, robust validator networks, and advanced features, it stands as a key element in the evolution of the blockchain and Web3 space.

"},{"location":"core/architecture/hermeschain/","title":"Hermes Chain","text":""},{"location":"core/architecture/hermeschain/#hermes-layer","title":"Hermes Layer","text":"

The Hermes layer is a vital component within the Dojima Network\u2019s multi-layer architecture, playing a crucial role in ensuring seamless cross-chain interoperability and efficient liquidity management. Its primary responsibilities include managing native token liquidity from all blockchains, overseeing staking and rewards management for liquidity providers. It ensures the proper functioning of validators, enforces slashing mechanisms for network security, collects transaction fees, and, most importantly, offers developers universal access to cross-chain liquidity. This layer plays a pivotal role in enabling seamless interoperability and efficient liquidity management across the Dojima Network.

Main modules inside Hermes Chain are: - Narada - Threshold signature scheme - Fortunas - Sors

"},{"location":"core/architecture/hermeschain/#narada","title":"Narada","text":"

Narada functions as a central hub connecting clients to the Hermes chain. Its primary responsibility is to monitor blockchain events i.e. swapping of Arweave -> Ethereum, Arweave -> Dojima and other custom messages. It also transforms these events into Hermes layer-compatible messages and relays them to the hermes layer.

  • Chain clients

    Chain clients are responsible for reading events from their respective blockchains. Client will listen to hermes wallet address transactions as destination/target address. Currently supported chain clients are Arweave, Bitcoin, Binance, Cosmos, Ethereum, Solana, Polkadot.

  • Observer

    Observer is responsible for transforming and transmitting observed events to the hermes layer.

  • Signer

    Signer is responsible for signing transactions onto the destination chain that received from the Hermes chain.

"},{"location":"core/architecture/hermeschain/#threshold-signature-scheme-tss","title":"Threshold signature scheme ( TSS )","text":"

Threshold signature scheme is responsible for securing the liquidity which is being held in the Hermes chain. Liquidity is holded by fortunas vaults. Dojima has written many articles on tss, please checkout https://medium.com/@dojimanetwork for more on tss. Each chain supports certains signature mechanism for signing wallet transactions like secp256k1 curve of ECDSA algorithm for Ethereum, Binance, Cosmos, Binance and RSA for Arweave and ed25519 for Solana, Polkadot. Currently, dojima has support for ecdsa, rsa, ed25519 signature algorithms.

"},{"location":"core/architecture/hermeschain/#fortunas","title":"Fortunas","text":"

Fortunas are responsible for holding liquidity of multiple tokens at single place which are generated by dojima tss. Security of liquidity depends on the number of validators managed by tss. When swapping of tokens are involved ( Binance -> Arweave), \u2154 of validators will sign to release the desired token amount on the destination chain requested for swap received from the hermes chain. Since tss is a slow process, for small swap amounts is a drawback. To overcome this, Sors is introduced.

"},{"location":"core/architecture/hermeschain/#sors","title":"Sors","text":"

Sors are responsible for sending small amounts of requested swap tokens onto the destination chain. Each validator can be a sors. Validator will be assigned 25% of total amount supported tokens based on validator staked amount.

"},{"location":"core/architecture/overview/","title":"Overview","text":""},{"location":"core/architecture/overview/#dojima-architecture","title":"Dojima Architecture","text":"

Dojima Network is built on a multi-layer architecture comprising two blockchains that collaboratively interact with other blockchains. This design enables liquidity access and serves as a cross-chain development platform for creating cross-chain applications. These layers include the Hermes layer and the DojimaChain.

  • The Hermes layer is built on top of the Cosmos SDK and tendermint. It is the buffer layer that is connected to various independent blockchains.

  • DojimaChain operates as the intermediate layer where developers deploy applications and access the Hermes layer to establish connections with all chains.

In simple terms, we will create a buffer layer on top of Cosmos SDK and Tendermint, establishing connections with major blockchains while maintaining liquidity pools for the Dojima native token(DOJ) and other tokens of prominent blockchain platforms. Liquidity data will be available and verified by all validators at the end of each block and supplied to contracts on the intermediate layer, Dojima chain. This data can be accessed by smart contracts developed by cross-chain DApp creators.

Some of the features that Dojima Network offers include:

  1. Universal Liquidity Access: This enables developers to access the liquidity of all blockchains directly from their protocols.

  2. Cross-Chain Execution and Transfer: This enables users to execute contract code on multiple platforms and also enables cross-chain data transfer to communicate with custom smart contracts.

  3. Cross-Chain Liquidity Pools: This feature enables developers and users to access cross-chain liquidity pools for executing various custom cross-chain actions

"},{"location":"core/architecture/contracts/inbound_state_sender/","title":"Inbound State Sender","text":""},{"location":"core/architecture/contracts/inbound_state_sender/#the-inbound-state-sender-contract","title":"The Inbound State Sender Contract","text":"

The Inbound State Sender Contract is a specialized smart contract. Its primary function is to assist developers of decentralized applications (dApps) in transmitting state updates from the source chain to the Dojima Chain. This contract operates on the source chain, enabling transactions to be carried out from the source chain to the Dojima Chain.

To utilize the State Sender Contract, follow these straightforward steps:

"},{"location":"core/architecture/contracts/inbound_state_sender/#step-1-copy-the-inbound-state-sender-contract-interface-from-github","title":"Step 1: Copy the Inbound State Sender Contract interface from GitHub","text":"
  • Get the Inbound State Sender Contract Interface from the GitHub repository here.
  • Copy the contract interface into its corresponding folder, typically located in, \u2019. /interfaces/\u2019 or as per your project structure.
"},{"location":"core/architecture/contracts/inbound_state_sender/#step-2-obtain-the-inbound-state-sender-contract-address","title":"Step 2: Obtain the Inbound State Sender Contract Address","text":"
  • Retrieve the Inbound State Sender Contract address from the Dojima Chain Explorer.

\u26a0\ufe0f Warning: The Inbound State Sender Contract address may vary for different chains. Ensure that you select the appropriate chain i.e. (Ethereum, Avalanche) and the appropriate network i.e. (mainnet or testnet).

"},{"location":"core/architecture/contracts/inbound_state_sender/#step-3-register-the-destination-contract","title":"Step 3: Register the Destination Contract","text":"

Before you can send state transaction to the Dojima Chain, you need to register the destination contract. This is done using the register function in the State Sender Contract. This function takes two parameters:

  • sender: This is the address of the contract that is sending the state update. In most cases, this will be the address of your contract.
  • receiver: This is the address of the contract that will receive the state update. This is what we call the destination contract.

Warning

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer. These steps will be added later.

"},{"location":"core/architecture/contracts/inbound_state_sender/#step-4-call-the-transferpayload-function","title":"Step 4: Call the transferPayload function","text":"
  • After registering the destination contract, you can now send state updates to it. This is done using the transferPayload function in the State Sender Contract. This function takes two parameters:

  • destinationContract: This is the address of the contract that will receive the state update. This is what we call the destination contract.

  • payload: This is the ABI-encoded contract call that you want to send to the destination contract.

Warning

DISCLAIMER:Below provided code example is for educational purposes only. It is not intended for use in a production environment or with real assets. Please exercise caution and ensure proper testing and validation of your code before deploying it in a production environment.

// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n\n// Import the interface from the GitHub repository\nimport { IInboundStateSender } from './interfaces/IInboundStateSender.sol';\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract App {\n    // Declare a variable to hold the address of the StateSender contract\n    address public stateSender;\n    uint256 public maxErc20Amount = 100 * (10**18);\n    IInboundStateSender public stateSender;\n    // Destination chain contract address (Polygon, Avalanche, etc.)\n    address public destinationContract;\n\n    constructor(address _stateSender, address _destContract) {\n        // Create an instance of the IStateSender interface using the StateSender address\n        stateSender = IInboundStateSender(_stateSender);\n        require(_destContract != address(0), \"Invalid destination contract address\");\n        destinationContract = _destContract;\n    }\n\n    function depositERC20(\n        address _token,\n        uint256 _amount\n    ) public {\n        require(_amount <= maxErc20Amount, \"exceed maximum deposit amount\");\n        require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), \"TOKEN_TRANSFER_FAILED\");\n\n        // Call the transferPayload function\n        stateSender.transferPayload(\n          destinationContract, abi.encode(msg.sender, _token, _amount)\n        );\n    }\n}\n
"},{"location":"core/architecture/contracts/inbound_state_sender/#step-5-event-emitted-by-the-state-sender-contract-tokentransferwithpayload","title":"Step 5: Event emitted by the State Sender Contract TokenTransferWithPayload","text":"
  • Once the State Sender Contract executes the transferPayload function, it emits an event called DataTransfer. This event plays a vital role in the interaction with Narada.
  • The DataTransfer event furnishes essential information in its parameters:
  • depositID - This identifier uniquely identifies deposits on the Dojima chain. It is relevant only when the destinationChain is Dojima.
  • destinationContract - It signifies the target contract to which the tokens and payload are delivered.
  • payload - This field holds the ABI-encoded contract call that was transmitted.
"},{"location":"core/architecture/contracts/outbound_state_sender/","title":"Outbound State Sender","text":""},{"location":"core/architecture/contracts/outbound_state_sender/#the-outbound-state-sender-contract","title":"The Outbound State Sender Contract","text":"

The Outbound State Sender Contract is a specialized smart contract. Its primary function is to assist developers of decentralized applications (dApps) in transmitting state updates and asset transfer from the Dojima Chain to the destination chain. This contract operates on the dojima chain, enabling transactions to be carried out from the Dojima Chain to the destination chain.

To utilize the State Sender Contract, follow these straightforward steps:

"},{"location":"core/architecture/contracts/outbound_state_sender/#step-1-copy-the-inbound-state-sender-contract-interface-from-github","title":"Step 1: Copy the Inbound State Sender Contract interface from GitHub","text":"
  • Get the Outbound State Sender Contract Interface from the GitHub repository here.
  • Copy the contract interface into its corresponding folder, typically located in, \u2019. /interfaces/\u2019 or as per your project structure.
"},{"location":"core/architecture/contracts/outbound_state_sender/#step-2-obtain-the-outbound-state-sender-contract-address","title":"Step 2: Obtain the Outbound State Sender Contract Address","text":"
  • Retrieve the Outbound State Sender Contract address from the Dojima Chain Explorer.
"},{"location":"core/architecture/contracts/outbound_state_sender/#step-3-register-the-destination-contract-destination-asset-and-destination-chain","title":"Step 3: Register the Destination Contract, Destination Asset and Destination Chain","text":"

Before you can send a state transaction or asset transaction to the destination chain, you need to make sure that everything is registered.

  • To use transferPayload function, you need to make sure that the following things are registered:
  • Destination Contract: This is the address of the contract that will receive the state update.
  • Destination Chain: This is the name chain that will receive the state update.
  • Steps to register destination address and chain:

Warning

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer.

  • To use transferAsset function, you need to make sure that the following things are registered:
  • Destination Address: This is the address of the user that will receive the transferred asset.
  • Destination Asset: This is the address of the asset that will be transferred to the destination chain.
  • Destination Chain: This is the name chain that will receive the asset update.
  • Steps to register destination address, asset and chain:

Warning

NOTE: The registration process involves certain steps that need to be followed on the Dojima Chain Block Explorer. These steps will be added later.

"},{"location":"core/architecture/contracts/outbound_state_sender/#step-4-calling-the-functions-to-transfer-payload-and-asset","title":"Step 4: Calling the functions to transfer payload and asset","text":"
  • Once you have registered all the details, you can now send state updates or transfer asset to the destination chain. This is done using the transferPayload and transferAsset functions in the Outbound State Sender Contract.
  • Fees for both function calls will be deducted from the caller\u2019s (in this case contract) account in the form of Dojima tokens. The caller needs to make sure that they have enough Dojima tokens in their account to pay the fees.
  • Transfer Payload function takes four parameters:
  • Destination Chain: This is the name of the destination chain in bytes32 format, that will receive the state update.
  • Destination Contract: This is the address of the contract in bytes format, that will receive the state update on a destination chain.
  • Refund Address : This is the address of the user in ETH address format that will receive the refund if the transaction fails.
  • Payload: This is the abi encoded contract call that in bytes format you want to send to the destination contract.

    • Note: The payload should be encoded as per the destination contract function.
  • Transfer Asset function takes five parameters:

  • Destination Chain: This is the name of the destination chain in bytes32 format, that will receive the asset.
  • Destination Address: This is the address of the user in bytes format, that will receive the asset on destination chain.
  • Refund Address : This is the address of the user in ETH address format that will receive the refund if the transaction fails.
  • Destination Asset: This is the address of the asset in bytes format that will be transferred to the destination chain.
  • Asset Amount: This is the amount of asset in uint256 format that will be transferred to the destination chain.

Warning

DISCLAIMER:Below provided code examples is for educational purposes only. It is not intended for use in a production environment or with real assets. Please exercise caution and ensure proper testing and validation of your code before deploying it in a production environment.

  • Example for how to use transferPayload function in contract-based chains:

// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n\n// Import the interface from the GitHub repository\nimport {IOutboundStateSender} from './interfaces/IOutboundStateSender.sol';\nimport {IERC20Burnable} from \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\ncontract ChildChain {\n\n  // mapping for (withdraw ID => true/false)\n  mapping(uint256 => bool) public withdraws;\n\n  // outbound state sender contract\n  IOutboundStateSender public outboundStateSender;\n\n  constructor(address _outboundStateSender) {\n    require(_outboundStateSender != address(0x0), 'Child Chain: Invalid OutboundStateSender address');\n\n    // Create an instance of the IOutboundStateSender interface using the OutboundStateSender address\n    outboundStateSender = IOutboundStateSender(_outboundStateSender);\n  }\n  /*\n   * @notice withdrawTokens\n   * @dev: amountOrTokenId: tokenId for ERC721 and amount for ERC20\n   * @param user address for deposit\n   * @param rootToken root token address\n   * @param withdrawId\n   */\n  function withdrawTokens(\n    address rootToken,\n    address user,\n    uint256 amountOrTokenId,\n    uint256 withdrawId,\n    bytes32 destinationChain,\n    bytes memory destinationContract\n  ) public onlyOwner {\n    // check if withdrawal happens only once\n    require(withdraws[withdrawId] == false, 'Child Chain: already withdrawal for the given Id');\n\n    // set withdrawal flag\n    withdraws[withdrawId] = true;\n\n    // Create an instance of the ERC20Burnable contract\n    IERC20Burnable erc20Token = IERC20Burnable(rootToken);\n\n    // Burn the tokens from the user's account\n    erc20Token.burn(amountOrTokenId);\n\n    outboundStateSender.transferPayload(\n      destinationChain,\n      destinationContract,\n      user,\n      abi.encode(rootToken, user, amountOrTokenId, withdrawId)\n    );\n  }\n}\n
* Example for how to use transferAsset function in account-based chains:
// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n// Import the interface from the GitHub repository\nimport {IOutboundStateSender} from './interfaces/IOutboundStateSender.sol';\nimport {IERC20Burnable} from \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\ncontract ChildChain {\n  // mapping for (withdraw ID => true/false)\n  mapping(uint256 => bool) public withdraws;\n\n  // outbound state sender contract\n  IOutboundStateSender public outboundStateSender;\n\n  constructor(address _outboundStateSender) {\n    require(_outboundStateSender != address(0x0), 'Child Chain: Invalid OutboundStateSender address');\n\n    // Create an instance of the IOutboundStateSender interface using the OutboundStateSender address\n    outboundStateSender = IOutboundStateSender(_outboundStateSender);\n  }\n  /*\n   * @notice withdrawTokens\n   * @dev: amountOrTokenId: tokenId for ERC721 and amount for ERC20\n   * @param user address for deposit\n   * @param rootToken root token address\n   * @param withdrawId\n   */\n  function withdrawTokens(\n    bytes memory rootToken,\n    address user,\n    uint256 amountOrTokenId,\n    uint256 withdrawId,\n    bytes32 destinationChain,\n    bytes memory destinationAddress,\n    bytes memory destinationAsset\n  ) public onlyOwner {\n    // check if withdrawal happens only once\n    require(withdraws[withdrawId] == false, 'Child Chain: already withdrawal for the given Id');\n\n    // set withdrawal flag\n    withdraws[withdrawId] = true;\n\n      // Create an instance of the ERC20Burnable contract\n      IERC20Burnable erc20Token = IERC20Burnable(address(rootToken));\n\n      // Burn the tokens from the user's account\n      erc20Token.burn(amountOrTokenId);\n\n      outboundStateSender.transferAsset(\n        destinationChain,\n        destinationAddress,\n        user,\n        destinationAsset,\n        amountOrTokenId\n      );\n  }\n}\n

"},{"location":"core/chain-clients/evm/client/","title":"Client","text":""},{"location":"core/chain-clients/evm/client/#introduction","title":"Introduction","text":"

The EVM (Ethereum Virtual Machine) client is a crucial component designed to facilitate interactions between EVM-compatible chains and the Dojima chain. It is responsible for processing transactions initiated by users and forwarding them to the Dojima chain. Additionally, it receives state updates from the Dojima chain and relays them to the destination chain. The EVM client is particularly useful for handling all interactions that occur on EVM-related chains, such as transactions from AVAX C-chain to Dojima or vice versa.

"},{"location":"core/chain-clients/evm/client/#architecture","title":"Architecture","text":"

The EVM client is composed of two main services: - Listener service - Parser service.

"},{"location":"core/chain-clients/evm/client/#listener-service","title":"Listener Service","text":"

The Listener service is responsible for monitoring all events emitted by EVM-related contracts, including the State Sender contract, Outbound State Sender contract, and Router contract. It filters out the relevant events and forwards them to the Parser service for further processing.

"},{"location":"core/chain-clients/evm/client/#parser-service","title":"Parser Service","text":"

The Parser service takes the events forwarded by the Listener service, parses these events, and sends them in batches to the Observer. The Observer then processes these batches further. This architecture allows the EVM client to efficiently handle a large volume of transactions and state updates, ensuring that all relevant data is accurately relayed between the source chain, the Dojima chain, and the destination chain.

"},{"location":"core/chain-clients/evm/client/#usage","title":"Usage","text":"

To use the EVM client, you need to initiate a transaction or a state update on an EVM-compatible chain. The Listener service of the EVM client will automatically detect the event emitted by the transaction or state update. It will filter out the relevant events and forward them to the Parser service. The Parser service will then parse these events and send them in batches to the Observer. The Observer will process these batches and update the state of the Dojima chain or the destination chain accordingly. By using the EVM client, you can ensure that all interactions between EVM-compatible chains and the Dojima chain are handled efficiently and accurately.

"},{"location":"core/chain-clients/evm/hermes-bridge/","title":"Hermes Bridge","text":""},{"location":"core/chain-clients/evm/hermes-bridge/#introduction","title":"Introduction","text":"

The Hermes chain is a Cosmos-based blockchain responsible for connecting the Dojima chain to other chains, both EVM (Ethereum Virtual Machine) and non-EVM chains. Within Hermes, there are three distinct modules Narada the Hermes and the DojimaChain module.

Narada serves as a hub for clients connected to the Hermes chain. Its primary role is to monitor all events and convert them into a format suitable for transmission to the Hermes chain. After observing transactions, Narada relays them to the Hermes chain.

The Hermes module functions as a storage system for the Dojima chain. It stores transactions sent by Narada, ensuring they are readily accessible when needed.

The DojimaChain module acts as a client of the Dojima chain, facilitating interactions between the Dojima chain and the Hermes chain.

type Tx struct {\n  ID          TxID    `protobuf:\"bytes,1,opt,name=id,proto3,casttype=TxID\" json:\"id,omitempty\"`\n  Chain       Chain   `protobuf:\"bytes,2,opt,name=chain,proto3,casttype=Chain\" json:\"chain,omitempty\"`\n  FromAddress Address `protobuf:\"bytes,3,opt,name=from_address,json=fromAddress,proto3,casttype=Address\" json:\"from_address,omitempty\"`\n  ToAddress   Address `protobuf:\"bytes,4,opt,name=to_address,json=toAddress,proto3,casttype=Address\" json:\"to_address,omitempty\"`\n  Coins       Coins   `protobuf:\"bytes,5,rep,name=coins,proto3,castrepeated=Coins\" json:\"coins\"`\n  Gas         Gas     `protobuf:\"bytes,6,rep,name=gas,proto3,castrepeated=Gas\" json:\"gas\"`\n  Memo        string  `protobuf:\"bytes,7,opt,name=memo,proto3\" json:\"memo,omitempty\"`\n  Payload     []byte  `protobuf:\"bytes,8,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n}\n\n// Transaction ID is a unique identifier for a transaction\ntype TxID string\n\n// Chain is an alias of string , represent a blockchain name\ntype Chain string\n\ntype Address string\n\ntype Coin struct {\n  Asset    Asset                                   `protobuf:\"bytes,1,opt,name=asset,proto3\" json:\"asset\"`\n  Amount   github_com_cosmos_cosmos_sdk_types.Uint `protobuf:\"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint\" json:\"amount\"`\n  Decimals int64                                   `protobuf:\"varint,3,opt,name=decimals,proto3\" json:\"decimals,omitempty\"`\n}\n\ntype Asset struct {\n  Chain  Chain  `protobuf:\"bytes,1,opt,name=chain,proto3,casttype=Chain\" json:\"chain,omitempty\"`\n  Symbol Symbol `protobuf:\"bytes,2,opt,name=symbol,proto3,casttype=Symbol\" json:\"symbol,omitempty\"`\n  Ticker Ticker `protobuf:\"bytes,3,opt,name=ticker,proto3,casttype=Ticker\" json:\"ticker,omitempty\"`\n  Synth  bool   `protobuf:\"varint,4,opt,name=synth,proto3\" json:\"synth,omitempty\"`\n}\n\n// Symbol represent an asset\ntype Symbol string\n\n// Ticker The trading 'symbol' or shortened name (typically in capital letters)\n// that refer to a coin on a trading platform. For example: BNB\ntype Ticker string\n
"},{"location":"core/chain-clients/evm/hermes-bridge/#narada","title":"Narada","text":"

Narada\u2019s operations can be summarized in the following steps:

  • Narada observes the events emitted by the State Sender Contract. The State Sender Contract is a contract that is deployed on the Ethereum chain.
  • The State Sender Contract generates an event known as TokenTransfer, containing transaction information destined for the Dojima chain.
  • Narada captures and transforms the TokenTransfer event into a common format referred to as XMsgObservedTx, which is compatible with the Hermes chain.
type XMsgObservedTx struct {\n  Tx             Tx         `protobuf:\"bytes,1,opt,name=tx,proto3\" json:\"tx\"`\n  Status         Status    `protobuf:\"varint,2,opt,name=status,proto3,enum=types.Status\" json:\"status,omitempty\"`\n  BlockHeight    int64     `protobuf:\"varint,3,opt,name=block_height,json=blockHeight,proto3\" json:\"block_height,omitempty\"`\n  Signers        []string  `protobuf:\"bytes,4,rep,name=signers,proto3\" json:\"signers,omitempty\"`\n  KeysignMs      int64     `protobuf:\"varint,5,opt,name=keysign_ms,json=keysignMs,proto3\" json:\"keysign_ms,omitempty\"`\n  FinaliseHeight int64     `protobuf:\"varint,6,opt,name=finalise_height,json=finaliseHeight,proto3\" json:\"finalise_height,omitempty\"`\n}\n
"},{"location":"core/chain-clients/evm/hermes-bridge/#hermes","title":"Hermes","text":"

The Hermes module is responsible for validating and storing transactions sent by Narada. It operates with its set of validators responsible for transaction validation. These validators are chosen through the Tendermint consensus algorithm. Once a sufficient number of validators approve a transaction, its data is validated. Subsequently, based on memo data, transaction data is converted into the Hermes chain message format.

For Ethereum chain State Sender Contract events, event data is converted into the following format:

type MsgEVMTransferNative struct {\n  Txn                  Tx                                      `protobuf:\"bytes,1,opt,name=tx,proto3\" json:\"tx\"`\n  Signer              github_com_cosmos_cosmos_sdk_types.AccAddress  `protobuf:\"bytes,2,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress\" json:\"signer,omitempty\"`\n  DestinationContract github_com_dojimanetwork_hermes_common.Address `protobuf:\"bytes,3,opt,name=destination_contract,json=destinationContract,proto3,casttype=github.com/dojimanetwork/hermes/common.Address\" json:\"destination_contract,omitempty\"`\n  DepositId           uint64                                         `protobuf:\"varint,4,opt,name=depositId,proto3\" json:\"depositId,omitempty\"`\n}\n

The MsgEVMTransferNative format is stored within the Hermes chain and later converted into the DojimaInput format, which is used by the Dojima chain.

type DojimaInput struct {\n  ID           uint64                                              `protobuf:\"varint,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n  Contract     github_com_dojimanetwork_dojimachain_common.Address `protobuf:\"bytes,2,opt,name=contract,proto3,casttype=github.com/dojimanetwork/dojimachain/common.Address\" json:\"contract\"`\n  Data         []byte                                              `protobuf:\"bytes,3,opt,name=data,proto3\" json:\"data,omitempty\"`\n  TxHash       string                                              `protobuf:\"bytes,4,opt,name=txHash,proto3\" json:\"txHash,omitempty\"`\n  ObservedTime time.Time                                           `protobuf:\"bytes,5,opt,name=observedTime,proto3,stdtime\" json:\"observedTime\"`\n  ChainID      string                                              `protobuf:\"bytes,6,opt,name=chain_id,json=chainId,proto3\" json:\"chain_id,omitempty\"`\n}\n\nfunc (h EvmTransferNativeHandler) handleV89(ctx cosmos.Context, msg *MsgEVMTransferNative) (*cosmos.Result, error) {\n  ctx.Logger().Info(\"message evm transfer\", \"received message\", msg)\n\n  ctx.Logger().Debug(\"\u2705 Validating EvmTransferNative msg\",\n    \"Id\", msg.Tx.ID,\n    \"Destination Contract\", msg.DestinationContract,\n    \"Chain\", msg.Tx.Chain,\n    \"Deposit Id\", msg.DepositId,\n  )\n\n  // check if event record exists\n  if exists := h.mgr.Keeper().HasLayer1TransferNativeMsg(ctx, msg.Tx.ID.String()); exists {\n    return sdk.WrapServiceResult(ctx, nil, common.ErrEventRecordAlreadySynced(types.DefaultCodespace))\n  }\n\n  hermesKeeper := h.mgr.Keeper()\n  lastDepositId, err := hermesKeeper.GetDojimaLastDepositId(ctx)\n  if err != nil {\n    ctx.Logger().Error(\"Unable to fetch Dojima Chain Last Deposit ID\", \"error\", err)\n    return nil, err\n  }\n\n  // create Dojima Input\n  inRecord := dtypes.NewDojimaInput(\n    lastDepositId+1, // ID generated on Hermes\n    dcommon.HexToAddress(msg.DestinationContract.String()), // Contract address should be updated in chain params\n    msg.Tx.Payload,\n    msg.Tx.ID.String(),\n    ctx.BlockTime(),\n    hermesKeeper.GetChainId(ctx),\n  )\n\n  if err := hermesKeeper.StoreDojimaInput(ctx, inRecord); err != nil {\n    ctx.Logger().Error(\"Unable to update event record\", \"id\", msg.Tx.ID, \"error\", err)\n    return sdk.WrapServiceResult(ctx, nil, common.ErrDojimaInputUpdate(types.DefaultCodespace))\n  }\n\n  // Storing Dojima Input Message with Unique TxHash\n  if err = hermesKeeper.StoreEVMTransferNativeMsg(ctx, msg); err != nil {\n    ctx.Logger().Error(\"unable to store dojima input evm transfer message\",\n    \"id\", msg.Tx.ID, \"error\", err)\n    return sdk.WrapServiceResult(ctx, nil, common.ErrDojimaInputMessageUpdate(types.DefaultCodespace))\n  }\n\n  return &sdk.Result{\n    Events: ctx.EventManager().Events().ToABCIEvents(),\n  }, nil\n}\n

"},{"location":"core/chain-clients/evm/hermes-bridge/#dojima-chain-module","title":"Dojima Chain Module","text":"

The Dojima Chain module provides a querying mechanism to retrieve transactions from the Hermes chain.

Transactions are fetched from the Hermes chain using the following query format:

  // Queries a list of DojimaInput items.\n  rpc DojimaInput(QueryDojimaInputRequest) returns (QueryDojimaInputResponse) {\n    option (google.api.http).get = \"/dojimanetwork/hermes/dojimachain/dojima_input/{id}\";\n  }\n\n  message QueryDojimaInputRequest {\n    uint64 id = 1;\n  }\n\n  message QueryDojimaInputResponse {\n    DojimaInput input = 1;\n  }\n\n  message DojimaInput {\n    option (gogoproto.goproto_stringer) = false;\n    uint64 id = 1 [(gogoproto.customname) = \"ID\"]; //to be changed to sequence number from hash - @akhilpune\n    common.DcAddress contract = 2 [(gogoproto.casttype) = \"github.com/dojimanetwork/dojimachain/common.Address\",(gogoproto.nullable) = false];\n    bytes data = 3;\n    string txHash = 4;\n    google.protobuf.Timestamp observedTime = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];\n    string chain_id = 6 [(gogoproto.customname) = \"ChainID\"];\n  }\n
"},{"location":"core/chain-clients/evm/state-sender-contract/","title":"Ethereum State Sender Contract","text":""},{"location":"core/chain-clients/evm/state-sender-contract/#introduction","title":"Introduction","text":"

Ethereum, a pioneering decentralized platform, empowers developers to create and deploy smart contracts. These self-executing pieces of code automate intricate processes and agreements, akin to digital agreements that trigger automatically when predefined conditions are met.

However, Ethereum\u2019s significance transcends its technological prowess. It has cultivated a vibrant ecosystem where global developers converge to craft decentralized applications (dApps). Leveraging Ethereum\u2019s smart contracts, these dApps provide a wide array of services. These range from decentralized finance (DeFi) and non-fungible tokens (NFTs) to decentralized governance and beyond.

"},{"location":"core/chain-clients/evm/state-sender-contract/#the-state-sender-contract","title":"The State Sender Contract","text":"

The State Sender Contract is a smart contract designed to facilitate Ethereum (dApp) developers in sending tokens and payloads to the Dojima Chain.

To utilize the State Sender Contract, follow these straightforward steps:

"},{"location":"core/chain-clients/evm/state-sender-contract/#step-1-copy-the-state-sender-contract-from-github","title":"Step 1: Copy the State Sender Contract from GitHub","text":"
  • Access the State Sender Contract Interface and Contract on the GitHub repository here and here respectively.
  • Copy both the Interface and Contract into their corresponding folders, typically located in \u2019. /contracts/\u2019, \u2019. /interfaces/\u2019 or as per your project structure.
"},{"location":"core/chain-clients/evm/state-sender-contract/#step-2-obtain-the-state-sender-contract-address","title":"Step 2: Obtain the State Sender Contract Address","text":"
  • Retrieve the State Sender Contract address from the Dojima Chain Explorer.

Note: The State Sender Contract address may vary for different chains. Ensure that you select the Ethereum chain and the appropriate mainnet or testnet.

"},{"location":"core/chain-clients/evm/state-sender-contract/#step-3-initialize-the-state-sender-contract","title":"Step 3: Initialize the State Sender Contract","text":"
  • Initialize the State Sender Contract in your dapp by passing the State Sender Contract address as a parameter.
// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n\n// Import the interface from the GitHub repository\nimport { IStateSender } from './interfaces/IStateSender.sol';\n\ncontract App {\n    // Declare a variable to hold the address of the StateSender contract\n    address public stateSender;\n\n    constructor(address _stateSender) {\n        stateSender = _stateSender;\n    }\n\n    /**\n    * @dev Function to call the tokenTransferWithPayload function from the StateSender contract\n    * @param destinationChain The chain to which the tokens and payload are to be sent.\n    * @param destinationContract The contract to which the tokens and payload are to be sent.\n    * @param asset The address of the token to be sent.\n    * @param tokenAmount The amount of tokens to be sent.\n    * @param payload The abi encoded contract call to be sent.\n    * @notice destinationChain and destinationContract should be registered with the state sender contract before sending the tokens and payload.\n    */\n    function sendState(\n        bytes32 destinationChain,\n        address destinationContract,\n        address asset,\n        uint256 tokenAmount,\n        bytes calldata payload\n    ) public {\n        // Create an instance of the IStateSender interface using the StateSender address\n        IStateSender stateSenderInstance = IStateSender(stateSender);\n\n        // Call the tokenTransferWithPayload function\n        stateSenderInstance.tokenTransferWithPayload(\n            destinationChain,\n            destinationContract,\n            asset,\n            tokenAmount,\n            payload\n        );\n    }\n}\n
"},{"location":"core/chain-clients/evm/state-sender-contract/#step-4-event-emitted-by-the-state-sender-contract-tokentransferwithpayload","title":"Step 4: Event emitted by the State Sender Contract TokenTransferWithPayload","text":"
  • Once the State Sender Contract executes the TokenTransferWithPayload function, it emits an event called TokenTransfer. This event plays a vital role in the interaction with Narada.
  • The TokenTransfer event furnishes essential information in its parameters:
    • depositID - This identifier uniquely identifies deposits on the Dojima chain. It is relevant only when the destinationChain is Dojima.
    • destinationChain - This denotes the specific chain to which the tokens and payload have been dispatched.
    • destinationContract - It signifies the target contract to which the tokens and payload are delivered.
    • asset - This parameter contains the address of the token that was sent.
    • tokenAmount - The amount of tokens sent.
    • payload - This field holds the ABI-encoded contract call that was transmitted. Step 4: Processing the Event Emitted by the State Sender Contract - TokenTransferWithPayload Once the State Sender Contract executes the TokenTransferWithPayload function, it emits an event called TokenTransfer. This event plays a vital role in the interaction with Narada.
"},{"location":"core/chain-clients/nonevm/arweave/","title":"Arweave Chain Client","text":""},{"location":"core/chain-clients/nonevm/arweave/#introduction","title":"Introduction","text":"

Arweave is a new type of storage that backs data with sustainable and perpetual endowments, allowing users and developers to truly store data forever \u2013 for the very first time.

As a collectively owned hard drive that never forgets, Arweave allows us to remember and preserve valuable information, apps, and history indefinitely. By preserving history, it prevents others from rewriting it.

"},{"location":"core/chain-clients/nonevm/arweave/#scanning-blocks","title":"Scanning Blocks","text":"

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

      txInfo, err := c.client.GetTransactionByID(tx)\n\n      // if tx is not found, invalid\n      if err == argo.ErrNotFound || err == argo.ErrInvalidId {\n      return types.TxInItem{}, err\n      }\n\n      // converting signature data to owner address\n      sender, err := arutils.OwnerToAddress(txInfo.Owner)\n\n      if err != nil {\n      return types.TxInItem{}, err\n      }\n\n      winstonQtyStr := txInfo.Quantity\n      winstonFeeStr := txInfo.Reward\n\n      winstonQty, ok := cosmos.ParseUint(winstonQtyStr)\n\n      if ok != nil {\n      err = fmt.Errorf(\"invalid amount: %v\", winstonQtyStr)\n      return types.TxInItem{}, err\n      }\n\n      _, ok = cosmos.ParseUint(winstonFeeStr)\n\n      if ok != nil {\n      err = fmt.Errorf(\"invalid fee: %v\", winstonFeeStr)\n      return types.TxInItem{}, err\n      }\n\n      // when value is less than or equal to zero, it is data transaction not a transfer\n      if winstonQty.IsZero() {\n      return types.TxInItem{}, fmt.Errorf(\"not a transfer transaction, its a data transaction, so ignoring\")\n      }\n\n      client := argo.NewClient(\"https://arweave.net\")\n      address := os.Getenv(\"AR_ADDRESS\")\n      reward, err := client.GetTransactionPrice([]byte(\"\"), &address)\n      convReward := cosmos.NewUint(uint64(reward))\n      // till here\n\n      if err != nil {\n      c.logger.Error().Err(err).Msg(\"failed to get arweave fee\")\n      }\n\n      gasFee := common.Gas{\n      common.NewCoin(common.ARAsset, convReward).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),\n      }\n      // update memory cache\n      c.udpateARGasCache(convReward)\n\n      toAddr := txInfo.Target\n\n      //read memo from tags [{name, value}]\n      var memo string\n      for _, val := range txInfo.Tags {\n      if strings.EqualFold(val.Name, \"memo\") {\n      memo = val.Value\n      c.logger.Debug().Str(\"memo\", memo).Msg(\"found memo field\")\n      }\n      }\n\n      if memo == \"\" {\n      c.logger.Debug().Str(\"memo\", memo).Msg(\"found empty memo\")\n      }\n\n      return types.TxInItem{\n      BlockHeight: height,\n      Tx:          txInfo.ID,\n      Sender:      sender,\n      To:          toAddr,\n      Coins: common.Coins{\n      common.NewCoin(common.ARAsset, winstonQty).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),\n      },\n      Memo: memo,\n      Gas:  gasFee,\n      }, nil\n
"},{"location":"core/chain-clients/nonevm/arweave/#arweave-signer","title":"Arweave Signer","text":"

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on arweave chain. Signing transactions are done in two ways: using rsa tss signing algo and single wallet signing.

      _, err := tx.VaultPubKey.GetAddress(c.GetChain())\n      //c.logger.Debug().Msgf(\"process outbound tx\", fromAddr)\n      if err != nil {\n      return &types.Transaction{}, fmt.Errorf(\"failed to convert arweave address (%s): %w\", tx.VaultPubKey.String(), err)\n      }\n\n      // initialise to collect all received txout substractFee coins\n      var coins = cosmos.NewUint(0)\n      for _, coin := range tx.Coins {\n      // handle sors return, leave enough coin to pay for gas.\n      if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {\n      if coin.Asset == c.cfg.ChainID.GetGasAsset() {\n      substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))\n      if coin.Amount.LT(substractFee) {\n      return &types.Transaction{}, fmt.Errorf(\"not enough to pay for transaction, Origal amount %d, Fee %d\", coin.Amount.Uint64(), substractFee.Uint64())\n      }\n\n      coin.Amount = coin.Amount.Sub(substractFee)\n      }\n      }\n      coins = coins.Add(coin.Amount)\n      }\n\n      tag := types.Tag{\n        Name:  \"memo\",\n        Value: tx.Memo,\n      }\n\n      var tags []types.Tag\n      tags = append(tags, tag)\n      encodeTag := utils.TagsEncode(tags)\n\n      arTx := &types.Transaction{\n      Format:   2,\n      Quantity: coins.String(),\n      Data:     \"\",\n      DataSize: \"0\",\n      Reward:   c.averageFee().String(),\n      Target:   tx.ToAddress.String(),\n      Tags:     encodeTag,\n      }\n\n      return arTx, nil\n
"},{"location":"core/chain-clients/nonevm/polkadot/","title":"Polkadot Chain Client","text":""},{"location":"core/chain-clients/nonevm/polkadot/#introduction","title":"Introduction","text":"

Polkadot unites and secures a growing ecosystem of specialized blockchains called parachains. Apps and services on Polkadot can securely communicate across chains, forming the basis for a truly interoperable decentralized web.

"},{"location":"core/chain-clients/nonevm/polkadot/#scanning-blocks","title":"Scanning Blocks","text":"

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

    func (c *Client) convertToTxIn(dextrinsic *DecodedExtrinsic, height int64) (types.TxInItem, error) {\n      e := dextrinsic.Extrinsic\n      call, ok := e.Metadata.CallIndex[e.CallIndex]\n      if !ok {\n        return types.TxInItem{}, fmt.Errorf(\"failed to get call index from metadata\")\n      }\n      // if extrinsic module is utility and function is batch all or batch with signed tx, gas class is normal\n      // https://docs.substrate.io/build/tx-weights-fees/\n      if e.Module == \"Utility\" && (call.Call.Name == \"batch_all\" || call.Call.Name == \"batch\") && e.ContainsTransaction && len(e.Signature) > 0 && dextrinsic.PaymentInfo.Class == \"normal\" {\n        dest := \" \"\n        dotQty := cosmos.ZeroUint()\n        memo := \"\"\n        calls := &[]UtilityBatchCall{}\n        err := unmarshalAny(calls, e.Params[0].Value)\n        gas := dextrinsic.PaymentInfo.PartialFee.BigInt().Uint64()\n        comsosGas := cosmos.NewUint(gas)\n        c.updateDOTGasCache(comsosGas)\n        if err != nil {\n          return types.TxInItem{}, err\n        }\n\n        for _, c := range *calls {\n          for _, a := range c.Params {\n            switch a.Name {\n            // decode destination address to ss58\n            case \"dest\":\n              dest = EncodeToSS58(a.Value.(map[string]interface{})[\"Id\"].(string))\n              break\n              // get transacted value to dest address\n            case \"value\":\n              value := a.Value.(string)\n              dotQty, err = cosmos.ParseUint(value)\n              if err != nil {\n                return types.TxInItem{}, err\n              }\n              break\n              // get memo field\n            case \"remark\":\n              memoBeforeConv := a.Value.(string)\n              parts := strings.Split(memoBeforeConv, \":\")\n              if len(parts) < 2 {\n                return types.TxInItem{}, fmt.Errorf(\"invalid memo of dot transaction %s, tx hash %s\", memo, e.ExtrinsicHash)\n              }\n              if strings.EqualFold(parts[0], \"memo\") {\n                memo = strings.Join(parts[1:], \":\")\n              } else {\n                return types.TxInItem{}, fmt.Errorf(\"invalid memo of dot transaction %s, tx hash %s\", memo, e.ExtrinsicHash)\n              }\n              break\n            }\n          }\n        }\n\n        return types.TxInItem{\n          BlockHeight: height,\n          Tx:          e.ExtrinsicHash,\n          Sender:      EncodeToSS58(e.Address.(string)),\n          To:          dest,\n          Memo:        memo,\n          Coins: common.Coins{\n            common.NewCoin(common.DOTAsset, dotQty).WithDecimals(common.DOTCHAIN.GetGasAssetDecimal()),\n          },\n          Gas: common.Gas{\n            common.NewCoin(common.DOTAsset, comsosGas).WithDecimals(common.DOTCHAIN.GetGasAssetDecimal()),\n          },\n        }, nil\n      }\n\n      return types.TxInItem{}, nil\n    }\n
"},{"location":"core/chain-clients/nonevm/polkadot/#polkadot-signer","title":"Polkadot Signer","text":"

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on arweave chain. Signing transactions are done in two ways: using ed25519/sr25519 tss signing algo and single wallet signing.

    func (c *Client) processOutboundTx(tx stypes.TxOutItem, hermeschainHeight int64) (gsrpcTypes.SignatureOptions, gsrpcTypes.Extrinsic, error) {\n      _, err := tx.VaultPubKey.GetAddress(c.GetChain())\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, fmt.Errorf(\"failed to convert polkadot address (%s): %w\", tx.VaultPubKey.String(), err)\n      }\n\n      // initialise to collect all received txout substractFee coins\n      var coins = cosmos.NewUint(0)\n      for _, coin := range tx.Coins {\n        // handle sors return, leave enough coin to pay for gas.\n        if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {\n          if coin.Asset == c.cfg.ChainID.GetGasAsset() {\n            substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))\n            if coin.Amount.LT(substractFee) {\n              return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, fmt.Errorf(\"not enough to pay for transaction, Origal amount %d, Fee %d\", coin.Amount.Uint64(), substractFee.Uint64())\n            }\n\n            coin.Amount = coin.Amount.Sub(substractFee)\n          }\n        }\n        coins = coins.Add(coin.Amount)\n      }\n\n      // fetch the latest metadata from chain\n      metadata, err := c.GetLatestMetadata()\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // convert from ss58 to hexadecimal address\n      hexAddr := DecodeFromSS58(tx.ToAddress.String())\n      appendX := strings.Join([]string{\"0x\", hexAddr}, \"\")\n      dest, err := gsrpcTypes.NewMultiAddressFromHexAccountID(appendX)\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // append memo string to tx.memo and join with \":\"\n      memoArray := strings.Join([]string{\"memo\", tx.Memo}, \":\")\n      memo := []byte(memoArray)\n\n      // prepare system::remark call\n      remarkCall, err := gsrpcTypes.NewCall(metadata, \"System.remark\", memo)\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // dest amount\n      valUint64 := coins.Uint64()\n      amount := gsrpcTypes.NewUCompactFromUInt(valUint64)\n\n      // prepare balances::transfer call\n      transferCall, err := gsrpcTypes.NewCall(metadata, \"Balances.transfer\", dest, amount)\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // prepare utility::batch_all\n      utilityBatchCall, err := gsrpcTypes.NewCall(metadata, \"Utility.batch_all\", []gsrpcTypes.Call{transferCall, remarkCall})\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // fetch genesis hash for immortal era.\n      genesisHash, err := c.gsrpc.RPC.Chain.GetBlockHash(0)\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // create storage key\n      storageKey, err := gsrpcTypes.CreateStorageKey(metadata, \"System\", \"Account\", c.dotKeysignWrapper.dotKP.PublicKey)\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // fetch account info for nonce value\n      var accountInfo gsrpcTypes.AccountInfo\n      ok, err := c.gsrpc.RPC.State.GetStorageLatest(storageKey, &accountInfo)\n      nonce := accountInfo.Nonce\n\n      if err != nil || !ok {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // fetch runtime version data\n      runtimeVersion, err := c.GetRuntimeVersion()\n\n      if err != nil {\n        return gsrpcTypes.SignatureOptions{}, gsrpcTypes.Extrinsic{}, err\n      }\n\n      // prepare extrinsic for signing\n      extrinsic := gsrpcTypes.NewExtrinsic(utilityBatchCall)\n\n      return gsrpcTypes.SignatureOptions{\n        BlockHash:          genesisHash,\n        Era:                gsrpcTypes.ExtrinsicEra{IsMortalEra: false},\n        GenesisHash:        genesisHash,\n        Nonce:              gsrpcTypes.NewUCompactFromUInt(uint64(nonce)),\n        SpecVersion:        runtimeVersion.SpecVersion,\n        Tip:                gsrpcTypes.NewUCompactFromUInt(0),\n        TransactionVersion: runtimeVersion.TransactionVersion,\n      }, extrinsic, nil\n    }\n
"},{"location":"core/chain-clients/nonevm/solana/solana-client/","title":"Solana Chain Client","text":""},{"location":"core/chain-clients/nonevm/solana/solana-client/#introduction","title":"Introduction","text":"

Solana is a layer-1 blockchain similar to Ethereum and Bitcoin meaning other layer-2 blockchains can build on Solana. Solana has a similar concept of smart contracts on Ethereum called as Programs which also facilitates in development of dApps. Solana follows a consensus mechanism of Proof-of-History, which can be understood as a type of cryptographic timeclock which manages to timestamp a blockchain transaction. This helps in order of the blocks and transactions. The advantages of this can be understood on comparing the Bitcoin block validation time (10 mins) which uses Proof of Work and Solana block validation time (800 milliseconds).

"},{"location":"core/chain-clients/nonevm/solana/solana-client/#solana-local-test-node","title":"Solana local test node","text":"

To build programs and test it on your local node, you need to run a local instance of Solana local validator. To run it, first install Solana CLI. Then start your own local validator node by running the command solana-test-validator after successfully installing Solana CLI. Further steps can be found here if you find the need to dive in-depth.

"},{"location":"core/chain-clients/nonevm/solana/solana-client/#solana-client-overview","title":"Solana-Client Overview","text":"

Solana client listens and parses the transactions included in solana blocks. It will parse the transaction\u2019s inner instructions field to know which programs were part of the execution. If we find our state-sender program address in the inner-instruction, It means that some other program had to use our state-sender program for some sort of cross-chain operation. The logs of the above transaction are parsed to see what type of event is emitted. The event is extracted(termed as payload) and posted to the Hermes chain as a TxIn item. At regular block intervals dojima chain will fetch TxIn items stored on hermes chain. Based on the received payload, the dojima chain will be sending the payload to a destined contract on the dojima chain.

"},{"location":"core/chain-clients/nonevm/solana/solana-client/#filtering-transactions","title":"Filtering Transactions","text":"
func isDOJStateSenderTxn(tx *rpc.GetParsedTransactionResult, stateSenderContract string) (bool, string) {\n   log := tx.Meta.LogMessages\n   prog_add := \"\"\n   if len(tx.Meta.InnerInstructions) == 0 {\n      return false, \"\"\n   }\n   for i := 0; i < len(tx.Meta.InnerInstructions[0].Instructions); i++ {\n      prog_add += tx.Meta.InnerInstructions[0].Instructions[i].ProgramId.String()\n      prog_add += \" \"\n   }\n   if !strings.Contains(prog_add, \"<sol_state_sender_prog>\") {\n      return false, \"\"\n   }\n   log_str := fmt.Sprint(log)\n   if strings.Contains(log_str, \"TokenTransfer\") {\n      return true, \"TokenTransfer\"\n   } else if strings.Contains(log_str, \"TransferPayload\") {\n      return true, \"TransferPayload\"\n   }\n   return false, \"\"\n}\n

Info

The above code snippet allows the client to decide whether the picked transaction should be filtered and sent to hermes.

  • isDOJStateSenderTxn - This function returns a boolean value stating whether the transaction is state-sender transaction or not.
  • tx.Meta.InnerInstructions[0].Instructions - This consists of the programs that were part of the first instruction execution.
  • TokenTransfer and TransferPayload are the types of events which are to be filtered and stored in the Hermes chain.
func GetUnpackedEvent(log []string, typ string) (StateSenderEvent, error) {\n   sse := StateSenderEvent{}\n   if typ == \"TokenTransfer\" {\n     return sse, nil\n   } else if typ == \"TransferPayload\" {\n      log_str := fmt.Sprintln(log)\n      log_str_arr := strings.Split(log_str, \" \")\n      indx := -1\n      for i := 0; i < len(log_str_arr); i++ {\n         if log_str_arr[i] == typ {\n            indx = i\n            break\n         }\n      }\n    if indx == -1 {\n        return sse, fmt.Errorf(\"unable to parse TransferPayload event\")\n    }\n      //Destination chain\n      sse.DestChain = \"DOJ\"\n      //Destination contract\n      sse.SourceDestContract = log_str_arr[1]\n      //destination chain destination contract\n      sse.DestinationDestContract = log_str_arr[indx+2]\n      //Destination counter nonce\n      counter_in_u64, err := strconv.ParseUint(log_str_arr[indx+1], 10, 64)\n      if err != nil {\n         return sse, &StateSenderError{}\n      }\n      sse.CounterNonce = counter_in_u64\n      //emitted data for child chain smart contract\n      sse.DataInBytes = log_str_arr[indx+3]\n      return sse, nil\n   }\n   return sse, nil\n}\n

Info

The above code snippet allows the client to parse log to extract payload .

"},{"location":"core/chain-clients/nonevm/solana/solana-client/#scanning-blocks","title":"Scanning Blocks","text":"

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

      client := rpc.NewClient(\"http://127.0.0.1:8899\")\n      address := os.Getenv(\"SOL_ADDRESS\")\n\n      txInfo, err := c.client.GetTransaction(\n        context.TODO(), \n        txSig, \n        &rpc.GetTransactionOpts{Encoding: solana.EncodingBase64}\n        )\n\n      // If Transaction is not found.\n      if err != nil {\n        return types.TxInItem{}, err\n      }\n\n      decodedTx, err := solana.TransactionFromDecoder(bin.NewBinDecoder(txInfo.Transaction.GetBinary()))\n\n      // If Transaction is not decoded. \n      if err != nil {\n        return types.TxInItem{}, err\n      }\n\n      // Getting the transaction details from the decoded transaction.\n      sender := decodedTx.AccountMetaList()[0].PublicKey.String()\n      LamportQtyStr := cosmos.NewUint(txInfo.Meta.PostBalances[1] - txInfo.Meta.PreBalances[1])\n      LamportFeeStr := cosmos.NewUint(txInfo.Meta.Fee)\n\n      // Read memo from solana transaction.\n      solmemo := \"\"\n      if len(txInfo.Meta.LogMessages) > 4 {\n        solmemo = txInfo.Meta.LogMessages[4]\n        solmemo = strings.ReplaceAll(solmemo, \"Program log: \", \"\")\n      }\n\n      gasFee := common.Gas{\n        common.NewCoin(common.SOLAsset, LamportFeeStr),\n      }\n      toAddr := decodedTx.Message.AccountKeys[1].String()\n\n      // update memory cache\n      c.udpateSOLGasCache(LamportFeeStr)\n\n      return types.TxInItem{\n        BlockHeight: height,\n        Tx:          tx,\n        Sender:      sender,\n        To:          toAddr,\n        Coins: common.Coins{\n          common.NewCoin(common.SOLAsset, LamportQtyStr),\n        },\n        Memo: solmemo,\n        Gas:  gasFee,\n      }, nil\n
"},{"location":"core/chain-clients/nonevm/solana/solana-client/#solana-signer","title":"Solana Signer","text":"

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on solana chain. Signing transactions are done in two ways: using ed25519 tss signing algo and single wallet signing.

    _, err := tx.VaultPubKey.GetAddress(c.GetChain())\n  if err != nil {\n    return &solana.Transaction{}, fmt.Errorf(\"failed to convert solana address (%s): %w\", tx.VaultPubKey.String(), err)\n  }\n\n  var coins = cosmos.NewUint(0)\n  for _, coin := range tx.Coins {\n    // handle sors return, leave enough coin to pay for gas.\n    if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {\n        if coin.Asset == c.cfg.ChainID.GetGasAsset() {\n            substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))\n            if coin.Amount.LT(substractFee) {\n                return &solana.Transaction{}, fmt.Errorf(\"not enough to pay for transaction, Origal amount %d, Fee %d\", coin.Amount.Uint64(), substractFee.Uint64())\n            }\n\n            coin.Amount = coin.Amount.Sub(substractFee)\n        }\n    }\n    coins = coins.Add(coin.Amount)\n  }\n  recent, err := c.GetRecentBlockhash()\n  if err != nil {\n\n  }\n\n  amt := coins.String()\n  instruction_data := []byte{0xaa, 0xbb}\n\n  instruction := []solana.Instruction{\n    &TransactionInstructions{\n        accounts: []*solana.AccountMeta{\n            {PublicKey: solana.MustPublicKeyFromBase58(tx.fromAddress.PublicKey()), IsSigner: true, IsWritable: true},\n            {PublicKey: solana.MustPublicKeyFromBase58(tx.ToAddress.String()), IsSigner: false, IsWritable: true},\n            {PublicKey: solana.SystemProgramID, IsSigner: false, IsWritable: false},\n        },\n        data:      instruction_data,\n        programID: solana.MustPublicKeyFromBase58(os.Getenv(\"SOL_PROGRAM\")),\n    },\n  }\n\n  solTx, err := solana.NewTransaction(\n    instruction,\n    recent.Value.Blockhash,\n    solana.TransactionPayer(c.SolKeysignWrapper.privateKey.PublicKey()),\n  )\n  return solTx, err\n
"},{"location":"core/chain-clients/nonevm/solana/solana-state-sender/","title":"Solana State Sender","text":"

The solana-state-sender program is named as solana-dojima-bridge. This program maintains the mapping of registered programs on solana blockchain(Only registered programs can interact with state-sender program). Solana programs should register and call this state-sender program to interact with other contracts on destination chains.

//admin will create the registry - (token mapping)\n   pub fn create_registry(\nctx: Context<CreateRegistry>, \nsolanaprogaddress: Pubkey,\ndojimatoken: String, \nauthority: Pubkey) -> Result<()> \n   {\n       if ctx.accounts.user.key() != ctx.accounts.admin.admin {\n           return  err!(MyError::NotOwner);\n       }\n       ctx.accounts.contract_mapping.dojimatokenaddress = dojimatoken;\n       ctx.accounts.contract_mapping.authority = authority;\n       Ok(())\n   }\n   //lock_program(eg;) => (dojimatoken+authority)\n   #[account]\n   pub struct ContractMapping {\n    dojimatokenaddress: String,\n    authority: Pubkey\n   }\n\n\n   #[derive(Accounts)]\n   #[instruction(solanaprogaddress: Pubkey)]\n   pub struct CreateRegistry<'info> {\n    //error handling\n    #[account(mut)]\n    pub user: Signer<'info>,\n    #[account(\n        init,\n        payer = user,\n        seeds = [solanaprogaddress.key().as_ref(), b\"dojima_contract_mapping\"],\n            bump,\n        space = 8 + 64 + 64,\n    )]\n    pub contract_mapping: Account<'info, ContractMapping>,\n    pub system_program: Program<'info, System>,\n    #[account(\n        seeds = [b\"dojima_bridge_admin4\"],\n        bump,\n    )]\n    pub admin: Account<'info, Admin>,\n  }\n
  • Create_registry - Admin will register the programs and create a contract mapping for every program.
  • dojimatoken - This is the equivalent of solana token on dojima chain.
  • authority - PDA of a program which signs to interact with the state-sender contract should be passed as an authority.
pub fn transfer_payload(\n       ctx: Context<TransferPayload>,\n       destination_contract: String,\n       payload: String\n   ) -> Result<()> {\n       //only authority(ie; PDA of locking program) is allowed to call this function\n       if ctx.accounts.contract_mapping.authority.key() != ctx.accounts.user.key() {\n           return  err!(MyError::UnauthorizedContract);\n       }\n       if ctx.accounts.contract_mapping.dojimatokenaddress != destination_contract {\n           return  err!(MyError::UnauthorizedContract);\n       }\n       let nonce =  ctx.accounts.counter.count;\n       ctx.accounts.counter.count += 1;\n       msg!(\n           \"{} {} {} {}\",\n           \"TransferPayload\",\n           nonce,\n           destination_contract,\n           payload\n       );\n       Ok(())\n   }\n
  • transfer_payload - This function is used to transfer abi-encoded payload to dojima chain contracts.
  • destination_contract - Which contract to call on the destination chain.
  • payload - abi-encoded data that should be passed to the destination chain.
  • A check will be made whether the calling program is registered in the registry or not.
  • destination_contract should be the same as the registered dojima token address.
  • Counter keeps track of the number of interactions happening with the state-sender program.
  • It will increment the counter by one for everytime a transfer_payload (or) token_transfer_from_solana function is called.
  • After incrementing the counter TransferPayload message(event) is emitted which is filtered by solana-client(narada) and submitted to hermes.
pub fn token_transfer_to_solana(\nctx: Context<TokenTransferToSolana>, \ndestination_prog_data: Vec<u8>\n) -> Result<()> {\n       //check whether the signer is TSS\n\n\n       //Define seeds for signing\n       let seeds: &[&[u8]] = &[\n           b\"dojima_bridge_authority\",\n           &[254]\n       ]; \n       let signer_seeds:&[&[&[u8]]] = &[&seeds[..]];\n\n\n       //unpack accounts\n       let destination_prog = &ctx.accounts.destination_program;\n       let sender_ATA = &ctx.accounts.from_token_account;\n       let receiver_ATA = &ctx.accounts.to_token_account;\n       let tkn_prog = &ctx.accounts.token_program;\n       let auth = &ctx.accounts.authority;\n       let bridge_owner_pda = &ctx.accounts.bridge_owner_pda;\n\n\n       //Construct accoount_metas for CPI invocation\n       let account_metas = vec![\n           AccountMeta::new(ctx.accounts.signing_pda.key(),true),\n           AccountMeta::new(sender_ATA.key(), false),\n           AccountMeta::new(receiver_ATA.key(), false),\n           AccountMeta::new_readonly(tkn_prog.key(), false),\n           AccountMeta::new_readonly(auth.key(), false),\n           AccountMeta::new_readonly(bridge_owner_pda.key(), false),\n       ];\n\n\n       //Instruction identifier of global:execute_state\n       let inst_identifier:Vec<u8> = vec![34, 26, 147, 217, 17, 18, 70, 124];\n\n\n       //Prepare data for CPI\n       let destination_prog_data_len = destination_prog_data.len() as u32;\n       let destnation_prog_data_len_bytes = destination_prog_data_len.to_le_bytes();\n       let mut data = inst_identifier.to_vec();\n       data.extend(destnation_prog_data_len_bytes.to_vec());\n       data.extend(destination_prog_data);\n\n\n\n\n\n       let account_infos = vec![\n           ctx.accounts.signing_pda.to_account_info(),\n           sender_ATA.to_account_info(),\n           receiver_ATA.to_account_info(),\n           tkn_prog.to_account_info(),\n           auth.to_account_info(),\n           bridge_owner_pda.to_account_info(),\n       ];\n\n\n       //Construct instruction\n        let inst = Instruction{\n           program_id: destination_prog.key(),\n           accounts: account_metas,\n           data: data,\n       };\n\n\n       //Invoke CPI\n       invoke_signed(&inst, &account_infos, signer_seeds);\n\n\n\n\n       Ok(())\n   }\n
  • token_transfer_to_solana - This function will be used by cross-chain dapp developers to transfer (or) mint SPL tokens from the destination chain.
  • destination_prog_data - Encoded byte data that is passed from destination chain(Developer can choose the way data gets encoded on destination chain.)
  • All the accounts and encoded byte data passed from the destination chain are unpacked in this function and sent to a given destination contract on solana.
  • The unpacked data will be passed to the execute_state function of the destination contract(Destination contract should implement execute_state function).
  • Prepare the required data to construct instruction and CPI is done using invoke_signed.
  • The instruction will be signed using a PDA derived from defined seeds.
"},{"location":"core/concepts/code.liberies/","title":"Code Libraries","text":"

The following libraries will help you in your integration

"},{"location":"core/concepts/code.liberies/#d11k","title":"D11K","text":"

D11K Guide

https://github.com/dojimanetwork/d11k-ts

"},{"location":"core/concepts/code.liberies/#wallet-js","title":"Wallet-js","text":"

https://github.com/dojimanetwork/wallet-js

"},{"location":"core/concepts/connecting.doj.chain/","title":"Connecting to HERMESChain","text":"

How to connect to Hermesgard, HERMESNode and the base Tendermint layer.

The Network Information comes from four sources:

  1. HERMESNode: Raw blockchain data provided by the HERMESChain state machine. HERMESChain wallets and block explorers will query HERMESChain-specific information here.
  2. Cosmos RPC: Used to query for generic CosmosSDK information.
  3. Tendermint RPC: Used to query for consensus-related information.
"},{"location":"core/concepts/connecting.doj.chain/#cosmos-rpc","title":"Cosmos RPC","text":"

The Cosmos RPC allows Cosmos base blockchain information to be returned. However, not all endpoints have been enabled.

"},{"location":"core/concepts/connecting.doj.chain/#endpoints-guide","title":"Endpoints guide","text":"

https://v1.cosmos.network/rpc/v0.45.1

"},{"location":"core/concepts/connecting.doj.chain/#example-url","title":"Example URL","text":"

https://api-dev.h4s.dojima.network/cosmos/bank/v1beta1/balances/dojima1nh4y3gqxsn7ymm9t45zwsz3h8p9tm7pev8my62

"},{"location":"core/concepts/connecting.doj.chain/#tendermint-rpc","title":"Tendermint RPC","text":"

The Tendermint RPC allows Tendermint consensus information to be returned.

Any Node Ports

  • MAINNET Port: 27147
  • STAGENET Port: 26657
  • TESTNET Port: 26657
"},{"location":"core/concepts/connecting.doj.chain/#endpoints-guide_1","title":"Endpoints guide","text":"

https://docs.tendermint.com/master/rpc/#/

"},{"location":"core/concepts/connecting.doj.chain/#rpc-end-links","title":"Rpc End Links","text":"

https://rpc-dev.h4s.dojima.network/

"},{"location":"core/concepts/connecting.doj.chain/#p2p","title":"P2P","text":"

P2P is the network layer between nodes, useful for network debugging.

TESTNET Port: 26656

P2P Guide

https://docs.tendermint.com/master/spec/p2p/

"},{"location":"core/concepts/querying/","title":"Querying HERMESChain","text":"

How to Query HERMESChain

"},{"location":"core/concepts/querying/#getting-the-fortunas-vault","title":"Getting the Fortunas Vault","text":"

Vaults are fetched from the /inbound_addresses:

https://api-dev.h4s.dojima.network/hermeschain/inbound_addresses

You need to select the address of the Chain the inbound transaction will go to.

The address will be the current active Fortunas Address that accepts inbounds. Do not cache these address as they change regularly.

Example Output, each connected chain will be displayed.

[\n    {\n        \"chain\": \"BTC\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"tb1qnh4y3gqxsn7ymm9t45zwsz3h8p9tm7pejmmxf5\",\n        \"halted\": false,\n        \"gas_rate\": \"2000000\"\n    },\n    {\n        \"chain\": \"BNB\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"tbnb1nh4y3gqxsn7ymm9t45zwsz3h8p9tm7pezkgkh4\",\n        \"halted\": false,\n        \"gas_rate\": \"2000000\"\n    },\n    {\n        \"chain\": \"ETH\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"0xd526d5f47f863eff32b99bc4f9e77ddb4bd2929b\",\n        \"router\": \"0x1e87989b0792c236c383Aa498E52770015af66cf\",\n        \"halted\": false,\n        \"gas_rate\": \"30\"\n    },\n    {\n        \"chain\": \"AR\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"2txTDSdb_RjG12uHZlVsB5jrfPzqxtzScKTtPef2KZ0\",\n        \"halted\": false,\n        \"gas_rate\": \"1412964922\"\n    },\n    {\n        \"chain\": \"SOL\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"82iP5jLLyiuTHbQRrSwUgZ6sKycT2mjbNkncgpm7Duvg\",\n        \"halted\": false,\n        \"gas_rate\": \"15000\"\n    },\n    {\n        \"chain\": \"DOT\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"5H16DLfWFLdpm5C4f9Qr6UkADsT1PtD9jELWF9WKuiC7St1T\",\n        \"halted\": false,\n        \"gas_rate\": \"2000000\"\n    }\n]\n

Warning

If a chain has a router on the inbound address endpoint, then everything must be deposited via the router. The router is a contract that the user first approves, and the deposit call transfers the asset into the network and emits an event to HERMESChain.

This is done because \u201ctokens\u201d on protocols don\u2019t support memos on-chain, thus need to be wrapped by a router which can force a memo.

Note: you can transfer the base asset, eg ETH, directly to the address and skip the router, but it is recommended to deposit everything via the router.

{\n        \"chain\": \"ETH\",\n        \"pub_key\": \"dojimapub1addwnpepqf9eve9a9d5xlvvhlf5mjhan2gu9hk4ptch2asmwun6y43w6a47wqgqjd9f\",\n        \"address\": \"0xd526d5f47f863eff32b99bc4f9e77ddb4bd2929b\",\n        \"router\": \"0x1e87989b0792c236c383Aa498E52770015af66cf\",\n        \"halted\": false,\n        \"gas_rate\": \"30\"\n    },\n

Danger

Never cache vault addresses, they churn regularly.

Danger

Check for the halted parameter and never send funds if it is set to true

Chain: Chain Name

Address: Fortunas Vault inbound address for that chain.,

Halted: Boolean, if the chain is halted. This should be monitored.

gas_rate: rate to be used, e.g. in Stats or GWei. See Fees.

Info

Only pools with \u201cstatus\u201d: \u201cavailable\u201d are available to trade

Info

Make sure to manually add Native $DOJ as a swappable asset.

Info

\u201cassetPrice\u201d tells you the asset\u2019s price in DOJ (DOJ Depth/AssetDepth ). In the above example 1 BNB.BTCB-1DE = 11,205 DOJ

"},{"location":"core/concepts/querying/#decimals-and-base-units","title":"Decimals and Base Units","text":"

All values on HERMESChain are given in 1e8 eg, 100000000 base units (like Bitcoin), and unless postpended by \u201cUSD\u201d, they are in units of DOJ. Even 1e18 assets, such as ETH.ETH, are shortened to 1e8. 1e6 Assets like ETH.USDC, are padded to 1e8. HERMESNode will tell you the decimals for each asset, giving you the opportunity to convert back to native units in your interface.

"},{"location":"core/concepts/transaction.memos/","title":"Transaction Memos","text":"

Transaction Memo Details

"},{"location":"core/concepts/transaction.memos/#overview","title":"Overview","text":"

A memo serves as additional data attached to a transaction, facilitating the communication of user intent to the Hermes Chain. The memo field signifies the type of transaction being executed, such as SWAP, WITHDRAW, or RESERVE, among others. Hermes Chain inspects the transaction object as well as the MEMO in order to process the transaction. It is essential to ensure that both the memo and the transaction are valid; otherwise, Hermes Chain will automatically refund the assets.

Different chains employ various methods to include state information within a transaction. Long assets can be shortened using Asset abbreviations (below) as well as Hermes Names to reduce the size of destination/affiliate addresses.

"},{"location":"core/concepts/transaction.memos/#format","title":"Format","text":"

Memos follow the format:

TYPE:PARAM1:PARAM2:PARAM3:PARAM4

The type is invoked by a string, which in turn calls a particular handler in the state machine. The state machine parses the memo looking for the parameters which is simply decodes from human-readable strings.

In addition, some parameters are optional. Simply leave them blank, but retain the : separator:

TYPE:PARAM1:::PARAM4

"},{"location":"core/concepts/transaction.memos/#permitted-memos","title":"Permitted Memos","text":"

The following memos are permitted:

  1. SWAP
  2. ADD Liquidity
  3. WITHDRAW Liquidity
  4. BOND, UNBOND & LEAVE
  5. DONATE & RESERVE
  6. NOOP
"},{"location":"core/concepts/transaction.memos/#swap","title":"Swap","text":"

Perform a swap.

SWAP:ASSET:DESTADDR:LIM:AFFILIATE:FEE

Parameter Note Conditions Payload Send the asset to swap. Must be an active pool on Hermes Chain. SWAP The swap handler also s, = :ASSET The asset identifier. Can be shortened. :DESTADDR The destination address to send to. Can use HERMESName. :LIM The trade limit ie, set 100000000 to get a minimum of 1 full asset, else a refund. Optional, 1e8 format :AFFILIATE The affiliate address. DOJ is sent to Affiliate. Optional. Must be HERMESName or HERMES Address. :FEE The affiliate fee. Limited from 0 to 1000 Basis Points Optional

Examples

SWAP:ASSET:DESTADDR simply swap

=:ASSET:DESTADDR:LIM swap with limit

s:ASSET:DESTADDR:LIM:AFFILIATE:FEE swap with limit and affiliate

=:DOJIMA.DOJ:dojima1el4ufmhll3yw7zxzszvfakrk66j7fx0tvcslym:19779138111

s:BNB/BUSD-BD1:dojima15s4apx9ap7lazpsct42nmvf0t6am4r3w0r64f2:628197586176

"},{"location":"core/concepts/transaction.memos/#adding-and-removing-liquidity","title":"Adding and Removing Liquidity","text":"

Entering and Leaving a Pool

To deposit assets on Hermes Chain, you need a compatible wallet with your assets connected to one of the many User Interfaces. Liquidity providers can add liquidity to any of the active or pending pools. There is no minimum deposit amount, however, your deposit will have to cover the deposit and later a withdrawal fee costs. The ability to manage and withdraw assets is completely noncustodial and does not require any KYC or permission process. Only the original depositor has the ability to withdraw them (based on the address used to deposit the assets). Note, every time you add liquidity, Impermanent Loss Protection time resets.

While Symmetrically additions are recommended, Asymmetrical additions are supported, below are the rules:

If you add symmetrically first;

  • You will be able to add asymmetrically with DOJ later

  • You will be able to add asymmetrically with ASSET later but it would create a new LP position

  • You will be able to add symmetrically later

If you add asymmetrically with ASSET first;

  • You will be able to add asymmetrically with DOJ later but it would create a new LP position

  • You will be able to add asymmetrically with ASSET later

  • You will be able to add symmetrically later but it would create a new LP position

If you add asymmetrically with DOJ first:

  • You will be able to add asymmetrically with DOJ later
  • You will be able to add asymmetrically with ASSET later but it would create a new LP position
  • You will not be able to add symmetrically later
"},{"location":"core/concepts/transaction.memos/#ilp-how-hermes-chain-protects-its-liquidity-providers","title":"ILP: How Hermes Chain protects its Liquidity Providers","text":"

Liquidity Providers will receive 100% Impermanent Loss Protection (ILP) after they have been in the pool for 100 days, getting 1% coverage for each day in the pool. Essentially this means you are adding 1% protection for every day that you provide liquidity. 49 days provided = 49% IL protection, 100 days = 100% IL protection.

Impermanent Loss Protection (ILP) ensures that you will not be worse off providing liquidity into Hermes Chain than just holding two assets, DOJ and ASSET, in your wallet. Protection is always recorded and applied symmetrically to both assets after the deposit is rebalanced to 50/50. Impermanent Loss Protection can also be thought of as deposit protection compared to holding both assets. Minimum withdrawal value will be the same as if you held both assets.

NOTE: The coverage will reset every time you add liquidity to the same pool and withdrawal fees will affect the withdrawal amount. Partial withdrawals do not reset the ILP counter.

"},{"location":"core/concepts/transaction.memos/#add-liquidity","title":"Add Liquidity","text":"

There are rules for adding liquidity, see the rules here and regardless of how it is added, it is subject to Impermanent Loss Protection.

ADD:POOL:PAIREDADDR:AFFILIATE:FEE

Parameter Note Conditions Payload The asset to add liquidity with. Must be supported by Hermes Chain. ADD The Add Liquidity handler. also a, + :POOL The pool to add liquidity to. Can be shortened. :PAIREDADDR The other address to link with. If on external chain, link to HERMES address. If on Hermes Chain, link to external address. If a paired address is found, the LP is matched and added. If none is found, the liquidity is put into pending. Optional. If not specified, a single-sided add-liquidity action is created. :AFFILIATE The affiliate address. The affiliate is added in to the pool as an LP. Optional. Must be HERMESName or HERMES Address. :FEE The affiliate fee. Fee is allocated to the affiliate. Optional. Limited from 0 to 1000 Basis Points.

Examples

ADD:POOL single-sided add liquidity. If this is a position\u2019s first add, liquidity can only be withdrawn to the same address.

+:POOL:PAIREDADDR add on both sides.

a:POOL:PAIREDADDR:AFFILIATE:FEE add with affiliate

+:BTC.BTC:

"},{"location":"core/concepts/transaction.memos/#withdraw-liquidity","title":"Withdraw Liquidity","text":"

Withdraw liquidity from a pool.

A withdrawal can be either dual-sided (wtihdrawn based on pool\u2019s price) or entirely single-sided (converted to one side and sent out).

WITHDRAW:POOL:BASISPOINTS:ASSET

Parameter Note Conditions Payload Send just enough of the asset to cause the transaction to be picked up by Hermes Chain. Caution Dust Limits: BTC,BCH,LTC chains 10k sats; DOGE 1m Sats; ETH 0 wei; HERMES 0 DOJ. WITHDRAW The withdraw handler. also -, wd :POOL The pool to withdraw liquidity from Can be shortened. :BASISPOINTS Basis points (0-10000, where 10000=100%) :ASSET Single-sided withdraw to one side. Optional. Can be shortened. Must be either DOJ or the ASSET.

Examples

WITHDRAW:POOL:10000 dual-sided 100% withdraw liquidity. If a single-address position, this withdraws single-sidedly instead.

-:POOL:1000 dual-sided 10% withdraw liquidity.

wd:POOL:5000:ASSET withdraw 50% liquidity as the asset specified while the rest stays in the pool, eg: wd:BTC.BTC:5000:BTC.BTC

"},{"location":"core/concepts/transaction.memos/#donate-reserve","title":"DONATE & RESERVE","text":"

Donate to a pool or the RESERVE.

DONATE:POOL

Parameter Note Conditions Payload The asset to donate to a Hermes Chain pool. Must be supported by Hermes Chain. Can be DOJ or ASSET. DONATE The donate handler. also % :POOL The pool to withdraw liquidity from. Can be shortened.

RESERVE

Parameter Note Conditions Payload HERMES.DOJ The DOJ to credit to the RESERVE. RESERVE The reserve handler."},{"location":"core/concepts/transaction.memos/#bond-unbond-leave","title":"BOND, UNBOND & LEAVE","text":"

Perform node maintenance features.

BOND:NODEADDR:PROVDER:FEE

Parameter Note Conditions Payload The asset to bond to a Node. Must be DOJ. BOND The bond handler. Anytime :NODEADDR The node to bond with. :PROVIDER Whitelist in a provider. Optional, add a provider :FEE Specify an Operator Fee in Basis Points. Optional, default will be the mimir value (2000 Basis Points). Can be changed anytime.

UNBOND:NODEADDR:AMOUNT

Parameter Note Conditions Payload None required Use MsgDeposit UNBOND The unbond handler. :NODEADDR The node to unbond from. Must be in standby only. :AMOUNT The amount to unbond. In 1e8 format. If setting more than actual bond, then capped at bond.

LEAVE:NODEADDR

Parameter Note Conditions Payload None required Use MsgDeposit LEAVE The leave handler. :NODEADDR The node to force to leave. If in Active, request a churn out to Standby for 1 churn cycle. If in Standby, forces a permanent leave.

Examples

BOND:hermes1xd4j3gk9frpxh8r22runntnqy34lwzrdkazldh

LEAVE:hermes18r8gnfm4qjak47qvpjdtw66ehsx49w99c5wewd

"},{"location":"core/concepts/transaction.memos/#noop","title":"NOOP","text":"

Dev-centric type to fix Hermes Chain state. Caution: may cause loss of funds if not done exactly right at the right time.

NOOP

Parameter Note Conditions Payload The asset to credit to a vault. Must be ASSET or DOJ. NOOP The noop handler Adds to the vault balance, but does not add to the pool. :NOVAULT Do not credit the vault. Optional. Just fix the insolvency issue."},{"location":"core/concepts/transaction.memos/#refunds","title":"Refunds","text":"

The following are the conditions for refunds:

Conditions Note Invalid MEMO If the MEMO is incorrect the user will be refunded. Invalid Assets If the asset for the transaction is incorrect (adding an asset into a wrong pool) the user will be refunded. Exceeding Price Limit If the final value achieved in a trade differs to expected, they are refunded.

Refunds cost fees to prevent Denial of Service attacks. The user will pay the correct outbound fee for that chain.

"},{"location":"core/concepts/transaction.memos/#asset-notation","title":"Asset Notation","text":"

The following is the notation for Assets in Hermes Chain\u2019s system:

Note: CHAIN.ASSET denotes native asset. CHAIN/ASSET denotes a Synthetic Asset

Examples

Assets Notation Bitcoin BTC.BTC (Native) Bitcoin BTC/BTC (Synth) Ethereum ETH.ETH USDT ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7 BNB BNB.BNB (Native) BNB BNB/BNB (Synth) DOJ (BEP2) BNB.DOJ-B1A DOJ (NATIVE) HERMES.DOJ"},{"location":"core/concepts/transaction.memos/#asset-abbreviations","title":"Asset Abbreviations","text":"

Assets can be abbreviated using fuzzy logic. The following will all be matched appropriately. If there are conflicts then the deepest pool is matched. (To prevent attacks).

Notation ETH.USDT ETH.USDT-ec7 ETH.USDT-6994597c13d831ec7 ETH.USDT-0xdac17f958d2ee523a2206206994597c13d831ec7"},{"location":"core/concepts/transaction.memos/#mechanism-for-transaction-intent","title":"Mechanism for Transaction Intent","text":"Chain Mechanism Notes Bitcoin OP_RETURN Limited to 80 bytes. Ethereum Smart Contract Input Use deposit(vault, asset, amount, memo)function, where memo is string Binance Chain MEMO Each transaction has an optional memo, limited to 128 bytes. Monero Extra Data Each transaction can have attached extra data field, that has no limits.

Each chain will have a unique way of adding state to a transaction. Long assets can be shortened using Asset abbreviations (below) as well as HERMESNames to reduce the size of destination/affiliate addresses.\u200b

"},{"location":"core/d11kguide/arweave/","title":"@d11k-ts/arweave","text":""},{"location":"core/d11kguide/arweave/#modules","title":"Modules","text":"
  • client - Custom client for communicating with arweave by using arweave
"},{"location":"core/d11kguide/arweave/#installation","title":"Installation","text":"
yarn add @d11k-ts/arweave\n
"},{"location":"core/d11kguide/arweave/#documentation-basic-usage-examples","title":"Documentation : Basic usage examples","text":""},{"location":"core/d11kguide/arweave/#connect-wallet-to-new-arweaveclient","title":"Connect wallet to new ArweaveClient","text":"
  • Create new Arweave client
  • Network default is Mainnet
// Imports\nimport { ArweaveClient } from '@d11k-ts/arweave'\nimport { Network } from '@d11k-ts/client'\n\n//Connect wallet, get address and check balance \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const arClient = new ArweaveClient({phrase})\n  // testnet\n  // const arClient = new ArweaveClient({\n  //   phrase,\n  //   network: Network.Testnet,\n  //   config:{\n    //   host: \"ar-test.h4s.dojima.network\",\n    //   protocol: \"https\",\n    //   timeout: 100000,\n    // }\n  // })\n  let address = arClient.getAddress()\n  try {\n      const balance = await arClient.getBalance(address)\n      console.log(`Adress: ${address} with balance ${balance}`)\n\n    } catch (error) {\n      console.log(`Caught: ${error} `)\n    }\n}\n
"},{"location":"core/d11kguide/arweave/#mint-testnet-ar-tokens-using-arweaveclient","title":"Mint testnet \u2018ar\u2019 tokens using ArweaveClient","text":"
  • Create new Arweave client
  • Network is set to Testnet
  • By default 2 AR tokens were added to address on every call
  • Note: Testnet tokens are not useful in Mainnet
//Connect wallet, get address, mint tokens and check balance \nconst mintTokensToWallet = async () => {\n  let phrase = \"phrase\"\n  // testnet\n  const arClient = new ArweaveClient({\n    phrase,\n    network: Network.Testnet,\n    config:{\n      host: \"ar-test.h4s.dojima.network\",\n      protocol: \"https\",\n      timeout: 100000,\n    }\n  })\n  let address = arClient.getAddress()\n  try {\n      await arClient.mintArTokens(address)\n        const balance = await arClient.getBalance(address)\n      console.log(`Address: ${address} with balance ${balance}`)\n\n    } catch (error) {\n      console.log(`Caught: ${error} `)\n    }\n}\n
"},{"location":"core/d11kguide/arweave/#transfer-ar-using-arweaveclient","title":"Transfer ar using ArweaveClient","text":"
  • Create new ArweaveClient instance
  • Build transaction
  • Returns txHash as string
const transferAr = async () => {\n  // First initiate ArweaveClient\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  console.log(\"Building transaction\")\n  try {\n    const txid = await arClient.transfer({ \n      recipient,\n      amount: amountToTransfer\n    })\n    console.log(`Transaction sent: ${txid}`)\n    return txid\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • Create new ArweaveClient instance
  • Call getTransactionData(hash) returns hash-details
  • Call getTransactionsHistory(address) returns list of transactions (if any)
// Retrieve transaction data for a particular hash\nconst transactionData = async () => {\n  let hash = \"insert hash\"\n  let Address = arClient.getAddress()\n  try {\n    const txData = await arClient.getTransactionData(\n      hash\n    )\n    console.log(`Transaction data ${txData}`)\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n\n// Retrieve transaction history for a particular address\nconst transactionHistory = async () => {\n  let Address = arClient.getAddress()\n  try {\n    const txHistory = await arClient.getTransactionsHistory({\n      address: Address\n    })\n    console.log(`Found ${txHistory.total.toString()}`)\n    txHistory.txs.forEach(tx => console.log(tx))\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#get-gas-fee-for-transaction","title":"Get gas fee for transaction","text":"
  • Retrieve gas fee for transaction from build tx
const fee = async () => {\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  try {\n    const rawTx = await arClient.createTransaction(\n        recipient, \n       amountToTransfer\n    )\n    const fees = arClient.getFees(rawTx)\n    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#get-arweave-inbound-address","title":"Get Arweave Inbound address","text":"
  • Get Arweave Inbound address from hermes chain
  • Can be used in adding liquidity pool and swapping
const inboundAddr = async () => {\n  try {\n    const inboundAddress = await arClient.getArweaveInboundAddress()\n    console.log('Inbound Address :: ', inboundAddress)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#get-default-liquidity-pool-gas-fee","title":"Get default liquidity pool gas fee","text":"
  • Get Arweave default liquidity pool gas fee from hermes chain
const defaultLPGasFee = async () => {\n  try {\n    const LPDefaultGasFee = await arClient.getDefaultLiquidityPoolGasFee()\n    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#add-ar-token-into-liquidity-pool","title":"Add AR token into liquidity pool","text":"
  • Add AR tokens into liquidity pool
  • Get Arweave Inbound address from hermes chain
const addARToLiquidityPool = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await arClient.getArweaveInboundAddress()\n  try {\n    const liquidityPoolHash = await arClient.addLiquidityPool(\n      amountToTransfer,\n      inboundAddress,\n      dojAddress,           // optional dojima address\n    )\n    console.log('Liquidity pool hash : ', liquidityPoolHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#swap-ar-tokens","title":"Swap AR tokens","text":"
  • Swap AR tokens to required token using receiver address
  • Get Arweave Inbound address from hermes chain
  • Supported tokens for swapping - \u2018DOT\u2019, \u2018DOJ\u2019, \u2018ETH\u2019, \u2018SOL\u2019
import {SwapAssetList} from '@d11k-ts/utils'\n\nconst swapAR = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await arClient.getArweaveInboundAddress()\n  try {\n    const swapHash = await arClient.swap(\n       amountToTransfer,\n      SwapAssetList,\n      inboundAddress,\n      reciepient                // Respective receiver SwapAssetList token address\n    )\n    console.log('Swap tx hash : ', swapHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/arweave/#example-code","title":"Example Code","text":"

For sample code check out example test case in Arweeave

"},{"location":"core/d11kguide/binance-becon/","title":"@d11k-ts/binance-beacon","text":""},{"location":"core/d11kguide/binance-becon/#modules","title":"Modules","text":"
  • client - Custom client for communicating with Binance Chain by using binance-chain/javascript-sdk
  • types - TypeScript type definitions for binance-chain/javascript-sdk (not completed) and Binance WebSocket Streams.
  • util - Utitilies for using binance-chain/javascript-sdk
"},{"location":"core/d11kguide/binance-becon/#installation","title":"Installation","text":"
yarn add @d11k-ts/binance-beacon\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/binance-beacon.

yarn add @binance-chain/javascript-sdk\n
"},{"location":"core/d11kguide/binance-becon/#service-providers","title":"Service Providers","text":"

This package uses the following service providers:

Function Service Notes Rate limits Balances Binance Dex https://docs.binance.org/api-reference/dex-api/paths.html#apiv1accountaddress 5 requests per IP per second. Transaction history Binance Dex https://docs.binance.org/api-reference/dex-api/paths.html#apiv1transactions 60 requests per IP per minute Transaction details by hash Binance Dex https://docs.binance.org/api-reference/dex-api/paths.html#apiv1txhash 10 requests per IP per second Transaction fees Binance Dex https://docs.binance.org/api-reference/dex-api/paths.html#apiv1fees 1 request per IP per second Transaction broadcast Binance Dex https://docs.binance.org/api-reference/dex-api/paths.html#apiv1broadcast 5 requests per IP per second Explorer Binance Dex Explorer https://explorer.binance.org

This package gets the node information (https://docs.binance.org/api-reference/dex-api/paths.html#apiv1node-info) to transfer tokens.

"},{"location":"core/d11kguide/binance-becon/#documentation-basic-usage-example","title":"Documentation : Basic Usage Example","text":""},{"location":"core/d11kguide/binance-becon/#connect-wallet-to-new-binance-beacon-chain-client","title":"Connect wallet to new Binance-beacon Chain Client","text":"
  • Create new BinanceBeaconChain client
  • Network default is Mainnet
//Imports \nimport {BinanceBeaconClient} from '@d11k-ts/binance-beacon'\nimport {Network} from '@d11k-ts/client'\nimport {AssetBNB, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'\n\n// Connect wallet to new btc client \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // mainnet\n  const bnbClient = new BinanceBeaconClient({phrase})\n  // testnet\n  // const bnbClient = new BinanceBeaconClient({ phrase, network: Network.Testnet })\n  let address = bnbClient.getAddress()\n  console.log(`Asset Address is: ${address}`)\n\n  let balances = await bnbClient.getBalance(address, [AssetBNB])\n  try {\n    let assetAmount = (baseToAsset(balances[0].amount)).amount()\n    console.log(`with balance: ${assetAmount}`)\n  } catch (error) {\n    console.log('no balance')\n  }\n}\n
"},{"location":"core/d11kguide/binance-becon/#transfer-bnb-using-binance-beacon-client","title":"Transfer bnb using Binance-beacon Client","text":"
  • Default feeRate is fast
  • Create new Binance-beaconClient instance
  • Convert amount to transfer to base amount
  • Build transaction
  • Returns txHash as string
const transferBnb = async () => {\n  // First initiate BinanceBeaconClient\n  let amountToTransfer = 0.0001\n  let recipient = 'insert address'\n  let amount = assetToBase(assetAmount(amountToTransfer, 8))\n  console.log(\"Building transaction\")\n  try {\n    const txid = await bnbClient.transfer({\n      \"amount\": amount,\n      \"recipient\": recipient,\n      \"memo\": \"memo\",             // optional\n      \"walletIndex\": 0,            // optional (default)\n      \"asset\": AssetBNB,          // optional (default)\n\n    })\n    console.log(`Amount ${amount.amount().toString()} ${AssetBNB.symbol} TransactionId: ${txid}`)\n  } catch (error) {\n    console.log(`Transfer failed: ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/binance-becon/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • Create new Binance-beaconClient instance
  • Call getTransactionData(hash) returns hash-details
  • Call getTransactions(address) returns list of transactions (if any)
let hash = \"insert hash string\"\ntry {\n  const txData = await bnbClient.getTransactionData(hash)\n  console.log(txData)\n\n} catch (error) {\n  console.log(`Error: ${error}`)\n}\n\n// Retrieve transaction history for a set address\n// txHistoryParams > address, offset, startTime, asset? \ntry {\n  const txHistory = await bnbClient.getTransactions({address: Address, limit: 4})\n  console.log(`Found ${txHistory.total.toString()}`)\n  txHistory.txs.forEach(tx => console.log(tx))\n\n} catch (error) {\n  console.log(`Error: ${error}`)\n}\n
"},{"location":"core/d11kguide/binance-becon/#get-transfer-fees","title":"Get transfer fees","text":"
  • Bnb has fixed fee client, average, fast and fastest return the same value.
  • getFees() returns current fees for the network
try {\n  const fee = await bnbClient.getFees()\n  console.log(`Fees average:  ${baseToAsset(fee.average).amount()}`)\n  console.log(`Fees fast:  ${baseToAsset(fee.fast).amount()}`)\n  console.log(`Fees fastest:  ${baseToAsset(fee.fastest).amount()}`)\n\n} catch (error) {\n  console.log(error)\n}\n
"},{"location":"core/d11kguide/binance-becon/#example-code","title":"Example Code","text":"

For sample code check out example test case in Binance-Beacon

"},{"location":"core/d11kguide/bitcoin/","title":"@d11k-ts/bitcoin","text":""},{"location":"core/d11kguide/bitcoin/#modules","title":"Modules","text":"
  • client - Client for communicating with Bitcoin using BIP39 , bitcoinjs-lib and WIF
  • types - TypeScript type definitions based on @d11k-ts/client and @d11k-ts/utils
  • utils - Utitilies for using haskoin and sochain endpoints in Bitcoin client
"},{"location":"core/d11kguide/bitcoin/#installation","title":"Installation","text":"
yarn add @d11k-ts/bitcoin\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/bitcoin.

yarn add axios coinselect\n
"},{"location":"core/d11kguide/bitcoin/#service-providers","title":"Service Providers","text":"

This package uses the following service providers:

Function Service Notes Balances Sochain https://chain.so/api/v2#get-balance Transaction history Sochain https://chain.so/api/v2#get-display-data-address, https://chain.so/api/v2#get-tx Transaction details by hash Sochain https://chain.so/api/v2#get-tx Transaction fees Bitgo https://app.bitgo.com/docs/#operation/v2.tx.getfeeestimate Transaction broadcast / utxos Sochain / Haskoin https://chain.so/api/v2#send-transaction, https://haskoin.ninerealms.com/btc Explorer Blockstream https://blockstream.info

Sochain API rate limits: https://chain.so/api/v2#rate-limits (300 requests/minute)

Bitgo API rate limits: https://app.bitgo.com/docs/#section/Rate-Limiting (10 requests/second)

Haskoin API : https://haskoin.ninerealms.com/btc

"},{"location":"core/d11kguide/bitcoin/#documentation-basic-usage-example","title":"Documentation : Basic Usage Example","text":""},{"location":"core/d11kguide/bitcoin/#connect-wallet-to-new-bitcoinclient","title":"Connect wallet to new BitcoinClient","text":"
  • Create new Bitcoin client
  • Network default is Mainnet
//Imports\nimport {BTC_DECIMAL, BitcoinClient} from '@d11k-ts/bitcoin'\nimport {Network} from '@d11k-ts/client'\nimport {AssetBTC, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'\n\n// Connect wallet to new btc client \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const btcClient = new BitcoinClient({phrase})\n  // testnet\n  // const bnbClient = new BitcoinClient({ phrase, network: Network.Testnet })\n  let address = btcClient.getAddress()\n  console.log(`Asset Address is: ${address}`)\n\n  let balances = await btcClient.getBalance(address, [AssetBTC])\n  try {\n    let assetAmount = (baseToAsset(balances[0].amount)).amount()\n    console.log(`Asset address balance: ${assetAmount}`)\n  } catch (error) {\n    console.log('Address has no balance')\n  }\n}\n
"},{"location":"core/d11kguide/bitcoin/#transfer-btc-using-bitcoinclient","title":"Transfer btc using BitcoinClient","text":"
  • Default feeRate is fast
  • Create new BitcoinClient instance
  • Convert amount to transfer to base amount
  • Build transaction
  • Returns txHash as string
const transfer = async () => {\n  // First initiate BitcoinClient\n  let amountToTransfer = 0.0001\n  let recipient = 'insert address'\n  let amount = assetToBase(assetAmount(amountToTransfer, BTC_DECIMAL))\n  try {\n    const txid = await btcClient.transfer({\n      asset: AssetBTC,\n      recipient: recipient,\n      amount: amount,\n      memo: \"payment\"         // optional\n    })\n    console.log(`Amount: ${amount.amount().toString()} ${AssetBTC.symbol} Transaction id: ${txid}`)\n  } catch (error) {\n    console.log(`Transfer failed ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/bitcoin/#transfer-by-setting-feerate","title":"Transfer by setting feeRate","text":"
  • Build transaction using parameters
  • Set feeRate in transaction parameters Or use getFeeRates()
//Returns FeeRates > this allows for dynamic feeRate adjustment on selection\nconst {fast, fastest, average} = await btcClient.getFeeRates()\n\ntry {\n  const txid = await btcClient.transfer({\n    'asset': AssetBTC,\n    'recipient': recipient,\n    'amount': amount,\n    'memo': \"test transfer\",        // optional\n    feeRate: fast\n  })\n  console.log(`Amount ${baseToAsset(amount).amount()} ${AssetBTC.symbol} Transaction id ${txid}`)\n} catch (error) {\n  console.log(`Transfer failed ${error}`)\n}\n
"},{"location":"core/d11kguide/bitcoin/#get-fees-feerates-estimations","title":"Get Fees & FeeRates estimations","text":"
//Get Fees - returns FeeOption & fee in BaseAmount \n` Fees Fast: 0.00001 Fastest: 0.0000468 Average: 0.00001 `\ntry {\n  const {fast, fastest, average} = await btcClient.getFees()\n  console.log(`Fees Fast: ${baseToAsset(fast).amount()} Fastest: ${baseToAsset(fastest).amount()} Average: ${baseToAsset(average).amount()}`)\n\n} catch (error) {\n  console.log(error)\n}\n\n//Get FeeRates - returns FeeOption & rate  \n` Fast: 12, Fastest 60, Average: 6 `\n\ntry {\n  const {fast, fastest, average} = await btcClient.getFeeRates()\n  console.log(`Fast: ${fast}, Fastest ${fastest}, Average: ${average}`)\n\n} catch (error) {\n  console.log(error)\n}\n
"},{"location":"core/d11kguide/bitcoin/#get-transaction-data","title":"Get transaction data","text":"
  • Create new BitcoinClient instance
  • Call getTransaction(hash) returns hashDetails
const transactionData = async () => {\n  let hash = \"txhash string\"\n  try {\n    const txData = await btcClient.getTransactionData(hash)\n    console.log(`From ${JSON.stringify(txData)}`)\n\n  } catch (error) {\n    console.log(`Error: ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/bitcoin/#get-transaction-history","title":"Get Transaction History","text":"
  • Create new Binance-beaconClient instance
  • Call getTransactions(address) returns list of transactions (if any)
const transactionHistory = async () => {\n  // Retrieve transaction history for a set address\n  // txHistoryParams > address, offset, startTime, asset?\n  try {\n    const txHistory = await btcClient.getTransactions({address: Address, limit: 4})\n    console.log(`Found ${txHistory.total.toString()}`)\n    txHistory.txs.forEach(tx => console.log(tx))\n\n  } catch (error) {\n    console.log(`Error: ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/bitcoin/#example-code","title":"Example Code","text":"

For sample code check out example test case in Bitcoin

"},{"location":"core/d11kguide/client/","title":"@d11k-ts/client","text":""},{"location":"core/d11kguide/client/#installation","title":"Installation","text":"
yarn add @d11k-ts/client\n

Initialise and set up the client to connect to its necessary third-party services to fulfil basic functionality. The third-party services used must be at a minimum to fulfil the wallet functionality, such as displaying balances and sending transactions.

"},{"location":"core/d11kguide/client/#d11k-ts-wallet-client-interface","title":"D11K-ts Wallet Client Interface","text":"

A specification for a generalised interface for crypto wallets clients, to be used by D11K-ts implementations. The client should not have any functionality to generate a key, instead, the asgardex-crypto library should be used to ensure cross-chain compatible keystores are handled. The client is only ever passed a master BIP39 phrase, from which a temporary key and address is decoded.

"},{"location":"core/d11kguide/cosmos/","title":"@d11k-ts/cosmos","text":"

Cosmos Module for D11K clients

"},{"location":"core/d11kguide/cosmos/#installation","title":"Installation","text":"
yarn add @d11k-ts/cosmos\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/cosmos.

yarn add axios @cosmos-client/core@^0.45.13\n

NOTE : Make sure to install same version of @cosmos-client/core as @d11k-ts/cosmos is using (currently \u201c@cosmos-client/core\u201d: \u201c^0.45.13\u201d, ). In other case things might break.

"},{"location":"core/d11kguide/cosmos/#cosmos-client-testing","title":"Cosmos Client Testing","text":"
yarn install\nyarn test\n
"},{"location":"core/d11kguide/cosmos/#documentation","title":"Documentation","text":"

Yet to be added.

"},{"location":"core/d11kguide/cosmos/#service-providers","title":"Service Providers","text":"

This package uses the following service providers:

Function Service Notes Balances Cosmos RPC https://cosmos.network/rpc/v0.37.9 (GET /bank/balances/{address}) Transaction history Cosmos RPC https://cosmos.network/rpc/v0.37.9 (GET /txs) Transaction details by hash Cosmos RPC https://cosmos.network/rpc/v0.37.9 (GET /txs/{hash}) Transaction broadcast Cosmos RPC https://cosmos.network/rpc/v0.37.9 (POST /txs) Explorer BigDipper https://cosmos.bigdipper.live

Rate limits: No

"},{"location":"core/d11kguide/crypto/","title":"@d11k-ts/crypto","text":"

The D11K CRYPTO package is a crypto package used by all D11K clients.

D11K-CRYPTO encrypts a master phrase to a keystore. This keystore can then be exported to other D11K wallets or stored securely.

Users can export their phrase and import them into other wallets since it is a BIP39 compatible phrase.

"},{"location":"core/d11kguide/crypto/#installation","title":"Installation","text":"
  • Install @d11k-ts/crypto from npm
yarn add @d11k-ts/crypto\n
"},{"location":"core/d11kguide/crypto/#build","title":"Build","text":"
yarn build\n
"},{"location":"core/d11kguide/crypto/#tests","title":"Tests","text":"
yarn test\n
"},{"location":"core/d11kguide/crypto/#constants","title":"Constants","text":"
// Crypto Constants for chain\nconst cipher = 'aes-128-ctr'\nconst kdf = 'pbkdf2'\nconst prf = 'hmac-sha256'\nconst dklen = 32\nconst c = 262144\nconst hashFunction = 'sha256'\nconst meta = 'd11k-keystore'\n
"},{"location":"core/d11kguide/crypto/#keystore-type","title":"Keystore Type","text":"
export type Keystore = {\n  address: string,\n  crypto: {\n    cipher: string,\n    ciphertext: string,\n    cipherparams: {\n      iv: string\n    },\n    kdf: string,\n    kdfparams: {\n      prf: string,\n      dklen: number,\n      salt: string,\n      c: number,\n    },\n    mac: string,\n  },\n  id: string,\n  version: number,\n  meta: string,\n}\n
"},{"location":"core/d11kguide/ethereum/","title":"@d11k-ts/ethereum","text":""},{"location":"core/d11kguide/ethereum/#modules","title":"Modules","text":"
  • client - Custom client for communicating with Ethereum by using ethers
"},{"location":"core/d11kguide/ethereum/#installation","title":"Installation","text":"
yarn add @d11k-ts/ethereum\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/ethereum.

yarn add axios ethers\n
"},{"location":"core/d11kguide/ethereum/#service-providers","title":"Service Providers","text":"

This package uses the following service providers:

Function Service Notes ETH balances Etherscan https://etherscan.io/apis#accounts (module=account, action=balance) Token balances Etherscan https://etherscan.io/apis#tokens (module=account, action=tokenbalance) ETH transaction history Etherscan https://etherscan.io/apis#accounts (module=account, action=txlistinternal) Token transaction history Etherscan https://etherscan.io/apis#accounts (module=account, action=tokentx) Transaction fees Etherscan https://etherscan.io/apis#gastracker (module=gastracker, action=gasoracle) Transaction broadcast Etherscan https://sebs.github.io/etherscan-api/#eth_sendrawtransaction Explorer Etherscan https://etherscan.io/

Etherscan API rate limits: https://info.etherscan.com/api-return-errors/

  • Testnet API - https://api-goerli.etherscan.io/ , Explorer - https://goerli.etherscan.io/

  • This package uses etherjs library, by default it uses several providers. (https://docs.ethers.io/v5/api-keys/)

"},{"location":"core/d11kguide/ethereum/#documentation-basic-usage-examples","title":"Documentation : Basic usage examples","text":""},{"location":"core/d11kguide/ethereum/#connect-wallet-to-new-ethereumclient","title":"Connect wallet to new EthereumClient","text":"
  • Create new EthereumChain client
  • Network default is Mainnet
// Imports\nimport {Network} from '@d11k-ts/client'\nimport {ETH_DECIMAL, EthereumClient} from '@d11k-ts/ethereum'\nimport {assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'\n\n//Connect wallet, validate address and check balance \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const ethClient = new EthereumClient({phrase})\n  // testnet\n  // const bnbClient = new EthereumClient({ \n  //    phrase, \n  //    network: Network.Testnet,\n  //    etherscanApiKey: 'get-etherscan-api-key',\n  //    ethplorerApiKey: 'get-ethplorer-api-key',\n  //  })\n  let address = ethClient.getAddress()\n  let isValid = ethClient.validateAddress(address)\n  console.log(address)\n  if (isValid === true) {\n    try {\n      const balance = await ethClient.getBalance(address)\n      let assetAmount = (baseToAsset(balance[0].amount)).amount()\n      console.log(`Adress: ${address} with balance ${assetAmount}`)\n\n    } catch (error) {\n      console.log(`Caught: ${error} `)\n    }\n  } else {\n    console.log(`Address: ${address} is invalid`)\n  }\n}\n
"},{"location":"core/d11kguide/ethereum/#transfer-eth-using-ethereumclient","title":"Transfer eth using EthereumClient","text":"
  • Create new EthereumClient instance
  • Convert amount to transfer to base amount
  • Build transaction
  • Returns txHash as string
// Transfer ethereum other TxParams > feeOptionKey?, gasLimit?, gasPrice? \nconst transferEth = async () => {\n  // First initiate EthereumClient\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  let amount = assetToBase(assetAmount(amountToTransfer, ETH_DECIMAL))\n  console.log(\"Building transaction\")\n  try {\n    const txid = await ethClient.transfer({\n      amount,\n      recipient,\n      \"memo\": \"memo\",               // optional\n      \"walletIndex\": 0,             // optional (default)\n      \"asset\": AssetETH,            // optional (default)\n    })\n    console.log(`Transaction sent: ${txid}`)\n    return txid\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/ethereum/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • Create new EthereumClient instance
  • Call getTransactionData(hash) returns hash-details
  • Call getTransactions(address) returns list of transactions (if any)
// Retrieve transaction data for a particular hash\nconst transactionData = async () => {\n  let hash = \"insert hash\"\n  let Address = ethClient.getAddress()\n  try {\n    const txData = await ethClient.getTransactionData(\n      hash,\n      Address         // optional\n    )\n    console.log(`Transaction data ${txData}`)\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n\n// Retrieve transaction history for a particular address\nconst transactionHistory = async () => {\n  let Address = ethClient.getAddress()\n  try {\n    const txHistory = await ethClient.getTransactions({address: Address})\n    console.log(`Found ${txHistory.total.toString()}`)\n    txHistory.txs.forEach(tx => console.log(tx))\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/ethereum/#get-transfer-fees-estimations","title":"Get transfer Fees estimations","text":"
  • Retrieve estimated gas prices and gas limits from ethereum client
// Retrieve fee estimations from transaction parameters\nconst feeEstimations = async () => {\n  let amountToTransfer = 0.001\n  let amount = assetToBase(assetAmount(amountToTransfer, ETH_DECIMAL))\n  let recipient = \"insert address\"\n  try {\n    const fees = await ethClient.estimateFeesWithGasPricesAndLimits({\n      \"amount\": amount,\n      \"recipient\": recipient\n    })\n    console.log(`Fees average : ${baseToAsset(fees.fees.average).amount()}, gas limits: ${fees.gasLimit}, gas prices average: ${baseToAsset(fees.gasPrices.average).amount()}`)\n\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/ethereum/#example-code","title":"Example Code","text":"

For sample code check out example test case in Ethereum

"},{"location":"core/d11kguide/hermes/","title":"@d11k-ts/hermes","text":"

Hermes Module for Dojima chain

"},{"location":"core/d11kguide/hermes/#installation","title":"Installation","text":"
yarn add @d11k-ts/hermes\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/hermes.

yarn add axios @cosmos-client/core@^0.45.13 bech32-buffer@^0.2.1\n

NOTE: Make sure to install same version of @cosmos-client/core and bech32-buffer as @d11k-ts/cosmos is using ( currently \u201c@cosmos-client/core\u201d: \u201c^0.45.13\u201d, \u201cbech32-buffer\u201d: \u201c^0.2.1\u201d). In other case things might break.

"},{"location":"core/d11kguide/hermes/#service-providers","title":"Service Providers","text":"

This package uses the following service providers:

Network Node RPC Testnet https://api-dev.h4s.dojima.network https://rpc-dev.h4s.dojima.network/ Mainnet NA NA

Note : \u2018Mainnet\u2019 is currently under process. Not applicable yet.

Function Service Notes Balances Cosmos RPC https://cosmos.network/rpc/v0.37.9 (GET /bank/balances/{address}) Transaction history Tendermint RPC https://docs.tendermint.com/master/rpc/#/Info/tx_search Transaction details by hash Cosmos RPC https://cosmos.network/rpc/v0.37.9 (GET /txs/{hash}) Transaction broadcast Cosmos RPC https://cosmos.network/rpc/v0.37.9 (POST /txs)

Rate limits: No

"},{"location":"core/d11kguide/hermes/#documentation-basic-usage-example","title":"Documentation: Basic usage example","text":""},{"location":"core/d11kguide/hermes/#connect-wallet-to-new-hermes-client","title":"Connect wallet to new Hermes Client","text":"
  • Create new HermesChain client
  • Network default is Mainnet
// Imports \nimport {Network} from '@d11k-ts/client'\nimport {DOJ_DECIMAL, HermesClient} from '@d11k-ts/hermes'\nimport {AssetDOJNative, assetAmount, assetToBase, baseToAsset} from '@d11k-ts/utils'\n\n\n// Create new instance of the client and query chain for balances. \nconst connectWallet = async () => {\n\n  let phrase = \"phrase\"\n  // mainnet\n  const hermesClient = new HermesClient({phrase})\n  // testnet\n  // const hermesClient = new HermesClient({ phrase, network: Network.Testnet })\n\n  let address = hermesClient.getAddress()\n  console.log(`Address: ${address}`)\n  try {\n    const balance = await hermesClient.getBalance(address, [AssetDOJNative])\n    let assetAmount = (baseToAsset(balance[0].amount)).amount()\n    console.log(`With balance: ${assetAmount}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/hermes/#transfer-doj-using-hermes-client","title":"Transfer doj using Hermes Client","text":"
  • Default feeRate is fast
  • Create new HermesChain client instance
  • Convert amount to transfer to base amount
  • Build transaction
  • Returns txHash as string
const transferDoj = async () => {\n\n  // First initiate HermesClient\n  let amountToTransfer = 0.1\n  let amount = assetToBase(assetAmount(amountToTransfer, DOJ_DECIMAL))\n  let recipient = \"insert address\"\n  try {\n    const txid = await hermesClient.transfer({\n      \"amount\": amount,\n      \"recipient\": recipient,\n      \"memo\": \"test\",             // optional\n      \"asset\": AssetDOJNative,    // optional (default)\n      \"walletIndex\": 0            // optional (default)\n    })\n    console.log(`Transaction sent: ${txid}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/hermes/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • Create new HermesClient instance
  • Call getTransactionData(hash) returns hash-details
  • Call getTransactions(address) returns list of transactions (if any)
const transactionData = async () => {\n\n  // First initiate HermesClient\n  let hash = \"insert hash\"\n  let address = hermesClient.getAddress()\n  try {\n    const txData = await hermesClient.getTransactionData(hash, address)\n    console.log(txData)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n// By default getTransactions() returns the transactions for the current address\n// Optional param - any dojima address\nconst transactionHistory = async () => {\n  try {\n    const txHistory = await hermesClient.getTransactions(address)\n    console.log(`Found ${txHistory.total}`)\n    txHistory.txs.forEach(tx => console.log(tx.hash))\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/hermes/#get-transfer-fees","title":"Get transfer Fees","text":"
  • Hermeschain runs on fee type of Flatfee set to 0.02 DOJ
// Returns Fees Fast: 0.02 Fastest: 0.02 Average: 0.02\nconst fee = async () => {\n\n  // First initiate HermesClient\n  try {\n    const {fast, fastest, average} = await hermesClient.getFees()\n    console.log(`Fees Fast: ${baseToAsset(fast).amount()} Fastest: ${baseToAsset(fastest).amount()} Average: ${baseToAsset(average).amount()}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/hermes/#deposit-doj-using-hermes-client","title":"Deposit doj using Hermes Client","text":"
  • Create new HermesChain client instance
  • Convert amount to transfer to base amount
  • Deposit transaction
  • Returns txHash as string
import {SwapAssetList} from '@d11k-ts/utils'\n\nconst transferDoj = async () => {\n\n  // First initiate HermesClient\n  let amountToTransfer = 0.1\n  let amount = assetToBase(assetAmount(amountToTransfer, DOJ_DECIMAL))\n  // amount: number     Note: convert amount to 'BaseAmount' before passing to transfer function\n  // memo: string\n  'ADD:{SwapAssetList}:{respective-token-address}'\n  'SWAP:{SwapAssetList}:{receiver-token-address}'\n  try {\n    // 'memo' with ADD\n    const txid = await hermesClient.deposit({\n      amount,\n      memo: `ADD:{SwapAssetList}:{respective-token-address}`,\n    })\n    // 'memo' with SWAP\n    // const depositHash = await hermesClient.deposit({\n    //   amount,\n    //   memo: `SWAP:{SwapAssetList}:{receiver-token-address}`,\n    // })\n    console.log(`Deposit tx hash: ${txid}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/hermes/#example-code","title":"Example Code","text":"

For sample code check out example test case in Hermes

"},{"location":"core/d11kguide/polkadot/","title":"@d11k-ts/polkadot","text":""},{"location":"core/d11kguide/polkadot/#modules","title":"Modules","text":"
  • client - Custom client for communicating with polkadot by using @polkadot/api
"},{"location":"core/d11kguide/polkadot/#installation","title":"Installation","text":"
yarn add @d11k-ts/polkadot\n
"},{"location":"core/d11kguide/polkadot/#documentation-basic-usage-examples","title":"Documentation : Basic usage examples","text":""},{"location":"core/d11kguide/polkadot/#connect-wallet-to-new-polkadotclient","title":"Connect wallet to new PolkadotClient","text":"
  • Create new Polkadot client
  • Network default is Mainnet
// Imports\nimport { Network } from '@d11k-ts/client'\nimport { PolkadotClient } from '@d11k-ts/polkadot'\n\n//Connect wallet, get address and check balance \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const polkaClient = new PolkadotClient({phrase})\n  // testnet\n  // const polkaClient = new PolkadotClient({ \n  //    phrase, \n  //    network: Network.Testnet \n  //    provider: 'wss://dotws-test.h4s.dojima.network:9944'\n  // })\n  let address = polkaClient.getAddress()\n  try {\n      const balance = await polkaClient.getBalance(address)\n      console.log(`Adress: ${address} with balance ${balance}`)\n\n    } catch (error) {\n      console.log(`Caught: ${error} `)\n    }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#transfer-dot-using-polkadotclient","title":"Transfer dot using PolkadotClient","text":"
  • Create new PolkadotClient instance
  • Build transaction
  • Returns txHash as string
const transferDot = async () => {\n  // First initiate PolkadotClient\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  console.log(\"Building transaction\")\n  try {\n    const txid = await polkaClient.transfer({ \n      recipient,\n      amount: amountToTransfer\n    })\n    console.log(`Transaction sent: ${txid}`)\n    return txid\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • No code for retrieving tx data and history in @d11k-ts/polkadot.
  • View tx details in explorer
  • Mainnet : polkadot-subscan
"},{"location":"core/d11kguide/polkadot/#get-gas-fee-for-transaction","title":"Get gas fee for transaction","text":"
  • Retrieve gas fee for transaction from build tx
const fee = async () => {\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  try {\n    const fees = polkaClient.getFees({\n      recipient,\n      amount: amountToTransfer\n    })\n    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#get-polkadot-inbound-address","title":"Get Polkadot Inbound address","text":"
  • Get Polkadot Inbound address from hermes chain
  • Can be used in adding liquidity pool and swapping
const inboundAddr = async () => {\n  try {\n    const inboundAddress = await polkaClient.getPolkadotInboundAddress()\n    console.log('Inbound Address :: ', inboundAddress)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#get-default-liquidity-pool-gas-fee","title":"Get default liquidity pool gas fee","text":"
  • Get Polkadot default liquidity pool gas fee from hermes chain
const defaultLPGasFee = async () => {\n  try {\n    const LPDefaultGasFee = await polkaClient.getDefaultLiquidityPoolGasFee()\n    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#add-dot-token-into-liquidity-pool","title":"Add DOT token into liquidity pool","text":"
  • Add DOT tokens into liquidity pool
  • Get Polkadot Inbound address from hermes chain
const addDotToLiquidityPool = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await polkaClient.getPolkadotInboundAddress()\n  try {\n    const liquidityPoolHash = await polkaClient.addLiquidityPool(\n      amountToTransfer,\n      inboundAddress,\n      dojAddress,           // optional dojima address\n    )\n    console.log('Liquidity pool hash : ', liquidityPoolHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#swap-dot-tokens","title":"Swap DOT tokens","text":"
  • Swap DOT tokens to required token using receiver address
  • Get Polkadot Inbound address from hermes chain
  • Supported tokens for swapping - \u2018AR\u2019, \u2018DOJ\u2019, \u2018ETH\u2019, \u2018SOL\u2019
import {SwapAssetList} from '@d11k-ts/utils'\n\nconst swapDOT = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await polkaClient.getPolkadotInboundAddress()\n  try {\n    const swapHash = await polkaClient.swap(\n       amountToTransfer,\n      SwapAssetList,\n      inboundAddress,\n      reciepient                // Respective receiver SwapAssetList token address\n    )\n    console.log('Swap tx hash : ', swapHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n  process.exit()\n}\n
"},{"location":"core/d11kguide/polkadot/#example-code","title":"Example Code","text":"

For sample code check out example test case in Polkadot

"},{"location":"core/d11kguide/solana/","title":"@d11k-ts/solana","text":""},{"location":"core/d11kguide/solana/#modules","title":"Modules","text":"
  • client - Custom client for communicating with solana by using @solana/web3.js
"},{"location":"core/d11kguide/solana/#installation","title":"Installation","text":"
yarn add @d11k-ts/solana\n

Following dependencies have to be installed into your project. These are not included in @d11k-ts/solana.

yarn add axios\n
"},{"location":"core/d11kguide/solana/#documentation-basic-usage-examples","title":"Documentation : Basic usage examples","text":""},{"location":"core/d11kguide/solana/#connect-wallet-to-new-solanaclient","title":"Connect wallet to new SolanaClient","text":"
  • Create new Solana client
  • Network default is Mainnet
// Imports\nimport {SolanaClient} from '@d11k-ts/solana'\nimport {Network} from \"@d11k-ts/client\";\n\n//Connect wallet, get address and check balance \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const solClient = new SolanaClient({phrase})\n  // devnet\n  // const solClient = new SolanaClient({\n  //    phrase, \n  //    network: Network.Stagenet\n  //    endpoint: 'https://sol-test.h4s.dojima.network:8899'\n  // })\n  let address = solClient.getAddress()\n  try {\n    const balance = await solClient.getBalance(address)\n    console.log(`Adress: ${address} with balance ${balance}`)\n\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#request-airdrop-testnet-sol-tokens-using-solanaclient","title":"Request airdrop - testnet \u2018sol\u2019 tokens using SolanaClient","text":"
  • Create new Solana client
  • Network is set to devnet
  • By default 2 SOL tokens were added to address on every call
  • Note: Devnet tokens are not useful in Mainnet
// Imports\nimport {SolanaClient} from '@d11k-ts/solana'\nimport {Network} from \"@d11k-ts/client\";\n\n//Connect wallet, get address, request sol tokens and check balance \nconst connectWallet = async () => {\n  let phrase = \"phrase\"\n  // Mainnet\n  const solClient = new SolanaClient({phrase})\n  // devnet\n  // const solClient = new SolanaClient({\n  //    phrase, \n  //    network: Network.Stagenet\n  //    endpoint: 'https://sol-test.h4s.dojima.network:8899'\n  // })\n  let address = solClient.getAddress()\n  try {\n    await solClient.requestSolTokens(address)\n    const balance = await solClient.getBalance(address)\n    console.log(`Address: ${address} with balance ${balance}`)\n\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#transfer-sol-using-solanaclient","title":"Transfer sol using SolanaClient","text":"
  • Create new SolanaClient instance
  • Build transaction
  • Returns txHash as string
const transferSol = async () => {\n  // First initiate SolanaClient\n  let amountToTransfer = 0.001\n  let recipient = 'insert address'\n  console.log(\"Building transaction\")\n  try {\n    const txid = await solClient.transfer({\n      recipient,\n      amount: amountToTransfer\n    })\n    console.log(`Transaction sent: ${txid}`)\n    return txid\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#get-transaction-data-transaction-history","title":"Get transaction Data & transaction History","text":"
  • Create new SolanaClient instance
  • Call getTransactionData(hash) returns hash-details
  • Call getTransactionsHistory(address) returns list of transactions (if any)
// Retrieve transaction data for a particular hash\nconst transactionData = async () => {\n  let hash = \"insert hash\"\n  let Address = solClient.getAddress()\n  try {\n    const txData = await solClient.getTransactionData(\n      hash\n    )\n    console.log(`Transaction data ${txData}`)\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n\n// Retrieve transaction history for a particular address\nconst transactionHistory = async () => {\n  let Address = solClient.getAddress()\n  try {\n    const txHistory = await solClient.getTransactionsHistory({\n      address: Address\n    })\n    console.log(`Found ${txHistory.total.toString()}`)\n    txHistory.txs.forEach(tx => console.log(tx))\n  } catch (error) {\n    console.log(`Caught: ${error} `)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#get-gas-fee-for-transaction","title":"Get gas fee for transaction","text":"
  • Solana has fixed fee client, average, fast and fastest return the same value
const fee = async () => {\n  try {\n    const fees = solClient.getFees()\n    console.log(`Fees Fast: ${fees.average} Fastest: ${fees.fast} Average: ${fees.slow}`)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#get-solana-inbound-address","title":"Get Solana Inbound address","text":"
  • Get Solana Inbound address from hermes chain

  • Can be used in adding liquidity pool and swapping

const inboundAddr = async () => {\n  try {\n    const inboundAddress = await solClient.getSolanaInboundAddress()\n    console.log('Inbound Address :: ', inboundAddress)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#get-default-liquidity-pool-gas-fee","title":"Get default liquidity pool gas fee","text":"
  • Get Solana default liquidity pool gas fee from hermes chain
const defaultLPGasFee = async () => {\n  try {\n    const LPDefaultGasFee = await solClient.getDefaultLiquidityPoolGasFee()\n    console.log('Liquidity pool default gas fee :: ', LPDefaultGasFee)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#add-sol-token-into-liquidity-pool","title":"Add SOL token into liquidity pool","text":"
  • Add SOL tokens into liquidity pool
  • Get Solana Inbound address from hermes chain
const addSOLToLiquidityPool = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await solClient.getSolanaInboundAddress()\n  try {\n    const liquidityPoolHash = await solClient.addLiquidityPool(\n      amountToTransfer,\n      inboundAddress,\n      dojAddress,           // optional dojima address\n    )\n    console.log('Liquidity pool hash : ', liquidityPoolHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#swap-sol-tokens","title":"Swap SOL tokens","text":"
  • Swap SOL tokens to required token using receiver address
  • Get Solana Inbound address from hermes chain
  • Supported tokens for swapping - \u2018DOT\u2019, \u2018DOJ\u2019, \u2018ETH\u2019, \u2018AR\u2019
import {SwapAssetList} from '@d11k-ts/utils'\nconst swapSOL = async () => {\n  let amountToTransfer = 0.001\n  const inboundAddress = await solClient.getSolanaInboundAddress()\n  try {\n    const swapHash = await solClient.swap(\n      amountToTransfer,\n      SwapAssetList,\n      inboundAddress,\n      reciepient                // Respective receiver SwapAssetList token address\n    )\n    console.log('Swap tx hash : ', swapHash)\n  } catch (error) {\n    console.log(`Caught ${error}`)\n  }\n}\n
"},{"location":"core/d11kguide/solana/#example-code","title":"Example Code","text":"

For sample code check out example test case in Solana

"},{"location":"core/d11kguide/utils/","title":"@d11k-ts/utils","text":"

Utility helpers for D11k clients

"},{"location":"core/d11kguide/utils/#modules-in-alphabetical-order","title":"Modules (in alphabetical order)","text":"
  • asset - Utilities for handling assets
  • async - Utilities for async handling
  • bn - Utilities for using bignumber.js
  • chain - Utilities for multi-chain
  • string - Utilities for strings
"},{"location":"core/d11kguide/utils/#installation","title":"Installation","text":"

yarn add @d11k-ts/utils\n
The following peer dependencies have to be installed into your project. These are not included in @d11k-ts/utils.

yarn add bignumber.js\n
"},{"location":"core/sources/endpoints/","title":"Network Endpoints","text":""},{"location":"core/sources/endpoints/#testnet","title":"Testnet","text":"Field Testnet Network Name Hermes Dojima Http Api URL https://api-dev.h4s.dojima.network/ New RPC URL https://rpc-dev.h4s.dojima.network/ Chain ID hermes-testnet Currency symbol DOJ"},{"location":"core/sources/endpoints/#stagenet","title":"Stagenet","text":"Field Testnet Network Name Hermes Dojima Http Api URL https://api.h4s.dojima.network/ New RPC URL https://rpc.h4s.dojima.network/ Chain ID hermeschain-stagenet Currency symbol DOJ"},{"location":"core/sources/faucet/","title":"Faucet","text":"

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

"},{"location":"core/sources/faucet/#prerequisites","title":"Prerequisites","text":"

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don\u2019t have a seed phrase, follow these steps.

To request tokens using the faucet.

"},{"location":"core/sources/faucet/#1-before-requesting-testnet-tokens-check-the-table-for-available-faucet-balances","title":"1. Before requesting TestNet tokens check the table for available faucet balances.","text":""},{"location":"core/sources/faucet/#2-select-the-hermes-token-and-copy-the-address","title":"2. \u00a0Select the Hermes token and copy the address.","text":""},{"location":"core/sources/faucet/#3-choose-a-chain-for-token-requests","title":"3. Choose a chain for token requests.","text":""},{"location":"core/sources/faucet/#4-paste-address-in-the-address-input-or-use-self-address-checkbox","title":"4. Paste address in the address input or use self address checkbox.","text":""},{"location":"core/sources/faucet/#5-click-the-submit-button-following-submission-a-popup-will-appear-indicating-whether-the-transaction-was-successful-or-unsuccessful-to-close-the-popup-press-anywhere","title":"5. Click the \u201csubmit\u201d button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.","text":""},{"location":"core/sources/faucet/#6-if-the-pop-up-indicates-a-successful-transaction-you-can-check-your-test-token-balance-on-your-dojima-wallet-dashboard","title":"6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.","text":""},{"location":"core/sources/faucet/#stagenet","title":"Stagenet","text":"

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

"},{"location":"core/sources/transaction/","title":"Transactions","text":""},{"location":"core/sources/transaction/#guide-to-sending-a-dojima-coin-to-any-account","title":"Guide to sending a Dojima coin to any account","text":""},{"location":"core/sources/transaction/#1-first-log-into-your-dojima-wallet-if-you-dont-have-a-seed-phrase-follow-these-steps","title":"1. First, log into your Dojima Wallet. If you don\u2019t have a seed phrase, follow these steps.","text":"

Info

If you don\u2019t have Hermes Tokens, proceed to FAUCET to get testnet tokens.

"},{"location":"core/sources/transaction/#2-click-on-send-and-receive-option","title":"2. Click on Send and Receive option.","text":""},{"location":"core/sources/transaction/#3-to-send-digital-assets-just-click-on-the-send-option-beside-your-chosen-token","title":"3. To send digital assets, just click on the \u201cSEND\u201d option beside your chosen token.","text":""},{"location":"core/sources/transaction/#4-specify-the-amount-of-the-token-you-want-to-transfer","title":"4. Specify the amount of the token you want to transfer..","text":""},{"location":"core/sources/transaction/#5-to-input-an-amount-in-usd-users-should-toggle-the-input-usd-option-on-and-then-enter-the-desired-amount-in-usd","title":"5. To input an amount in USD, users should toggle the \u201cInput USD\u201d option on and then enter the desired amount in USD..","text":""},{"location":"core/sources/transaction/#6-to-proceed-with-the-sending-process-users-must-input-the-recipients-public-address","title":"6. To proceed with the sending process, users must input the recipient\u2019s public address..","text":""},{"location":"core/sources/transaction/#7select-the-gas-fee-users-have-the-option-to-choose-between-fast-average-and-slow-gas-fees-and-click-on-continue","title":"7.Select the gas fee, users have the option to choose between fast, average, and slow gas fees and click on Continue.","text":""},{"location":"core/sources/transaction/#8-the-next-step-is-the-review-page-where-users-can-carefully-examine-all-transaction-details-including-the-amount-they-are-sending-the-chosen-gas-fee-and-the-total-amount-they-are-paying-if-they-wish-to-make-any-changes-they-can-click-on-the-edit-option-otherwise-they-should-proceed-by-clicking-on-the-send-option-to-complete-the-transaction","title":"8. The next step is the review page, where users can carefully examine all transaction details, including the amount they are sending, the chosen gas fee, and the total amount they are paying. If they wish to make any changes, they can click on the \u201cEDIT\u201d option. Otherwise, they should proceed by clicking on the \u201cSEND\u201d option to complete the transaction.","text":""},{"location":"core/sources/transaction/#8-thats-it-the-transaction-is-complete-for-more-details-on-the-transaction-users-can-click-on-the-view-on-explorer-option","title":"8. That\u2019s it! The transaction is complete. For more details on the transaction, users can click on the \u201cView on Explorer\u201d option.","text":""},{"location":"developer/","title":"Developer","text":"Developers

Your resource hub for seamless onboarding and support within our evolving ecosystem.

Templates

Explore our library of ready-made templates, offering instant integration of common use cases or smart contracts, streamlining your blockchain development process.

Faucet

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

"},{"location":"developer/faucet/","title":"Faucet","text":"

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

"},{"location":"developer/faucet/#prerequisites","title":"Prerequisites","text":"

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don\u2019t have a seed phrase, follow these steps.

To request tokens using the faucet.

"},{"location":"developer/faucet/#1-before-requesting-testnet-tokens-check-the-table-for-available-faucet-balances","title":"1. Before requesting TestNet tokens check the table for available faucet balances.","text":""},{"location":"developer/faucet/#2-select-the-hermes-token-and-copy-the-address","title":"2. \u00a0Select the Hermes token and copy the address.","text":""},{"location":"developer/faucet/#3-choose-a-chain-for-token-requests","title":"3. Choose a chain for token requests.","text":""},{"location":"developer/faucet/#4-paste-address-in-the-address-input-or-use-self-address-checkbox","title":"4. Paste address in the address input or use self address checkbox.","text":""},{"location":"developer/faucet/#5-click-the-submit-button-following-submission-a-popup-will-appear-indicating-whether-the-transaction-was-successful-or-unsuccessful-to-close-the-popup-press-anywhere","title":"5. Click the \u201csubmit\u201d button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.","text":""},{"location":"developer/faucet/#6-if-the-pop-up-indicates-a-successful-transaction-you-can-check-your-test-token-balance-on-your-dojima-wallet-dashboard","title":"6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.","text":""},{"location":"developer/faucet/#stagenet","title":"Stagenet","text":"

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

"},{"location":"developer/quickstart/","title":"Introduction to Dojima PoS","text":"

Warning

UPDATING THE DEVELOP DOCS

The docs are being updated, enhanced, and improved. They are subject to change. Please feel free to raise an issue or pull request if you have any queries or suggestions.

Welcome to Dojima The most innovative and exciting platform to develop your blockchain application. Blockchain technology is poised to revolutionize how the digital world manages data and conducts business. You can join this revolution by getting a head start on Dojima\u2019s decentralized application (dApp) development.

This guide will introduce you to the Dojima ecosystem. You\u2019ll find links to valuable resources and websites that will bring you up to speed on building, not only on Dojima but also on general blockchain application development.

Tip

STAY IN THE KNOW

Keep up with the latest builder updates from the Dojima team and the community by subscribing to the .

"},{"location":"developer/quickstart/#building-on-dojima","title":"Building on Dojima","text":"

If you are an Ethereum developer, you are already a Dojima developer. Simply switch to the Dojima RPC and get started. All the tools you are familiar with on the Ethereum blockchain are supported on Dojima by default, such as Truffle, Remix, and Web3js.

You can deploy decentralized applications to either Dojima Testnet or the Mainnet. The Dojima Testnet connects with the Ethereum Go\u00ebrli Testnet, which acts as its ParentChain. You can find all the network-related details in the [network documentation].

"},{"location":"developer/quickstart/#wallets","title":"Wallets","text":"

To interact with the Dojima Network, you need to have an Ethereum-based wallet because Dojima runs on Ethereum Virtual Machine (EVM). You can choose to set up a Metamask or Arkane Wallet. More on wallet-related information and why you need one can be found in our wallet documentation.

"},{"location":"developer/quickstart/#smart-contracts","title":"Smart Contracts","text":"

Dojima supports many services you can use to test, compile, debug, and deploy decentralized applications onto the Dojima Network. These include deployment using Alchemy, Chainstack, QuickNode, Remix, Truffle, Hardhat, and Replit.

"},{"location":"developer/quickstart/#building-a-new-dapp-on-dojima","title":"Building a new dApp on Dojima?","text":"

Decentralized applications (dApps) act as the bridge between users and their data privacy on the blockchain. The increasing number of dApps validates their usefulness within the blockchain ecosystem, solving challenges like executing transactions between two participants without the need for central authority via smart contracts.

Suppose you have no prior experience building decentralized applications (dApps). In that case, the below-mentioned resources will give you a head start on the tools required to build, debug, and deploy dApps on the Dojima Network.

Full Stack dApp: Tutorial Series - Web3.js - Ethers.js - Remix - Truffle - Metamask - Arkane - Develop a dApp using Fauna, Dojima and React

"},{"location":"developer/quickstart/#already-have-a-dapp","title":"Already have a dApp?","text":"

If you already have a decentralized application (dApp) and are looking for a platform to help you scale efficiently, then you are at the right place because Dojima allows you to:

  1. Easily migrate from Ethereum Virtual Machine (EVM) based chain: Dojima prides itself in being the ultimate Layer-2 scaling solution for Ethereum. You don\u2019t have to worry about the underlying architecture while moving or deploying your dApps to the Dojima Network as long as it is EVM-compatible

  2. Use Dojima as a faster transaction layer: Deploying your dApp to the Dojima Mainnet allows you to leverage Dojima as a faster transaction layer for your dApp. Additionally, you can get your tokens mapped by us. You can join our technical discussions group on Telegram to learn more.

"},{"location":"developer/quickstart/#side-note","title":"Side Note","text":"

If this is overwhelming, that\u2019s alright! You can jump right into the action and start hacking. Here are some notes before you start diving into resources, repositories, and docs:

  1. Beware the cost of being on the bleeding edge: Like typical niche programming, dApps and blockchain development moves very quickly. While researching, you may find complex code repositories, 404s on a documentation site, or even no documentation. Use that opportunity to reach out to us via any social media channel.

  2. The learning curve may be daunting, but the barrier to entry is low: The community is very open and welcoming! Projects welcome pull requests from outsiders and resolve any blockers actively. We\u2019re working on creating a better world and contribution in any form is appreciated. We\u2019ll be grateful to onboard you into this amazing Web3 ecosystem.

Info

STAY UPDATED

Decentralized application development encourages network decentralization. Follow our social media handles for more insights and updates about the Dojima ecosystem. You can find the links to all the Dojima communities here.

"},{"location":"developer/transactions/","title":"Transactions","text":""},{"location":"developer/transactions/#heres-the-guide-to-sending-a-dojima-coin-to-any-account","title":"Here\u2019s the guide to sending a Dojima coin to any account","text":""},{"location":"developer/transactions/#1-first-log-into-your-dojima-wallet-account-if-you-dont-have-a-seed-phrase-follow-these-steps","title":"1. First, log into your Dojima Wallet account. If you don\u2019t have a seed phrase, follow these steps.","text":"

Info

If you don\u2019t have Doj Tokens, proceed to FAUCET to get testnet tokens.

"},{"location":"developer/transactions/#2-select-dojima-coin-and-select-send","title":"2. Select Dojima coin and select \u2018Send\u2019.","text":""},{"location":"developer/transactions/#3-enter-the-receivers-dojima-public-address","title":"3. Enter the receiver\u2019s Dojima Public Address.","text":""},{"location":"developer/transactions/#4-enter-the-amount-to-send","title":"4. Enter the amount to send.","text":""},{"location":"developer/transactions/#5-choose-the-network-speed","title":"5. Choose the network speed.","text":""},{"location":"developer/transactions/#7-verify-the-details-like-the-receivers-public-address-the-transfer-amount-and-the-network-speed","title":"7. Verify the details, like the receiver\u2019s public address, the transfer amount, and the network speed","text":""},{"location":"developer/transactions/#8-transaction-completed-anf-details-get-displayed","title":"8. Transaction completed anf details get displayed","text":""},{"location":"developer/verifying-smart-contract/","title":"Verifying A Smart Contract","text":"

Once verified, a smart contract or token contract\u2019s source code becomes publicly available and verifiable. This creates transparency and trust. Plus, it\u2019s easy to do! Verification is available for Solidity.

"},{"location":"developer/verifying-smart-contract/#smart-contract-verification-with-blockscout","title":"Smart Contract Verification with Blockscout","text":"

1) You will be given an address to check a pending transaction after the contract is created. If it doesn\u2019t take you to https://doj-bex-test.dojima.network/, go to Dojima Chain block explorer, make sure you\u2019re on the chain where the contract was set up, then type the address of the contract into the search field. Your contract details should come up.

2) To view the bytecode, select the Code tab and press the Verify and Publish button. Several options for verification will be available to you. Please select the \u201cvia flattened source code\u201d (solidity) option.

"},{"location":"developer/verifying-smart-contract/#via-flattened-source-code","title":"Via Flattened Source Code","text":"
  1. Contract Address: The 0x address entered when the contract was created
  2. Contract Name: The name of the class that was mentioned in the.sol files. In the contract MyContract {.. MyContract , for example, the contract\u2019s name is MyContract.
  3. Include Nightly Builds: If you wish to display nightly builds, then yes.
  4. Compiler: Taken from the first line of the X.X.X. contract's pragma solidity. Use the appropriate compiler instead of the nightly build.
  5. EVM Version: See EVM version details.
  6. Optimization: Check yes if you made optimization available during compilation.
  7. Optimization Runs: The default value for the Solidity Compiler is 200. change only if you modified this value during compilation.
  8. Enter the Solidity Contract Code: If your solidity code uses a library or inherits dependencies from another contract, you might need to flatten it. The POA solidity flattener or the truffle flattener are our recommendations.
  9. Try to fetch constructor arguments automatically: Similar contracts might be offered if they exist.
  10. ABI-encoded Constructor Arguments: See this page for more info.
  11. Add Contract Libraries: For any necessary libraries that must be called in the .sol file, enter their name and 0x address. Choose \"Verify and Publish\" from the menu. If everything is going well, you should notice a tick next to Code in the code tab and a new tab labelled \"Read Contract.\"Any transactions related to your contract will now be listed in BlockScout with the contract name.
"},{"location":"developer/Wallet/getstarted/","title":"Wallet","text":"

Tip

STAY IN THE KNOW

Keep up with the latest Wallet Suite updates from the Dojima team and community by subscribing to our Notifications.

Wallets that support Dojima allow for key management, access to accounts controlled by private keys, and interfaces that allow users to perform chain actions and sign transactions. The following page serves as a wallet index for wallets compatible with Dojima. Please note that this is not an exhaustive index.

Warning

THIRD-PARTY WALLETS

These third-party wallets have integrated Dojima and support a variety of features. You should do your own due diligence before using them. The official Dojima Support cannot provide assistance for issues with these wallets or other non-native wallets

Info

CENTRALIZED EXCHANGES (CEXS)

For a list of CEXs that support Dojima, visit a third-party tracking website such as CoinMarketCap.

"},{"location":"developer/Wallet/getstarted/#native-wallets","title":"Native Wallets","text":"

Dojima Support can provide assistance to users and address issues related to the following wallets:

Wallet Custody Account Type Multi-Sig NFT dApp Browser Bridge Support Fiat On-Ramp Platforms 1inch non-custodial EOA no interface yes yes no mobile Alpha Wallet* non-custodial EOA no interface yes yes yes mobile, api/sdk Atomic Wallet* non-custodial EOA no no no no yes mobile, desktop, api/sdk Ambire non-custodial smart contract no interface no yes yes browser BitKeep non-custodial EOA no interface no yes yes mobile Bitski custodial EOA no interface yes no browser, api/sdk Coin98 non-custodial EOA no interface yes yes yes mobile, browser, api/sdk Coinbase hybrid EOA no interface yes yes yes mobile, browser, api/sdk CypherD non-custodial EOA no no yes mobile D\u2019Cent* hybrid EOA no interface yes yes no mobile Exodus* non-custodial EOA no no no yes mobile, desktop Gnosis Safe* non-custodial smart contract yes interface yes no no mobile, browser, api/sdk Guarda non-custodial EOA no no no yes yes mobile, browser, desktop Huobi non-custodial EOA no no no yes no mobile Ledger* non-custodial EOA no interface no no no hardware, mobile, desktop Loopring non-custodial smart contract no no no mobile, api/sdk Magic* custodial EOA no no no mobile, browser, api/sdk MathWallet* custodial EOA no no no yes yes mobile, browser, api/sdk MetaMask* non-custodial EOA no interface yes no no mobile, browser, api/sdk Multis* non-custodial EOA no no no mobile, desktop MyEtherWallet* non-custodial EOA no interface no mobile Opera Crypto Browser* non-custodial EOA no support yes mobile, browser Pillar non-custodial EOA no interface no mobile Rainbow non-custodial EOA no interface yes mobile, api/sdk SafePal* non-custodial EOA no no yes hardware, mobile, api/sdk Sequence non-custodial smart contract no interface no browser, api/sdk SimpleHold non-custodial EOA no no no mobile, api/sdk SteakWallet non-custodial EOA no interface no mobile, api/sdk TokenPocket non-custodial EOA no support yes yes no mobile, browser, api/sdk Torus non-custodial EOA no support no no no browser, api/sdk Trezor* non-custodial EOA no support no hardware, mobile Trust Wallet* non-custodial EOA no support yes mobile Unstoppable non-custodial EOA no no yes mobile, api/sdk Venly hybrid smart contract no interface no browser, api/sdk Wirex* non-custodial EOA no no no mobile XDeFi non-custodial EOA no interface no no no browser Zerion non-custodial EOA no no yes mobile, browser

Warning

NON-NATIVE WALLET SUPPORT

Wallets denoted with * in the table above are not natively supported with the wallet software and require manual steps to add the Dojima network.

"},{"location":"developer/Wallet/getstarted/#key-management-strategy","title":"Key Management Strategy","text":"

The following basic steps allow for the integration of a client-side application with Dojima:

  1. Set up Web3: web3.js is a javascript library that allows a client-side application to talk to the blockchain. We configure web3 to communicate via a developer-based wallet like MetaMask. Use the web3.js docs to learn about adding web3.js to your project.
  2. Set up an Account: You will be able to send transactions (specifically ones that alter the state of the blockchain).
  3. Instantiate Contracts: Once a web3 object in place, we next instantiate our deployed contract, with which we interact.
  4. Call functions: Fetch data via functions in the contract - through our contract object.
"},{"location":"developer/Wallet/MetaMask/config-dojima-on-metamask/","title":"Add Dojima Network","text":"

In order to view the flow of funds in your accounts, on the Dojima Network, you will need to configure Dojima {testnet, mainnet} URL on Metamask.

There are two ways to do it:

  1. Using Dojimascan
  2. Add the Dojima network manually
"},{"location":"developer/Wallet/MetaMask/config-dojima-on-metamask/#using-dojimascan","title":"Using Dojimascan","text":"

Note

Please make sure you have already installed Metamask!

Dojima-Testnet

Please follow the steps to add Dojima\u2019s Testnet:

  • Navigate to https://doj-bex-test.dojima.network/

  • Scroll down to the bottom of the page and click on the button Add Dojima Network

  • Once you click the button you will see a Metamask Notification, now click on Approve. You will be directly switched to Dojima\u2019s Testnet now in the network dropdown list. You can now close the dialog.

If you are facing any issue, Add the Network Manually(steps given below)

"},{"location":"developer/Wallet/MetaMask/config-dojima-on-metamask/#add-the-dojima-network-manually","title":"Add the Dojima network manually","text":"Dojima-Testnet
  1. To add the Dojima Testnet to your Metamask extension for testing and development purposes, begin by launching the extension.
  2. Click on the three dots icon to access additional options, then select \u201cSettings\u201d to proceed with configuring the Metamask extension.
  3. Navigate to the \u201cNetworks\u201d section and select \u201cAdd Network\u201d to begin configuring a new network for integration with the Metamask extension.
  4. Choose the \u201cAdd Network Manually\u201d option to manually input the details of the Dojima Testnet network into the Metamask extension.
  5. Enter Dojima Chain as the network name in the corresponding field to accurately identify the network within the Metamask extension settings.
  6. Input the new RPC URL https://api-dev.d11k.dojima.network/ into the designated field to establish the connection with the Dojima Chain network.
  7. Set the Chain ID to 1001 in the provided field to uniquely identify the Dojima Chain network within the Metamask extension.
  8. Specify the Currency Symbol as DOJ to represent the native currency of the Dojima Chain network within the Metamask extension settings
  9. Congratulations! You have successfully added the Dojima Testnet to your Metamask extension. You can now begin testing and developing on the Dojima Chain network with ease.
"},{"location":"developer/Wallet/MetaMask/custom-tokens/","title":"Config Custom Tokens","text":"

This page demonstrates the process of configuring/adding custom tokens to Metamask. Specifically, we have demonstrated adding the example TEST ERC20 and ERC721 tokens to the G\u00f6rli testnet as well as the Dojima testnet,

You can use this process to add any custom ERC20 tokens to any network on Metamask.

Adding the TEST token (ERC20) to your Metamask account on the G\u00f6rli Network

To display TEST tokens on your account on the G\u00f6rli Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

The TEST token contract address on G\u00f6rli is 0x3f152B63Ec5CA5831061B2DccFb29a874C317502. Note that the TEST token is an example ERC20 token contract that is used throughout Dojima developer docs for illustration purposes.

The other fields will auto-populate. Click on Save and then click on Add Tokens. The TEST token should now be displayed on your account on Metamask.

Configuring DOJ TST tokens to Metamask

You will also need to configure the TST tokens to Dojima\u2019s Testnet for visualization if you are following the introductory D11.js tutorial. *Switch the network on Metamask to point to the Dojima testnet - https://api-dev.d11k.dojima.network/ *. On Metamask, this will be shown as Private Network or whatever you have named it when adding the custom rpc

The corresponding TST token address on Dojima testnet is 0x2d7882beDcbfDDce29Ba99965dd3cdF7fcB10A1e. Note that this token contract address is different from that of Goerli - since this is the TST token on the Dojima Network. A detailed, screen-by-screen guide to add custom tokens is shown here:

You can open Metamask and then click on the option for Add Token.

You will see a screen to either search from a list of already available tokens or add a custom token. Click on Custom Token.

You will see a field to add the Token Address. Paste the token address in the form, and configure the token name as TST.

You can then click on Next.

And then click on Add Tokens. You will be navigated back to the home screen and the new token will be displayed in the token list.

Adding the ERC721-TESTV4 token (ERC721) to your Metamask account on the G\u00f6rli Network

To display ERC721-TESTV4 tokens on your account on the G\u00f6rli Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

The ERC721-TESTV4 token contract address on G\u00f6rli is 0xfA08B72137eF907dEB3F202a60EfBc610D2f224b. Note that the ERC721-TESTV4 token is an example ERC721 token contract.

The token symbol is ERC721-Testv4 and token of precision is 18. Click on Add Tokens. The ERC721-TESTV4 token should now be displayed on your account on Metamask.

Adding the ERC721-TESTV4 token (ERC721) to your Metamask account on the Dojima Testnet Network

*Switch the network on Metamask to point to the Dojima testnet - https://api-dev.d11k.dojima.network/ *. On Metamask, this will be shown as Private Network or whatever you have named it when adding the custom rpc .

To display ERC721-TESTV4 tokens on your account on the Dojima Testnet Network, you can click on the Add Tokens option in Metamask. It will then navigate you to a screen. You then click on Custom Token tab and copy-paste the address below in the Token Address field.

The ERC721-TESTV4 token contract address on Dojima Testnet is 0x33FC58F12A56280503b04AC7911D1EceEBcE179c. Note that the ERC721-TESTV4 token is an example ERC721 token contract.

The token symbol is ERC721-Testv4 and token of precision is 18. Click on Add Tokens. The ERC721-TESTV4 token should now be displayed on your account on Metamask.

Adding a test ERC1155 token to your Metamask account

While the Dojima network supports ERC1155, Metamask does not yet support the standard. This update is expected in the fourth quarter of 2021.

"},{"location":"developer/Wallet/MetaMask/multiple-accounts/","title":"Create & Import Accounts","text":"

In case you are new to Ethereum and Metamask, here is a guide on how to create multiple accounts and import them:

"},{"location":"developer/Wallet/MetaMask/multiple-accounts/#create-account","title":"Create Account","text":"

To create multiple accounts, you click on Profile icon on Metamask and then click on Create Account

You can then add an account name and click on Create.

You can create more accounts this way. When you create multiple accounts, your addresses will be different at your end.

"},{"location":"developer/Wallet/MetaMask/multiple-accounts/#import-account","title":"Import Account","text":"
  • Open your wallet browser extension from your browser
  • Select Settings > Import Account
  • Copy the Private key(You can find this in the Account Details) from your local account, paste it into the window provided, and select Import
"},{"location":"developer/Wallet/MetaMask/overview/","title":"Overview of MetaMask","text":"

MetaMask is a crypto wallet that can be used in a web browser and on mobile devices to interact with the Ethereum blockchain. It allows you to run Ethereum Dapps (Decentralized Apps) right in your browser without running a full Ethereum node.

Type: Non-custodial/HD Private Key Storage: User\u2019s local browser storage Communication to Ethereum Ledger: Infura Private key encoding: Mnemonic

Danger

Please Backup your Secret Recovery Phrase, if your device breaks, is lost, stolen, or has data corruption, there is no other way to recover it. The Secret Recovery Phrase is the only way to recover your MetaMask accounts. Check more Basic Safety and Security Tips for MetaMask!

"},{"location":"developer/Wallet/MetaMask/overview/#guide-to-setup-metamask-for-dojima","title":"Guide to Setup Metamask for Dojima","text":"
  • Download & Install MetaMask
  • Configure Dojima on MetaMask
  • Config Custom Tokens
  • Create & Import Accounts

Get Test Tokens - Dojima Faucet

"},{"location":"developer/Wallet/MetaMask/overview/#1-set-up-web3","title":"1. Set up Web3","text":"

Step 1 Install the following in your DApp:

npm install --save web3\n

Create a new file, name it web3.js and insert the following code in it:

import Web3 from 'web3';\n\nconst getWeb3 = () => new Promise((resolve) => {\n  window.addEventListener('load', () => {\n    let currentWeb3;\n\n    if (window.ethereum) {\n      currentWeb3 = new Web3(window.ethereum);\n      try {\n        // Request account access if needed\n        window.ethereum.enable();\n        // Acccounts now exposed\n        resolve(currentWeb3);\n      } catch (error) {\n        // User denied account access...\n        alert('Please allow access for the app to work');\n      }\n    } else if (window.web3) {\n      window.web3 = new Web3(web3.currentProvider);\n      // Acccounts always exposed\n      resolve(currentWeb3);\n    } else {\n      console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');\n    }\n  });\n});\n\n\nexport default getWeb3;\n

The above file exports a function called getWeb3() - the purpose of which is to request metamask account\u2019s access via detecting a global object (ethereum or web3) injected by Metamask.

According to Metamask\u2019s API documentation:

MetaMask injects a global API into websites visited by its users at window.ethereum (Also available at window.web3.currentProvider for legacy reasons). This API allows websites to request user login, load data from blockchains the user has a connection to, and suggest the user sign messages and transactions. You can use this API to detect the user of a web3 browser.

In simpler terms, it basically means, having Metamask\u2019s extension/add-on installed in your browser, you\u2019d have a global variable defined, called ethereum (web3 for older versions) - using this variable we instantiate our web3 object.

Step 2

Now, in your client code, import the above file,

  import getWeb3 from '/path/to/web3';\n
and call the function:
  getWeb3()\n    .then((result) => {\n      this.web3 = result;// we instantiate our contract next\n    });\n

"},{"location":"developer/Wallet/MetaMask/overview/#2-set-up-account","title":"2. Set up account","text":"

Now to send transactions (specifically those that alter the state of the blockchain) we\u2019ll need an account to sign those transactions from We instantiate our contract instance from the web3 object we created above:

  this.web3.eth.getAccounts()\n  .then((accounts) => {\n    this.account = accounts[0];\n  })\n
The getAccounts() function returns an array of all the accounts on user\u2019s metamask, and accounts[0] is the one currently selected by the user.

"},{"location":"developer/Wallet/MetaMask/overview/#3-instantiate-your-contracts","title":"3. Instantiate your contracts","text":"

Once we have our web3 object in place, we\u2019ll next instantiate our contracts > Assuming you have your contract ABI and address already in place :)

  const myContractInstance = new this.web3.eth.Contract(myContractAbi, myContractAddress)\n

"},{"location":"developer/Wallet/MetaMask/overview/#4-call-functions","title":"4. Call functions","text":"

Now for any function you\u2019d want to call from your contract, we directly interact with our instantiated contract object (which is myContractInstance declared in Step 2)

A quick review: - Functions that alter the state of the contract are called send() functions - Functions that do not alter the state of the contract are called call() functions

Calling call() Functions

  this.myContractInstance.methods.myMethod(myParams)\n  .call()\n  .then (\n    // do stuff with returned values\n  )\n
Calling send() Functions
  this.myContractInstance.methods.myMethod(myParams)\n  .send({\n    from: this.account,gasPrice: 0\n  })\n  .then (\n    (receipt) => {\n      // returns a transaction receipt}\n    )\n

"},{"location":"developer/Wallet/MetaMask/tutorial-metamask/","title":"How to create a MetaMask Wallet?","text":"

If you are wondering how to create a new cryptocurrency wallet, consider creating one by installing the MetaMask extension.

MetaMask is a free and secure browser extension that allows web applications to read and interact with the Ethereum blockchain.

"},{"location":"developer/Wallet/MetaMask/tutorial-metamask/#step-1-install-metamask-on-your-browser","title":"Step 1. Install MetaMask on your browser","text":"

To create a new wallet with MetaMask you need to install the extension first. You can install Metamask for\u00a0Chrome,\u00a0Firefox, Brave and\u00a0Opera\u00a0browsers.

  1. Open\u00a0https://metamask.io\u00a0or search for \u201cMetamask extension\u201d using your favorite search engine.

In this tutorial we will be using Google Chrome as an example, but the workflow is the same for all browsers.

  1. Click\u00a0Chrome\u00a0to install MetaMask as a Google Chrome extension.

  2. Click\u00a0Add to Chrome.

  3. Click\u00a0Add Extension.

That\u2019s it! You have successfully installed MetaMask extension!

"},{"location":"developer/Wallet/MetaMask/tutorial-metamask/#step-2-create-an-account","title":"Step 2. Create an account","text":"

The next step is to create an account.

  1. Click on the MetaMask icon in the upper right corner to open the extension.
  2. To install the latest version of MetaMask, click\u00a0Try it now.
  3. Click\u00a0Continue.

  1. You will be asked to create a new password. Create a strong password and click\u00a0Create.

Don\u2019t forget to store your password for safekeeping!

  1. Proceed by clicking\u00a0Next, then accept Terms of Use.

  2. Click\u00a0Reveal secret words.

  3. You will see a 12 words seed phrase. Save seed words as a file or copy them to a safe place and click\u00a0Next.

Reveal secret words and copy your secret backup phrase to a safe place

Security tips:Write this phrase on a piece of paper and store in a secure location. If you want even more security, write it down on multiple pieces of paper and store each in 2\u20133 different locations.Memorize this phrase.

  1. Verify your secret phrase by selecting the previously generated phrase. When done, click\u00a0Confirm.

By \u201csolving this puzzle\u201d you are confirming that you know your secret phrase

Congratulations!\u00a0You have successfully created your MetaMask account. A new Ethereum wallet address was automatically generated for you!

"},{"location":"developer/developer-dashboard/contract/","title":"Contract","text":"

To deploy a smart contract using Dojima without any complications, you can follow these simplified steps designed for a seamless experience.By simplifying the process into a single-tap deployment, Dojima aims to enhance the user experience for deploying smart contracts on the supported chain (Ex. Dojima, Ethereum \u2026). The platform streamlines the necessary inputs, providing a user-friendly environment for both beginners and experienced developers.

"},{"location":"developer/developer-dashboard/contract/#step1-enter-required-inputs-for-contract-deployment","title":"Step1: Enter required inputs for contract deployment","text":"

Dojima introduces a unique feature that allows users to enter required inputs for contract deployment.By combining a user-friendly interface with dynamic code auto-generation, Dojima bridges the gap between beginners and experienced developers, making smart contract deployment accessible to a wider audience.

"},{"location":"developer/developer-dashboard/contract/#step2-click-on-deploy-button-to-proceed-to-next-step","title":"Step2: Click on Deploy button to proceed to next step","text":""},{"location":"developer/developer-dashboard/contract/#step3-review-and-deploy","title":"Step3: Review and Deploy","text":"

Certainly! Let\u2019s enhance the explanation for the last step where developers review the smart contract details, add arguments if needed, and initiate the deployment. And it takes a moment to complete the deployment process for the selected chain.

"},{"location":"developer/developer-dashboard/login/","title":"Login","text":""},{"location":"developer/developer-dashboard/login/#single-sign-on-with-google-account","title":"Single Sign-On with Google Account:","text":"

Seamlessly access to the Dojima Developer Dashboard by logging in with your Google account. Enjoy a secure and hassle-free authentication process, eliminating the need for multiple usernames and passwords.

"},{"location":"developer/developer-dashboard/projects/","title":"Projects List","text":"

Navigating through your projects has never been more straightforward. We\u2019ve organized your projects in a clear and concise table format, providing you with an instant overview and easy access to vital project details.

"},{"location":"developer/developer-dashboard/xchain_connections/","title":"XChain Connections","text":"

Dojima has made user-friendly process to deploy single-tap deployment of contracts for selected chains in xchain-connections.

"},{"location":"developer/developer-dashboard/xchain_connections/#step1-seclect-chain-layer","title":"Step1: Seclect Chain Layer","text":"

Select the chain layer and you can get the actions popup on the top-left of the screen.

"},{"location":"developer/developer-dashboard/xchain_connections/#step2-select-types-of-chain","title":"Step2: Select types of chain","text":"

Select the type from provided contract types and enter Contract Name and Contract Symbol. Additional details can be added such as Features, Access Control, Upgradeability and License. We generate the automated code for you.

"},{"location":"developer/developer-dashboard/xchain_connections/#step3-click-on-save-button","title":"Step3: Click on Save button","text":"

After entering the details and click on Save button. And Deploy button is activated on the bottom-right of the screen.

"},{"location":"developer/developer-dashboard/xchain_connections/#step4-click-on-deploy-button","title":"Step4: Click on Deploy button","text":"

After clicking on deploy button. Deploy popup is displayed to enter additional details for each chain one by one.

"},{"location":"developer/developer-dashboard/dashboard/new_project/","title":"Create New Project","text":""},{"location":"developer/developer-dashboard/dashboard/new_project/#create-new-project","title":"Create new project:","text":"

Welcome to the Template-Driven Project Creation Platform! To begin a new project, navigate to the \u201cCreate New Project\u201d section, where you\u2019ll find a straightforward process to kickstart your endeavor. Follow these steps to initiate your project:

"},{"location":"developer/developer-dashboard/dashboard/new_project/#enter-project-details","title":"Enter project details:","text":"

Enter project details such as Project Name, Project Type and Description of project. Before entering the next section user must enter Project Name and Project Type as they are mandatory fields.

"},{"location":"developer/developer-dashboard/dashboard/new_project/#select-chain","title":"Select Chain","text":"

It\u2019s time to take the next step in your project creation. Select one chain from the options provided but Dojima is auto selected as it is a mandatory chain. After next button is clicked the developer is navigated to xchain-connection section.

"},{"location":"developer/developer-dashboard/dashboard/templates/","title":"Templates","text":""},{"location":"developer/developer-dashboard/dashboard/templates/#select-from-templates","title":"Select from Templates","text":"

Navigate to the \u201cSelect from Templates\u201d section to explore our range of existing templates. Each template is designed to address distinct project types, offering you a head start in achieving your project creation.

"},{"location":"developer/sources/basic/","title":"Basics of Web3 Development","text":"
  • What is Ethereum?
  • Mastering Ethereum
  • Full-Stack dApp Tutorial Series
  • Web3 Developer Stack
  • How to Create a Token (ERC20)?
  • Integrating IPFS with Ethereum
  • Hello World Smart Contract
  • How to Create an NFT
  • Lens Protocol | How to Create a Decentralized Twitter
  • Truffle Tutorial
  • Dapp University
"},{"location":"developer/sources/basic/#learn-more-about-blockchain","title":"Learn More about Blockchain","text":"
  • Integrating Webhooks
  • [Archive Nodes with Debug namespace]
"},{"location":"developer/sources/endpoints/","title":"Network Endpoints","text":""},{"location":"developer/sources/endpoints/#testnet","title":"Testnet","text":"Field Testnet Network Name Dojima chain RPC URL https://api-dev.d11k.dojima.network/ WS URL https://rpc-dev.d11k.dojima.network/ Chain ID 1001 Currency symbol DOJ Block Explorer URL https://explorer-dev.dojima.network/"},{"location":"developer/sources/endpoints/#stagenet","title":"Stagenet","text":"Field Stagenet Network Name Dojima chain RPC URL https://api.d11k.dojima.network/ WS URL https://rpc.d11k.dojima.network/ Chain ID 1401 Currency symbol DOJ Block Explorer URL https://explorer.dojima.network/"},{"location":"developer/sources/external/","title":"External Documentation","text":"
  • ConsenSys Academy Developer Course
  • Infura Docs
  • Truffle Docs
  • Geth Docs
  • Remix Docs
  • OpenZeppelin Docs
"},{"location":"developer/sources/external/#useful-tutorials","title":"Useful Tutorials","text":"
  • Alchemy University
  • CryptoZombies
  • Ethernaut
  • Capture the Ether
  • Road to Web 3
"},{"location":"developer/sources/external/#additional-resources","title":"Additional Resources","text":"
  • Video Tutorials Library
  • Writings by the Team
"},{"location":"developer/sources/faucet/","title":"Faucet","text":"

The Faucet is a web-based service that can send you some test tokens so that you can explore and experiment with testnet without having to pay for anything.

"},{"location":"developer/sources/faucet/#prerequisites","title":"Prerequisites","text":"

Before we begin, you must have the testnet address of the respective chain. To obtain an address, Login or Register into Dojima Wallet. If you don\u2019t have a seed phrase, follow these steps.

To request tokens using the faucet.

"},{"location":"developer/sources/faucet/#1-before-requesting-testnet-tokens-check-the-table-for-available-faucet-balances","title":"1. Before requesting TestNet tokens check the table for available faucet balances.","text":""},{"location":"developer/sources/faucet/#2-select-the-hermes-token-and-copy-the-address","title":"2. \u00a0Select the Hermes token and copy the address.","text":""},{"location":"developer/sources/faucet/#3-choose-a-chain-for-token-requests","title":"3. Choose a chain for token requests.","text":""},{"location":"developer/sources/faucet/#4-paste-address-in-the-address-input-or-use-self-address-checkbox","title":"4. Paste address in the address input or use self address checkbox.","text":""},{"location":"developer/sources/faucet/#5-click-the-submit-button-following-submission-a-popup-will-appear-indicating-whether-the-transaction-was-successful-or-unsuccessful-to-close-the-popup-press-anywhere","title":"5. Click the \u201csubmit\u201d button. Following submission, a popup will appear indicating whether the transaction was successful or unsuccessful. To close the popup, press anywhere.","text":""},{"location":"developer/sources/faucet/#6-if-the-pop-up-indicates-a-successful-transaction-you-can-check-your-test-token-balance-on-your-dojima-wallet-dashboard","title":"6 If the pop-up indicates a successful transaction, you can check your test token balance on your Dojima wallet dashboard.","text":""},{"location":"developer/sources/faucet/#stagenet","title":"Stagenet","text":"

During a specified period, Stagenet tokens are accessible to users, offering a unique opportunity for participation in a limited-time token distribution.

"},{"location":"developer/templates/deposit_manager/","title":"Deposit Manager Template Documentation","text":""},{"location":"developer/templates/deposit_manager/#introduction","title":"Introduction","text":"

The Deposit Manager contract template is a pivotal tool for Dojima Chain developers, designed to facilitate cross-chain functionalities within decentralized applications (DApps). It emphasizes the management of token deposits across different blockchain networks.

"},{"location":"developer/templates/deposit_manager/#key-features","title":"Key Features:","text":"
  • Cross-Chain Token Management: Efficiently tracks ERC20 tokens (or their equivalents) across multiple chains.
  • Deposit Tracking: Employs unique IDs for each token deposit, alongside the token amount and address.
  • State Synchronization with Inbound State Sender: Leverages inbound state sender for communicating from other chains to the Dojima Chain.
  • Multi-Chain Compatibility: While primarily designed for Ethereum, it\u2019s adaptable for additional blockchain integrations.
"},{"location":"developer/templates/deposit_manager/#use-cases","title":"Use Cases","text":"
  • Cross-Chain DApps Development: Optimal for DApps that necessitate token fluidity across blockchain ecosystems.
  • Token Deposit Ledger: Ideal for platforms that require an accurate and detailed record of token deposits.
"},{"location":"developer/templates/deposit_manager/#prerequisites","title":"Prerequisites","text":"
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all the cross-chain data. Read more about the Dojima chain here.
  • Destination Chain: A destination chain will refer to all the chains that are connected to the Dojima chain. The destination chain could be Ethereum, Solana, or any other chain that is connected to the Dojima chain. But it doesn\u2019t represent the origin of transaction. Transaction can originate either from Dojima chain or destination chain (Ethereum, Solana).
  • Hermes Client: The Hermes client is essential for cross-chain communication between Destination and the Dojima Chain and vice versa. Read more about Hermes here.
  • Inbound State Sender: The Inbound State Sender is a key component of the cross-chain data transfer. It will be deployed on all the destination chains and will be responsible for facilitating the reception of encoded state messages from destination chains to the Dojima Chain. Read more about inbound state sender and how to use it here.
  • Root Token: In the context of deposit manager contract, root token refers to any token on the destination chains.
  • Child Token: In the context of deposit manager contract, child token refers to the root-tokens counterpart on the Dojima chain.
  • Child Chain: The child chain refers to the contract that is deployed on the Dojima chain. It manages all the root token counterparts (child tokens) on the Dojima chain.
"},{"location":"developer/templates/deposit_manager/#contract-overview","title":"Contract Overview","text":""},{"location":"developer/templates/deposit_manager/#childchain-contract-dojima-chain","title":"ChildChain Contract (Dojima Chain)","text":"

Child chain contract will be deployed on the Dojima chain. It is responsible for creating and managing child tokens on the Dojima chain. Each Root Token will have a corresponding child token on the Dojima chain. The child token will be used to track the token balance of users on the Dojima chain. The child token will be minted when a user deposits tokens on the Ethereum chain. The child token will be burned when a user withdraws tokens from the Ethereum chain.

"},{"location":"developer/templates/deposit_manager/#key-functionalities","title":"Key Functionalities","text":"
  • addToken: Creates and maps a child token on the Dojima chain for a specific root token for the specified chain.
  • onStateReceive: Executes the state sync process, minting tokens on the Dojima chain based on the incoming state information from the destination chains.
  • withdrawTokens: Manages tokens\u2019 withdrawal requests, facilitating transfers back to the Destination chain.
  • _depositTokens: Credits tokens on the Dojima chain based on the incoming state information.
"},{"location":"developer/templates/deposit_manager/#childerc20-and-childtoken-contracts","title":"ChildERC20 and ChildToken Contracts","text":"
  • Support ERC20 token functionalities on the Dojima chain, including standard and cross-chain transactions.
"},{"location":"developer/templates/deposit_manager/#depositmanager-contract-destination-chains","title":"DepositManager Contract (Destination Chains)","text":"

Deposit manager contract will be deployed on the destination chains (Ethereum, Solana, etc.). It is responsible for managing the deposit of tokens on the destination chains.

"},{"location":"developer/templates/deposit_manager/#constructor","title":"Constructor","text":"
  • Set up the contract with a specific chain name, establishing a cross-chain context.
"},{"location":"developer/templates/deposit_manager/#key-functions","title":"Key Functions","text":"
  • updateChildChainAndStateSender: Modifies the child chain and inbound state sender contract addresses.
  • deposit: Facilitates the deposit of ERC20 tokens by users, accurately recording each transaction. It involves locking tokens in deposit manager and initiate a state sync process to deposit tokens in child chain contract.
    inboundStateSender.transferPayload(\n _childChain,\n abi.encode(_chainName, _user, _token, _amount, _depositId)\n)\n
    The transferPayload function in the depositBlock method has the following parameters:
  • childChain: The target child chain contract address on the dojima chain for the cross-chain transfer.
  • balanceOf: Retrieves the specific token balance for an account.
  • abi.encode(_chainName, _user, _token, _amount, _depositId): This is the payload that is being transferred to the target blockchain. It\u2019s encoded using Ethereum\u2019s ABI (Application Binary Interface) encoding. The payload includes:
    • _chainName: The name of the chain where the tokens will be deposited. This will be same as the chain name passed to the constructor. Basically the name of the chain where the deposit manager contract is deployed. In this case Ethereum.
    • _user: The address of the user who will receive the tokens on the target blockchain
    • _token: The address of the token contract(root token) on the destination blockchain.
    • _amount: The number of tokens to be transferred.
    • _depositId: This is a unique identifier for the deposit operation. The depositId could be used to track or identify individual deposit operations.
"},{"location":"developer/templates/deposit_manager/#events","title":"Events","text":"
  • Deposit: Announced upon a successful token deposit.
  • Withdrawal: Announced during token withdrawal (yet to be implemented).
"},{"location":"developer/templates/deposit_manager/#system-integration","title":"System Integration","text":""},{"location":"developer/templates/deposit_manager/#inboundstatesender","title":"InboundStateSender","text":"
  • Functionality: The InboundStateSender\u2019s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (chain name,user address, token amount, deposit ID) to the Dojima chain.
  • Usage in transferToChain:
  inboundStateSender.transferPayload(\n   _childChain,\n   abi.encode(_chainName, _user, _token, _amount, _depositId)\n  )\n

Note: Read more about inbound state sender and how to use it here.

"},{"location":"developer/templates/deposit_manager/#workflow","title":"Workflow","text":"
  1. Token Registration: Utilizes ChildChain.addToken for mapping tokens on the Dojima chain.
  2. Token Deposit (Ethereum): Users make token deposits into the DepositManager.
  3. State Synchronization: Encoded deposit data is sent to the Dojima chain for synchronization.
  4. Token Deposit (Dojima): ChildChain decodes the data, allocating tokens correspondingly.
"},{"location":"developer/templates/deposit_manager/#interaction-with-child-chain","title":"Interaction with Child Chain","text":"

The Deposit Manager ensures tokens deposited on Ethereum are mirrored on the Dojima Chain through:

  • Inbound State Sender: Facilitates the reception of encoded state messages from Ethereum and other chains to the Dojima Chain, ensuring that deposit data is accurately transmitted for processing.
  • Token Minting on Dojima: Upon receiving deposit data, the Child Chain mints equivalent child tokens, crediting them to the respective user\u2019s account on the Dojima Chain, maintaining consistency across chains.
  • Security and Verification: The State Syncer Verifier, exclusive to the Dojima Chain, authenticates the incoming state messages, permitting the Child Chain to mint tokens securely.
"},{"location":"developer/templates/deposit_manager/#security-and-cautions","title":"Security and Cautions","text":"
  • Accurate State Sender Address: Essential verification of the state sender address for security.
  • Cross-Chain Protocol Security: Evaluate the security measures of the Hermes bridge and related platforms.
  • Comprehensive Smart Contract Audits: Essential to identify and mitigate potential vulnerabilities.
  • Robust User Authentication: Critical for ensuring secure user interaction with the DApp.
"},{"location":"developer/templates/deposit_manager/#conclusion","title":"Conclusion","text":"

This template, alongside the Child Chain, establishes a foundational framework for developing cross-chain DApps, particularly for token transfers between Ethereum and the Dojima Chain. By leveraging this template, developers are equipped to enable streamlined and secure cross-chain token transfers, broadening the interoperability and utility of their applications.

"},{"location":"developer/templates/omni_chain_ERC20/","title":"OmniChain ERC20 template Documentation","text":""},{"location":"developer/templates/omni_chain_ERC20/#introduction","title":"Introduction","text":"

The OmniChain ERC20 template is a pivotal tool for Dojima Chain developers, facilitating the seamless transfer and management of a token across different blockchain networks, including Ethereum, Solana, and others.

"},{"location":"developer/templates/omni_chain_ERC20/#key-features","title":"Key Features:","text":"
  • Cross-Chain Transfer: Enables the transfer of tokens from the Dojima chain to other blockchains.
  • State Synchronization with Outbound State Sender: Leverages outbound state sender for communicating from the Dojima Chain to other chains.
  • Multi-Chain Compatibility: It allows user to transfer tokens from the Dojima chain to any other chain that is connected to the Dojima chain.
"},{"location":"developer/templates/omni_chain_ERC20/#use-cases","title":"Use Cases","text":"
  • Cross-Chain DApps Development: Optimal for DApps that necessitate token fluidity across blockchain ecosystems.
  • Multi-Chain Token Management: Ideal for platforms that require a single token to be used across multiple blockchains.
"},{"location":"developer/templates/omni_chain_ERC20/#prerequisites","title":"Prerequisites","text":"
  • Primary Chain: The primary chain refers to the Dojima Chain.
  • Secondary Chain: The secondary chain refers to the chains other than the Dojima Chain. For example, Ethereum, Solana, Polkadot, etc.
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all cross-chain data. Read more about the Dojima chain here.
  • Source Chain: The source chain refers to the chain from which the cross-chain transfer originates. In the context of the OmniChainERC20Contract, the source chain is the Dojima chain.
  • Destination Chain: A destination chain will refer to all the chains that are connected to the Dojima chain. The destination chain could be Ethereum, Solana, or any other chain that is connected to the Dojima chain. It doesn\u2019t represent the origin of transaction.
  • Hermes Client: The Hermes client is essential for cross-chain communication between the destination and the Dojima Chain and vice versa. Read more about Hermes here.
  • Outbound State Sender: The Outbound State Sender is a key component of the cross-chain data transfer. It will be deployed on the Dojima chain and will be responsible for facilitating the transmission of encoded state messages from the Dojima chain to destination chains. Read more about outbound state sender and how to use it here.
  • XToken: The XToken is an ERC20 token that will be used for cross-chain transfer. It will be deployed on the Dojima chain and will be used to track the token balance of users on the Dojima chain.
  • CrossChainERC20Contract: This token contract will be deployed on the Ethereum chain. It will be used to manage the lifecycle of ERC20 tokens on the secondary chains (Ethereum, Solana, Polkadot, etc.). and will be able to communicate with OmniChainERC20Contract through the Hermes Client.
"},{"location":"developer/templates/omni_chain_ERC20/#contract-overview","title":"Contract Overview","text":""},{"location":"developer/templates/omni_chain_ERC20/#omnichainerc20contract","title":"OmniChainERC20Contract","text":"

Omni chain ERC20 contract is a standard ERC20 contract deployed on the Dojima chain. It is responsible for the minting and burning of XToken on the Dojima chain. It facilitates the transfer of XTokens from the Dojima chain to other chains.

"},{"location":"developer/templates/omni_chain_ERC20/#requirements","title":"Requirements","text":"
  • Outbound State Sender: This is the contract address that is used to send updates from the primary chain (Dojima Chain) to the Secondary Chain (Ethereum, Solana, Polkadot etc.).
  • OnStateReceive: This is a function that needs to be implemented in the primary chain (Dojima Chain) to process the state updates received from the secondary chain contract.

\u26a0\ufe0f Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

"},{"location":"developer/templates/omni_chain_ERC20/#key-functions","title":"Key Functions:","text":"
  • transferToChain: This function enables the transfer of tokens from the Dojima chain to other blockchains. It involves burning tokens on the Source Chain (Dojima chain) and initiates a state sync process to mint destination chain token.
        function transferToChain(\n      bytes32 destinationChain,\n      bytes memory user,\n      uint256 amount,\n      bytes memory destinationContractAddress\n  ) external nonReentrant {\n      _burn(msg.sender, amount);\n    outboundStateSender.transferPayload(\n      destinationChain,\n      destinationContractAddress,\n      refundAddress,\n      abi.encode(user, amount, depositID)\n    );\n  }\n
    The transferPayload function in the transferToChain method has the following parameters:
  • destinationChain: The destination chain will be either Ethereum, Polkadot, Solana etc. for the cross-chain transfer. Basically the name of the secondary chains where we want to send the state update.
  • destinationContractAddress: This is the address of the contract on the secondary chain (Ethereum, Polkadot, Solana etc.) that will receive, decode and process the payload. It\u2019s usually the address of a smart contract that has a function to handle such incoming payloads.
  • refundAddress: This is the address of the entity on the primary chain (Dojima Chain) usually a user address or another contract that will be receiving the refund if the state update fails.
  • abi.encode(user, amount, depositID): This is the payload that is being transferred to the target blockchain. It\u2019s encoded using Ethereum\u2019s ABI (Application Binary Interface) encoding. The payload includes:
    • user: The address of the user who will receive the tokens on the destination chain
    • amount: The number of tokens to be transferred.
    • depositID: The depositId could be used to track or identify individual token transfer operations.
  • onStateReceive: Executed by the _stateVerifier (Dojima system account), this function handles the minting of tokens on the Dojima chain based on the state received from other chains. It decodes the user address, amount, and deposit ID from the received encoded data.
"},{"location":"developer/templates/omni_chain_ERC20/#roles-and-security","title":"Roles and Security:","text":"
  • _stateVerifier Role: A system-controlled account with exclusive rights to mint tokens on the Dojima chain, ensuring security in the token minting process.
  • Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.
"},{"location":"developer/templates/omni_chain_ERC20/#xerc20contract","title":"XERC20Contract","text":"

This contract represents the ERC20 tokens on the Dojima Chain, detailing their properties and providing functions for their management within the Dojima ecosystem.

"},{"location":"developer/templates/omni_chain_ERC20/#crosschainerc20contract","title":"CrossChainERC20Contract","text":"

Manages the lifecycle of ERC20 tokens on the secondary chains (Ethereum, Solana, Polkadot, etc.). And links with OmniChainERC20Contract through the Hermes Client. The total supply of the token will be minted on during the contract initialization.

  • Burn: The Contract will burn user token on the secondary chain (Ethereum, Solana, Polkadot etc.) and will send the state update to the Dojima chain to mint the XERC20 token on the Dojima chain for the user.
  • Minting: The Contract will mint the ERC20 on the secondary chain based on the payload received from the Dojima chain by the executeState function.
"},{"location":"developer/templates/omni_chain_ERC20/#requirements_1","title":"Requirements","text":"
  • Inbound State Sender: This is the contract used to send updates from the secondary chain (Ethereum, Solana, Polkadot etc.) to the primary chain (Dojima Chain).
  • ExecuteState: This is a function that needs to be implemented in the secondary chain contract to process the state updates received from the primary chain (Dojima Chain).

\u26a0\ufe0f Warning: Only State Inbound State Sender contract address is allowed to call executeState function on secondary chains (Ethereum, Solana, Polkadot etc.).

"},{"location":"developer/templates/omni_chain_ERC20/#workflow","title":"Workflow","text":""},{"location":"developer/templates/omni_chain_ERC20/#transfer-from-omnichainerc20contract-to-crosschainerc20contract","title":"Transfer From OmniChainERC20Contract to CrossChainERC20Contract","text":"
  • Source Chain: The source chain here is Dojima Chain (Primary Chain).
  • Transfer From Source: ERC20 token transfers are initiated on the Dojima Chain through the OmniChainNFTContract, specifying the token amount, user address and destination contract address (CrossChainERC20 contract address).
  • State Synchronization: The transfer\u2019s state is encoded and transmitted across chains via the Hermes Client, utilizing the outbound state sender for secure communication.

  • Functionality: The OutboundStateSender\u2019s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) from the Dojima chain\u2019s OmniChainERC20Contract to destination chain contracts.

  • Significance: Ensures the synchronization of token states across chains, triggering corresponding actions (burn or mint) in the connected contracts.
  • Usage in transferToChain:
        outboundStateSender.transferPayload(\n        destinationChain,\n        destinationContractAddress,\n        msg.sender,\n        abi.encode(user, amount, depositID)\n    )\n

\u26a0\ufe0f Warning: The outboundStateSender contract is very crucial for the cross-chain transfer make sure you follow the steps mentioned in the doc.

  • After transfer payload: Once above step is successfully executed on a primary chain (Dojima Chain) the state update will be sent to the secondary chains (Ethereum, Solana, Polkadot etc.).
  • Minting on Destination Chain: Upon receiving the state, the CrossChainERC20 contract on the secondary chain will mint the specified number of tokens for the intended recipient through executeState function, completing the cross-chain transfer.
        function executeState(uint256 depositID, bytes calldata payload) external {\n        // Decode the payload\n        (address userAddress, uint256 amount, uint256 depositId) = abi.decode(\n            stateData, (address, uint256, uint256)\n        );\n        // Mint the ERC20 token for the user\n        // Process the state update\n    }\n
"},{"location":"developer/templates/omni_chain_ERC20/#transfer-from-crosschainerc20contract-to-omnichainerc20contract","title":"Transfer From CrossChainERC20Contract to OmniChainERC20Contract","text":"
  • Destination Chain: The destination chain here is Secondary Chains (Ethereum, Solana, Polkadot).
  • Burn on Destination Chain: The CrossChainERC20 contract will burn the specified number of tokens for the user on the secondary chain.
  • Transfer From Destination Chain: Encode the payload (user address, amount, depositID) and transfer from the secondary chains (Ethereum, Solana, Polkadot etc.) to the Dojima chain through the Inbound State Sender to mint the same amount of XERC20 token on the Dojima chain for the specified user.
  • Usage in transferToOmniChain:
       function transferToOmniChain(bytes memory user, uint256 amount) external nonReentrant {\n        _burn(senderAddress, amount);\n        inboundStateSender.transferPayload(\n          omniChainContractAddress,\n          abi.encode(user, amount, depositID)\n        );\n    }\n
  • After transfer payload: Once above step is successfully executed on secondary chains (Ethereum, Solana, Polkadot etc.) the state update will be sent to the Dojima chain.
  • State Receive on Source Chain: Upon receiving the state, OmniChainERC20Contract which is on Dojima Chain will decode the user address, amount, deposit ID will mint the specified number of tokens for the intended recipient, completing the cross-chain transfer. and deposit IDand mints the XERC20 token for the user.
"},{"location":"developer/templates/omni_chain_ERC20/#security-and-best-practices","title":"Security and Best Practices","text":"
  • Audit Compliance: Ensure all contracts undergo thorough security audits.
  • Transaction Monitoring: Implement systems to monitor and verify cross-chain transactions regularly.
  • Role Management: Strictly manage role assignments, especially for critical roles like _stateVerifier.
  • Gas Optimization: Aim for efficiency in contract execution to minimize transaction costs.
"},{"location":"developer/templates/omni_chain_ERC20/#conclusion","title":"Conclusion","text":"

The OmniChainERC20Contract Suite represents a significant step towards seamless blockchain interoperability, with a focus on security, efficiency, and developer-friendliness. It is crucial for developers to understand the intricacies of the suite to leverage its full potential in their DApp development.

"},{"location":"developer/templates/omni_chain_NFT/","title":"OmniChain NFT Template Documentation","text":""},{"location":"developer/templates/omni_chain_NFT/#introduction","title":"Introduction","text":"

The OmniChainNFT template provides a comprehensive framework for Dojima Chain developers to facilitate the cross-chain transfer of Non-Fungible Tokens (NFTs), enabling seamless interoperability and utilization across various blockchain ecosystems.

"},{"location":"developer/templates/omni_chain_NFT/#key-features","title":"Key Features","text":"
  • Cross-Chain NFT Transfers: Allows for the seamless transfer of NFTs across different blockchain networks.
  • State Synchronization : Utilizes the outbound state sender for robust cross-chain communication.
  • Multi-Chain Compatibility: Ensures NFTs are accessible and transferable across a wide range of blockchain networks.
"},{"location":"developer/templates/omni_chain_NFT/#use-cases","title":"Use Cases","text":"
  • Cross-Chain NFT Marketplaces: Allows NFTs to be listed, bought, and sold across different blockchain marketplaces.
  • NFT Collections: Enables collectors to move their NFTs across chains, broadening the exposure and utility of their collections.
"},{"location":"developer/templates/omni_chain_NFT/#prerequisites","title":"Prerequisites","text":"
  • Primary Chain: The primary chain refers to the Dojima Chain.
  • Secondary Chain: The secondary chain refers to the chains other than the Dojima Chain. For example, Ethereum, Solana, Polkadot, etc.
  • Source Chain: The source chain refers to the chain from which the cross-chain transfer originates.
  • Destination Chain: A destination chain will refer to the chains where the cross-chain transfer will be received.
  • Hermes Client: Proficiency with the Hermes Client, a crucial component for enabling the communication between the Dojima Chain and other blockchains. The Hermes Client facilitates the secure and efficient transfer of state information across chains.
  • Dojima Chain: The Dojima chain is an EVM-based blockchain that stores all cross-chain data. Read more about the Dojima chain here.
  • OutboundStateSender: The OutboundStateSender contract will be used to send state updates from the primary chain (Dojima Chain) to the secondary chain (Ethereum, Solana, Polkadot).
  • InboundStateSender: The InboundStateSender contract will be used to send state updates from the secondary chain (Ethereum, Solana, Polkadot) to the primary chain (Dojima Chain).
  • XNFTContract: The XNFTContract is an ERC721 standard token contract that will be used for cross-chain NFT transfer. It will be deployed on the Dojima chain and will be used to track the NFTs\u2019 of users on the Dojima chain.
  • CrossChainNFTContract: This NFT contract will be deployed on the secondary chains (Ethereum, Solana, Polkadot, etc.). It will be used to manage the lifecycle of NFTs\u2019 on the secondary chain (Ethereum, Solana, Polkadot, etc.) network and will be able to communicate with OmniChainNFTContract through the Hermes Client.
"},{"location":"developer/templates/omni_chain_NFT/#contract-overview","title":"Contract Overview","text":""},{"location":"developer/templates/omni_chain_NFT/#omnichainnftcontract","title":"OmniChainNFTContract","text":"

A pivotal contract deployed on the primary chain (Dojima Chain) to manage the lifecycle of NFTs during the cross-chain transfer process, including functionalities for burning and minting NFTs across chains.

"},{"location":"developer/templates/omni_chain_NFT/#requirements","title":"Requirements","text":"
  • Outbound State Sender: This is the contract address used to send updates from the primary chain (Dojima Chain) to the secondary chain (Ethereum, Solana, Polkadot).
  • OnStateReceive: This function is responsible for receiving the state updates from the secondary chain and processing them on the Dojima Chain.

\u26a0\ufe0f Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

"},{"location":"developer/templates/omni_chain_NFT/#key-functions","title":"Key Functions:","text":"
  • transferToChain: This function enables the transfer of NFT from the Dojima chain to other blockchains. It involves burning specified NFT on the Source Chain (Dojima chain) and initiates a state sync process to mint the same NFT on the destination chain.
      function transferToChain(\n    bytes32 destinationChain,\n    bytes memory user,\n    uint256 amount,\n    bytes memory destinationContractAddress\n) external nonReentrant {\n    _burn(msg.sender, amount);\n  outboundStateSender.transferPayload(\n    destinationChain,\n    destinationContractAddress,\n    refundAddress,\n    abi.encode(user, amount, depositID)\n  );\n}\n
    The transferPayload function in the transferToChain method has the following parameters:
  • destinationChain: The destination chain will be either Ethereum, Polkadot, Solana etc. for the cross-chain transfer. Basically the name of the secondary chains where we want to send the state update.
  • destinationContractAddress: This is the address of the contract on the secondary chain (Ethereum, Polkadot, Solana etc.) that will receive, decode and process the payload. It\u2019s usually the address of a smart contract that has a function to handle such incoming payloads.
  • refundAddress: This is the address of the entity on the primary chain (Dojima Chain) usually a user address or another contract that will be receiving the refund if the state update fails.
  • abi.encode(user, amount, depositId): This is the payload that is being transferred to the target blockchain. It\u2019s encoded using Ethereum\u2019s ABI (Application Binary Interface) encoding. The payload includes:
    • user: The address of the user who will receive the tokens on the destination chain
    • amount: The number of tokens to be transferred.
    • depositID: The depositId could be used to track or identify individual token transfer operations.
  • onStateReceive: Executed by the _stateVerifier (Dojima system account), this function handles the minting of tokens on the primary chain (Dojima chain) based on the state received from other chains. It decodes the user address, amount, and deposit ID from the received encoded data.
"},{"location":"developer/templates/omni_chain_NFT/#roles-and-security","title":"Roles and Security:","text":"
  • _stateVerifier Role: A system-controlled account with exclusive rights to mint NFTs\u2019 on the Dojima chain, ensuring security in the token minting process.
  • Security Concerns: Robust error handling and transaction monitoring are essential to maintain integrity in cross-chain communication and prevent unauthorized minting or burning of tokens.
"},{"location":"developer/templates/omni_chain_NFT/#xnftcontract","title":"XNFTContract","text":"

This contract represents the NFTs on the Dojima Chain, detailing their properties and providing functions for their management within the Dojima ecosystem.

"},{"location":"developer/templates/omni_chain_NFT/#crosschainnft","title":"CrossChainNFT","text":"

Manages the lifecycle of NFTs\u2019 on the secondary chains (Ethereum, Solana, Polkadot, etc.). And links with OmniChainNFTContract through the Hermes Client.

  • Burn: The Contract will burn user NFT on the secondary chain (Ethereum, Solana, Polkadot etc.) and will send the state update to the Dojima chain to mint the same NFT on the Dojima chain for the same user.
  • Minting: The Contract will mint the NFT on the secondary chain based on the payload received from the Dojima chain by the executeState function.
"},{"location":"developer/templates/omni_chain_NFT/#requirements_1","title":"Requirements","text":"
  • Inbound State Sender: This is the contract address that is used to send updates from the secondary chain (Ethereum, Solana, Polkadot) to the primary chain (Dojima Chain).
  • ExecuteState: This is a function that needs to be implemented in the secondary chain contract to process the state updates received from the primary chain (Dojima Chain).

\u26a0\ufe0f Warning: Only State Syncer Verifier is allowed to call onStateReceive function on dojima chain contracts. Syncer verifier is a system-controlled account with exclusive rights to mint tokens on the Dojima chain.

"},{"location":"developer/templates/omni_chain_NFT/#workflow","title":"Workflow","text":""},{"location":"developer/templates/omni_chain_NFT/#transfer-from-omnichainerc20contract-to-crosschainerc20contract","title":"Transfer From OmniChainERC20Contract to CrossChainERC20Contract","text":"
  • Source Chain: The source chain here is Dojima Chain (Primary Chain).
  • Burning NFT for Transfer: In transferToChain, NFT for the user are burned on the primary chain (Dojima chain) to initiate cross-chain transfer.
  • Transfer Initiation: NFT transfers are initiated on the Dojima Chain through the OmniChainNFTContract, specifying the NFT and its destination.
  • State Synchronization: The transfer\u2019s state is encoded and transmitted across chains via the Hermes Client, utilizing the outbound state sender for secure communication.
  • Functionality: The OutboundStateSender\u2019s transferPayload function is crucial in cross-chain communication. It transmits the encoded state (user address, token amount, deposit ID) from the Dojima chain\u2019s OmniChainERC20Contract to the secondary chain (Ethereum, Solana, Polkadot, etc.) CrossChainNFT contracts.
  • Usage in transferToChain:
    outboundStateSender.transferPayload(\n    destinationChain,\n    destinationContractAddress,\n    msg.sender,\n    abi.encode(user, tokenId, depositID)\n)\n

\u26a0\ufe0f Warning: The outboundStateSender contract is very crucial for the cross-chain transfer make sure you follow the steps mentioned in the doc.

  • After transfer payload: Once above step is successfully executed on a primary chain (Dojima Chain) the state update will be sent to the secondary chains (Ethereum, Solana, Polkadot etc.).
  • Minting on Destination Chain: Upon receiving the state, the CrossChainNFT contract on the secondary chain will mint the NFT for the intended recipient, completing the cross-chain transfer.
        function executeState(uint256 depositID, bytes calldata payload) external {\n        // Decode the payload\n        (address userAddress, uint256 tokenId, uint256 depositId) = abi.decode(\n            stateData, (address, uint256, uint256)\n        );\n        // Mint the NFT for the user\n        // Process the state update\n    }\n
"},{"location":"developer/templates/omni_chain_NFT/#transfer-from-crosschainerc20contract-to-omnichainerc20contract","title":"Transfer From CrossChainERC20Contract to OmniChainERC20Contract","text":"
  • Destination Chain: The destination chain here is Secondary Chains (Ethereum, Solana, Polkadot).
  • Burn on Destination Chain: The CrossChainNFT contract will burn the specified NFT for the user on the secondary chain.
  • Transfer From Destination Chain: Encode the payload (user address, tokenID, depositID) and transfer from the secondary chains (Ethereum, Solana, Polkadot etc.) to the Dojima chain through the Inbound State Sender
  • Usage in transferToOmniChain:
       function transferToOmniChain(bytes memory user, uint256 amount) external nonReentrant {\n        _burn(tokenId);\n        inboundStateSender.transferPayload(\n          omniChainContractAddress,\n          abi.encode(user, tokenId, depositID)\n        );\n    }\n
  • After transfer payload: Once above step is successfully executed on secondary chains (Ethereum, Solana, Polkadot etc.) the state update will be sent to the Dojima chain.
  • State Receive on Source Chain: Upon receiving the state, OmniChainERC20Contract which is on Dojima Chain will decode the user address, amount, deposit ID will mint the specified number of tokens for the intended recipient, completing the cross-chain transfer. and deposit IDand mints the XERC20 token for the user.
"},{"location":"developer/templates/omni_chain_NFT/#security-and-best-practices","title":"Security and Best Practices","text":"
  • Smart Contract Audits: Ensure comprehensive audits of all contracts involved in the NFT transfer process to identify and mitigate potential security risks.
  • Secure Communication Channels: Utilize secure and verified communication channels for the transmission of state information between chains.
  • Role-Based Access Control: Implement and strictly enforce role-based access control within contracts to prevent unauthorized actions.
"},{"location":"developer/templates/omni_chain_NFT/#conclusion","title":"Conclusion","text":"

The OmniChainNFT Suite marks a significant advancement towards achieving seamless NFT interoperability across blockchain networks. By providing a standardized framework for cross-chain NFT transfers, it opens up new possibilities for NFT utilization and enhances the overall blockchain ecosystem\u2019s connectivity.

"},{"location":"tools/","title":"Tools","text":"Tools

Explore our versatile tools section featuring a cross-chain wallet, innovative FAAS solution, and developer dashboard for seamless integration.

Dojima Wallet

Dojima wallet lets you organise major layer 1 tokens in one place.

Dojima Fass

You can get blockchain functionality as a service from Dojima FAAS, like signing transactions, viewing transaction histories and more.

"},{"location":"tools/dojima-faas/","title":"Dojima-FaaS","text":""},{"location":"tools/dojima-faas/#dojima-faas","title":"Dojima faas","text":"

Dojima faas provides you blockchain functionality as a service. Blockchain functionality such as creating an account, gas rates for transaction, signing transaction, dollar price, transaction history, submit transaction e.t.c.

"},{"location":"tools/dojima-faas/#features","title":"Features","text":"
  • One Api - Single endpoint for all blockchain functionality to develop dapps.
  • Create Account - create an account for any blockchain by just providing a chain name.
  • Gas Rates - slow, average, fast gas rates for transaction to be processed.
  • Dollar price - dollar price of any token instantly.
  • Transaction history - transaction history of any blockchain providing necessary details.
  • Price History - price of daily, weekly, yearly, all-time token.
"},{"location":"tools/dojima-faas/#user","title":"User","text":"

These endpoints are used to create, delete, find or update user.

POST Create user

 https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot1&email=robot1@gmail.com&plan=monthly\n

Returns user details along with apikey based on inputs provided.

"},{"location":"tools/dojima-faas/#params","title":"PARAMS","text":"name robot1 Required. Name of the user email robot1@gmail.com Required. Provide valid email of the user to receive updates or notifications plan monthly Required. \u2018monthly or yearly\u2019. Provide a plan type to get access until the selected period. > monthly - 10,000 calls/month yearly - 1,80,000 calls/year

GET Find user

 https://faas-test.dojima.network/dojima-faas/v1/user/data?api=c226c9df7eb08c82c4f4c22266dd\n
api c226c9df7eb08c82c4f4c22266dd"},{"location":"tools/dojima-faas/#account","title":"Account","text":"

These endpoints return details such as public address from seed phrase/mnemonic, balance of the respective input token.

GET Address

 https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn&network=testnet\n

Returns public addresses of the provided seed phrase of the user and network type.

"},{"location":"tools/dojima-faas/#headers","title":"HEADERS","text":"X-API-KEY c226c9df7eb08c82c4f4c22266dd Required. Api Key of the user for endpoint to generate result Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly."},{"location":"tools/dojima-faas/faasaccount/","title":"Account","text":"

These endpoints return details such as public address from seed phrase/mnemonic, balance of the respective input token.

"},{"location":"tools/dojima-faas/faasaccount/#get-address","title":"GET Address","text":"
 https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn&network=testnet\n

Returns public addresses of the provided seed phrase of the user and network type.

"},{"location":"tools/dojima-faas/faasaccount/#headers","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY c226c9df7eb08c82c4f4c22266dd Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faasaccount/#params","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description mnemonic letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn Required: Seed phrase of the user to generate addresses. network testnet Required: \u2018mainnet or testnet or devnet\u2019"},{"location":"tools/dojima-faas/faasaccount/#example-request-and-response","title":"Example Request and Response","text":"REQUESTResponse

cURL.

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet' \\\n--header 'X-API-KEY: ********************'\n

Java Script.

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"********************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
 {\n   \"arweave\": \"7zzxJgYHgDlaURc3xt3wvLITPp6I8oIpYj_yg_xirb4\",\n   \"bitcoin\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n   \"ethereum\": \"0x0577e1E35C4f30cA8379269B7Fd85cBCE7F084f4\",\n   \"solana\": \"DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS\"\n }\n
"},{"location":"tools/dojima-faas/faasaccount/#get-token-balance","title":"GET Token Balance","text":"

https://faas-test.dojima.network/dojima-faas/v1/account/balance?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&asset=bitcoin&network=testnet\n
Returns balance of the token based on inputs.

"},{"location":"tools/dojima-faas/faasaccount/#headers_1","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY c226c9df7eb08c82c4f4c22266dd Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faasaccount/#params_1","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description mnemonic letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn Required: Seed phrase of the user to generate addresses. network testnet Required: \u2018mainnet or testnet or devnet\u2019"},{"location":"tools/dojima-faas/faasaccount/#example-request-and-response_1","title":"Example Request and Response","text":"REQUESTResponse

cURL.

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet' \\\n--header 'X-API-KEY: ********************'\n

Java Script.

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"********************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
 {\n   \"key\": \"6\",\n   \"name\": \"robot\",\n   \"email\":  \"robot@gmail.com\",\n   \"apiKey\": \"**********************\",\n   \"plan\":\"monthly\",\n   \"limit\":\"100000\",\n   \"createdAt\": \"2022-08-04T05:02:19.000Z\",\n   \"validUntil\": \"2022-09-03T05:02:19.623Z\",\n   \"updatedAt\": \"2022-08-04T05:02:19.000Z\"\n }\n
"},{"location":"tools/dojima-faas/faaspricestats/","title":"Prices Stats","text":"

These endpoints return details such as token latest prices, stats, history based particular date or past n days or in between certain dates.

"},{"location":"tools/dojima-faas/faaspricestats/#get-token-latest-price","title":"GET Token latest price","text":"
https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana\n

Returns token current price, market_cap, volume, supply, data related to ath (all time high), atl (all time low).

"},{"location":"tools/dojima-faas/faaspricestats/#headers","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faaspricestats/#params","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description mnemonic Required: Seed phrase of the user to generate addresses. network Required: \u2018mainnet or testnet or devnet\u2019"},{"location":"tools/dojima-faas/faaspricestats/#example-request-and-response","title":"Example Request and Response","text":"REQUESTResponse

cURL

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana' \\\n--header 'X-API-KEY: ****************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"****************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
 {\n   \"current_price\": 39.19,\n   \"market_cap\": 13566176494,\n   \"total_volume\": 1491902699,\n   \"circulating_supply\": 346652190.616162,\n   \"total_supply\": 508180963.57,\n   \"max_supply\": null,\n   \"ath\": 259.96,\n   \"ath_change_percentage\": -84.96585,\n   \"ath_date\": \"Sat, 06 Nov 2021 21:54:35 GMT\",\n   \"atl\": 0.500801,\n   \"atl_change_percentage\": 7704.02799,\n   \"atl_date\": \"Mon, 11 May 2020 19:35:23 GMT\"\n }\n
"},{"location":"tools/dojima-faas/faaspricestats/#get-token-latest-stats","title":"GET Token latest stats","text":"

https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC\n
Returns token stats related to addresses, blocks, transactions, supply, etc.

"},{"location":"tools/dojima-faas/faaspricestats/#headers_1","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faaspricestats/#params_1","title":"Params","text":"

Note

Token list:

  • btc
  • ar
  • eth
  • sol
Parameter Description token Required: Token id to retrieve stats related to addresses, blocks, transactions, supply, etc."},{"location":"tools/dojima-faas/faaspricestats/#example-request-and-response_1","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC' \\\n--header 'X-API-KEY: **********************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"**********************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
     {\n \"id\": 1182,\n \"time\": 1659484800,\n \"symbol\": \"BTC\",\n \"partner_symbol\": \"BTC\",\n \"zero_balance_addresses_all_time\": 985144574,\n \"unique_addresses_all_time\": 1027159686,\n \"new_addresses\": 417758,\n \"active_addresses\": 979238,\n \"average_transaction_value\": 15.41044161368356,\n \"block_height\": 747864,\n \"hashrate\": 199187870.17167962,\n \"difficulty\": 27692567959233.59,\n \"block_time\": 597.1180555555553,\n \"block_size\": 1292170,\n \"current_supply\": 19111662,\n \"transaction_count\": 282037,\n \"transaction_count_all_time\": 753969557,\n \"large_transaction_count\": 18486\n }\n
"},{"location":"tools/dojima-faas/faaspricestats/#get-history-by-date","title":"GET History by date","text":"

https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=05-07-2021\n
Returns token price, market_cap and total_volume on a particular date.

"},{"location":"tools/dojima-faas/faaspricestats/#headers_2","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faaspricestats/#params_2","title":"Params","text":"

Note

Token list:

  • bitcoin
  • arweave
  • ethereum
  • solana
  • usd-coin
Parameter Description tokenName Required: token price, market_cap and total_volume on a particular date. days Required. DD-MM-YYYY format date"},{"location":"tools/dojima-faas/faaspricestats/#example-request-and-response_2","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=22-05-2022' \\\n--header 'X-API-KEY: *******************'\n

Java Script

  var myHeaders = new Headers();\n  myHeaders.append(\"X-API-KEY\", \"*******************\");\n\n  var requestOptions = {\n    method: 'GET',\n    headers: myHeaders,\n    redirect: 'follow'\n  };\n\n  fetch(\"https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=22-05-2022\", requestOptions)\n    .then(response => response.text())\n    .then(result => console.log(result))\n    .catch(error => console.log('error', error));\n
   [\n     {\n       \"current_price\": 29491.507947760598,\n       \"market_cap\": 561696351558.8424,\n       \"total_volume\": 13561006428.368963\n     }\n   ]\n
"},{"location":"tools/dojima-faas/faaspricestats/#get-get-history-by-days","title":"GET GET History by days","text":"

https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20\n
Returns token prices, market_cap and total_volume for mentioned no. of days. Minutely data for 1 day, hourly data for 1.

"},{"location":"tools/dojima-faas/faaspricestats/#headers_3","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faaspricestats/#params_3","title":"Params","text":"

Note

Token list:

  • bitcoin
  • arweave
  • ethereum
  • solana
  • usd-coin
Parameter Description tokenName Required: token price, market_cap and total_volume on a particular date. date Required. Token prices, market_cap and total_volume for mentioned no. of days. Minutely data for 1 day, hourly data for 1<days<=10 and daily data for 10 < days"},{"location":"tools/dojima-faas/faaspricestats/#example-request-and-response_3","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20' \\\n  --header 'X-API-KEY: *******************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"*******************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
 [\n   {\n     \"prices\": [\n       {\n         \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n         \"price\": 20794.811981436706\n       },\n       {\n         \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n         \"price\": 21193.08334336837\n       },\n       {\n         \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n         \"price\": 20824.36275165164\n       },\n       {\n         \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n         \"price\": 22395.365383103952\n       },\n       {\n         \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n         \"price\": 23366.90769792785\n       },\n       {\n         \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n         \"price\": 23313.296731959555\n       },\n       {\n         \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n         \"price\": 23155.207555248304\n       },\n       {\n         \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n         \"price\": 22696.902754290055\n       },\n       {\n         \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n         \"price\": 22506.199573628986\n       },\n       {\n         \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n         \"price\": 22613.719208248454\n       },\n       {\n         \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n         \"price\": 21330.295450788173\n       },\n       {\n         \"date\": \"Wed, 27 Jul 2022 00:00:00 GMT\",\n         \"price\": 21235.612316085775\n       },\n       {\n         \"date\": \"Thu, 28 Jul 2022 00:00:00 GMT\",\n         \"price\": 22908.884260468687\n       },\n       {\n         \"date\": \"Fri, 29 Jul 2022 00:00:00 GMT\",\n         \"price\": 23822.067597823116\n       },\n       {\n         \"date\": \"Sat, 30 Jul 2022 00:00:00 GMT\",\n         \"price\": 23847.58331873861\n       },\n       {\n         \"date\": \"Sun, 31 Jul 2022 00:00:00 GMT\",\n         \"price\": 23653.459549430798\n       },\n       {\n         \"date\": \"Mon, 01 Aug 2022 00:00:00 GMT\",\n         \"price\": 23379.70052509082\n       },\n       {\n         \"date\": \"Tue, 02 Aug 2022 00:00:00 GMT\",\n         \"price\": 23333.749243312184\n       },\n       {\n         \"date\": \"Wed, 03 Aug 2022 00:00:00 GMT\",\n         \"price\": 23053.846847482677\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 00:00:00 GMT\",\n         \"price\": 22860.42098438317\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 10:25:46 GMT\",\n         \"price\": 22950.523475823156\n       }\n     ],\n     \"market_cap\": [\n       {\n         \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n         \"price\": 397285233065.65533\n       },\n       {\n         \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n         \"price\": 404705642580.89075\n       },\n       {\n         \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n         \"price\": 397660610560.5498\n       },\n       {\n         \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n         \"price\": 425756736660.6174\n       },\n       {\n         \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n         \"price\": 445889013251.1064\n       },\n       {\n         \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n         \"price\": 446130012149.91077\n       },\n       {\n         \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n         \"price\": 442379611364.02734\n       },\n       {\n         \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n         \"price\": 433485926857.3929\n       },\n       {\n         \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n         \"price\": 429803379587.55133\n       },\n       {\n         \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n         \"price\": 433819662321.5266\n       },\n       {\n         \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n         \"price\": 407480099599.8142\n       },\n       {\n         \"date\": \"Wed, 27 Jul 2022 00:00:00 GMT\",\n         \"price\": 405692421501.52716\n       },\n       {\n         \"date\": \"Thu, 28 Jul 2022 00:00:00 GMT\",\n         \"price\": 437193517021.8447\n       },\n       {\n         \"date\": \"Fri, 29 Jul 2022 00:00:00 GMT\",\n         \"price\": 454806622614.75885\n       },\n       {\n         \"date\": \"Sat, 30 Jul 2022 00:00:00 GMT\",\n         \"price\": 459609388579.5554\n       },\n       {\n         \"date\": \"Sun, 31 Jul 2022 00:00:00 GMT\",\n         \"price\": 451726702392.36206\n       },\n       {\n         \"date\": \"Mon, 01 Aug 2022 00:00:00 GMT\",\n         \"price\": 447051019373.1847\n       },\n       {\n         \"date\": \"Tue, 02 Aug 2022 00:00:00 GMT\",\n         \"price\": 445958949620.3002\n       },\n       {\n         \"date\": \"Wed, 03 Aug 2022 00:00:00 GMT\",\n         \"price\": 440954684720.7478\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 00:00:00 GMT\",\n         \"price\": 437035641450.2815\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 10:25:46 GMT\",\n         \"price\": 438396573850.57587\n       }\n     ],\n     \"total_volume\": [\n       {\n         \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n         \"price\": 46542248374.33238\n       },\n       {\n         \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n         \"price\": 42051101694.797554\n       },\n       {\n         \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n         \"price\": 29615794461.49923\n       },\n       {\n         \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n         \"price\": 58636734705.48306\n       },\n       {\n         \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n         \"price\": 57338223361.51413\n       },\n       {\n         \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n         \"price\": 40775718993.79776\n       },\n       {\n         \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n         \"price\": 63224249257.511284\n       },\n       {\n         \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n         \"price\": 40304373301.41499\n       },\n       {\n         \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n         \"price\": 42519262113.1533\n       },\n       {\n         \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n         \"price\": 33108916659.05373\n       },\n       {\n         \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n         \"price\": 42667548128.932236\n       },\n       {\n         \"date\": \"Wed, 27 Jul 2022 00:00:00 GMT\",\n         \"price\": 53995620035.18145\n       },\n       {\n         \"date\": \"Thu, 28 Jul 2022 00:00:00 GMT\",\n         \"price\": 54498281944.45157\n       },\n       {\n         \"date\": \"Fri, 29 Jul 2022 00:00:00 GMT\",\n         \"price\": 55609627980.6571\n       },\n       {\n         \"date\": \"Sat, 30 Jul 2022 00:00:00 GMT\",\n         \"price\": 41089335195.63975\n       },\n       {\n         \"date\": \"Sun, 31 Jul 2022 00:00:00 GMT\",\n         \"price\": 62102072346.807785\n       },\n       {\n         \"date\": \"Mon, 01 Aug 2022 00:00:00 GMT\",\n         \"price\": 31786729326.443203\n       },\n       {\n         \"date\": \"Tue, 02 Aug 2022 00:00:00 GMT\",\n         \"price\": 44489771146.510735\n       },\n       {\n         \"date\": \"Wed, 03 Aug 2022 00:00:00 GMT\",\n         \"price\": 35151096516.75639\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 00:00:00 GMT\",\n         \"price\": 41334593234.075066\n       },\n       {\n         \"date\": \"Thu, 04 Aug 2022 10:25:46 GMT\",\n         \"price\": 23908600834.73234\n       }\n     ]\n   }\n ]\n
"},{"location":"tools/dojima-faas/faaspricestats/#get-history-by-date-range","title":"GET History by date range","text":"

https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=05-07-2021\n
Returns token price, market_cap and total_volume for date range. 5 minute interval data data if date difference 1 day, hourly data if date difference is between 1 and 90 and daily data if date difference is more than 90.

"},{"location":"tools/dojima-faas/faaspricestats/#headers_4","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/faaspricestats/#params_4","title":"Params","text":"

Note

Token list:

  • bitcoin
  • arweave
  • ethereum
  • solana
  • usd-coin
Parameter Description tokenName Required: token price, market_cap and total_volume on a particular date. fromDate Required: YYYY-MM-DD format date thruDate Required. YYYY-MM-DD format date"},{"location":"tools/dojima-faas/faaspricestats/#example-request-and-response_4","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/date/range?tokenName=bitcoin&fromDate=2022-05-01&thruDate=2022-05-11' \\\n  --header 'X-API-KEY: *****************'\n

Java Script

  var myHeaders = new Headers();\n  myHeaders.append(\"X-API-KEY\", \"*****************\");\n\n  var requestOptions = {\n    method: 'GET',\n    headers: myHeaders,\n    redirect: 'follow'\n  };\n\n  fetch(\"https://faas-test.dojima.network/dojima-faas/v1/prices/history/date/range?tokenName=bitcoin&fromDate=2022-05-01&thruDate=2022-05-31\", requestOptions)\n    .then(response => response.text())\n    .then(result => console.log(result))\n    .catch(error => console.log('error', error));\n
 {\n   \"prices\": [\n     {\n       \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n       \"price\": 1234.0991389763224\n     },\n     {\n       \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n       \"price\": 1355.04564021949\n     },\n     {\n       \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n       \"price\": 1344.7202840019017\n     },\n     {\n       \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n       \"price\": 1570.6589588642053\n     },\n     {\n       \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n       \"price\": 1542.6298214332235\n     },\n     {\n       \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n       \"price\": 1527.4139307593093\n     },\n     {\n       \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n       \"price\": 1576.8252394976823\n     },\n     {\n       \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n       \"price\": 1536.124922238913\n     },\n     {\n       \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n       \"price\": 1552.4964891908746\n     },\n     {\n       \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n       \"price\": 1601.2079670127046\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n       \"price\": 1450.4822852139405\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 04:59:49 GMT\",\n       \"price\": 1431.2771658285428\n     }\n   ],\n   \"market_cap\": [\n     {\n       \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n       \"price\": 147677565536.3019\n     },\n     {\n       \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n       \"price\": 161839496479.48514\n     },\n     {\n       \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n       \"price\": 161551223982.244\n     },\n     {\n       \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n       \"price\": 187518878564.43118\n     },\n     {\n       \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n       \"price\": 184299116474.0005\n     },\n     {\n       \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n       \"price\": 183383314168.63928\n     },\n     {\n       \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n       \"price\": 188807814065.77225\n     },\n     {\n       \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n       \"price\": 183933879174.97644\n     },\n     {\n       \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n       \"price\": 185766674503.14\n     },\n     {\n       \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n       \"price\": 192833875418.8718\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n       \"price\": 176371406952.78534\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 04:59:49 GMT\",\n       \"price\": 171509003635.7274\n     }\n   ],\n   \"total_volume\": [\n     {\n       \"date\": \"Sat, 16 Jul 2022 00:00:00 GMT\",\n       \"price\": 16817194904.2499\n     },\n     {\n       \"date\": \"Sun, 17 Jul 2022 00:00:00 GMT\",\n       \"price\": 19025831554.91271\n     },\n     {\n       \"date\": \"Mon, 18 Jul 2022 00:00:00 GMT\",\n       \"price\": 15797648344.457474\n     },\n     {\n       \"date\": \"Tue, 19 Jul 2022 00:00:00 GMT\",\n       \"price\": 26437290054.27533\n     },\n     {\n       \"date\": \"Wed, 20 Jul 2022 00:00:00 GMT\",\n       \"price\": 27749085857.707005\n     },\n     {\n       \"date\": \"Thu, 21 Jul 2022 00:00:00 GMT\",\n       \"price\": 21728126383.56131\n     },\n     {\n       \"date\": \"Fri, 22 Jul 2022 00:00:00 GMT\",\n       \"price\": 19411405082.967407\n     },\n     {\n       \"date\": \"Sat, 23 Jul 2022 00:00:00 GMT\",\n       \"price\": 18084368731.242767\n     },\n     {\n       \"date\": \"Sun, 24 Jul 2022 00:00:00 GMT\",\n       \"price\": 14901008279.154797\n     },\n     {\n       \"date\": \"Mon, 25 Jul 2022 00:00:00 GMT\",\n       \"price\": 16058331978.02615\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 00:00:00 GMT\",\n       \"price\": 19852493229.276333\n     },\n     {\n       \"date\": \"Tue, 26 Jul 2022 04:59:49 GMT\",\n       \"price\": 19607955073.403877\n     }\n   ]\n }\n
"},{"location":"tools/dojima-faas/faasuser/","title":"User","text":"

These endpoints are used to create, delete, find or update user.

"},{"location":"tools/dojima-faas/faasuser/#post-create-user","title":"POST Create user","text":"
 https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot1&email=robot1@gmail.com&plan=monthly\n

Returns user details along with apikey based on inputs provided.

"},{"location":"tools/dojima-faas/faasuser/#params","title":"PARAMS","text":"name robot1 Required. Name of the user email robot1@gmail.com Required. Provide valid email of the user to receive updates or notifications plan monthly Required. \u2018monthly or yearly\u2019. Provide a plan type to get access until the selected period. > monthly - 10,000 calls/month yearly - 1,80,000 calls/year"},{"location":"tools/dojima-faas/faasuser/#example-request-and-response","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

 curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************'\n

Java Script

   var requestOptions = {\n  method: 'POST',\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot&email=robot@gmail.com&plan=monthly\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
   {\n     \"key\": 6,\n     \"name\": \"robot\",\n     \"email\": \"robot@gmail.com\",\n     \"apiKey\": \"**********************\",\n     \"plan\": \"monthly\",\n     \"limit\": 100000,\n     \"createdAt\": \"2022-08-04T05:02:19.000Z\",\n     \"validUntil\": \"2022-09-03T05:02:19.623Z\",\n     \"updatedAt\": \"2022-08-04T05:02:19.000Z\"\n   }\n
"},{"location":"tools/dojima-faas/faasuser/#get-find-user","title":"GET Find user","text":"

https://faas-test.dojima.network/dojima-faas/v1/user/data?api=c226c9df7eb08c82c4f4c22266dd\n
Query Parameters

Parameters Description api c226c9df7eb08c82c4f4c22266dd"},{"location":"tools/dojima-faas/faasuser/#example-request-and-response_1","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"****************\");\n\nvar requestOptions = {\n  method: 'GET',\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n

``` json { \u201ckey\u201d: 6, \u201cname\u201d: \u201crobot\u201d, \u201cemail\u201d: \u201crobot@gmail.com\u201d, \u201capiKey\u201d: \u201c******\u201d, \u201cplan\u201d: \u201cmonthly\u201d, \u201climit\u201d: 100000, \u201ccreatedAt\u201d: \u201c2022-08-04T05:02:19.000Z\u201d, \u201cvalidUntil\u201d: \u201c2022-09-03T05:02:19.623Z\u201d, \u201cupdatedAt\u201d: \u201c2022-08-04T05:02:19.000Z\u201d }

```

"},{"location":"tools/dojima-faas/transactiondetails/","title":"Transaction Details","text":"

Returns transaction details such as detailed transaction data, transactions history based on mentioned token, network and related data.

"},{"location":"tools/dojima-faas/transactiondetails/#history","title":"History","text":"

Returns list of transactions done by an address based on respective token input and network.

"},{"location":"tools/dojima-faas/transactiondetails/#get-arweave","title":"GET Arweave","text":"
https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet\n

Returns list of transactions done by an address for arweave.

"},{"location":"tools/dojima-faas/transactiondetails/#headers","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description address Required: Public address of the user to which transactions history to be displayed. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions. limit Optional. Default 100. Number of transactions to be displayed per call."},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet\n

Java Script

  var myHeaders = new Headers();\n  myHeaders.append(\"X-API-KEY\", \"******************\");\n\n  var requestOptions = {\n    method: 'GET',\n    headers: myHeaders,\n    redirect: 'follow'\n  };\n\n  fetch(\"https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet\", requestOptions)\n    .then(response => response.text())\n    .then(result => console.log(result))\n    .catch(error => console.log('error', error));\n
 {\n   \"outer\": [\n     {\n       \"timestamp\": 1648533262,\n       \"transaction_hash\": \"sAn6BS_kQXYO2tq9NdNcQInzQBy8ai05T1lIoLVOFSE\",\n       \"block\": 902207,\n       \"from\": \"iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys\",\n       \"to\": \"4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o\",\n       \"value\": \"0.212303132894\",\n       \"gas_price\": \"0.000000724176\",\n       \"date\": \"29/03/2022\",\n       \"time\": \"11:24:22\"\n     },\n     {\n       \"timestamp\": 1648520642,\n       \"transaction_hash\": \"UygVPWgsvFYJnie_VmFXq4sXkq_48AxMQ2AuGTWWwVM\",\n       \"block\": 902106,\n       \"from\": \"iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys\",\n       \"to\": \"4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o\",\n       \"value\": \"263.746368279452\",\n       \"gas_price\": \"0.000000731880\",\n       \"date\": \"29/03/2022\",\n       \"time\": \"07:54:02\"\n     }\n   ],\n   \"inner\": [\n     {\n       \"timestamp\": 1648533262,\n       \"transaction_hash\": \"sAn6BS_kQXYO2tq9NdNcQInzQBy8ai05T1lIoLVOFSE\",\n       \"block\": 902207,\n       \"from\": \"iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys\",\n       \"to\": \"4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o\",\n       \"value\": \"0.212303132894\",\n       \"gas_price\": \"0.000000724176\",\n       \"date\": \"29/03/2022\",\n       \"time\": \"11:24:22\",\n       \"signature\": \"FTALC7RxZVXkd1cETUl83Zt8ZV-zOfy2lqPpC8XzKdzcu_pLBGCdq-UNT-YMfgiurPm4Tt673p7VgudNu55Lu76njnFi2oqnK7Ixn9pp3oMZVtNFEFf3u_MILeRC45arkzFUhZkPDRJkvHIDiKvDKHF1fUkJw20Eg0EiCZTjlkm7g-Uw3vHdESEwNVUv8O43Hg60yvk3Ky8c7k-blVxoD1GRcmLiayLoYRbpYLYyiyYgHZXkdeXLDll2DVjnjVT8RaQqG_EBlZRMkMKHX-FLmwFwmA0nM9PSaz9jQqk8ostxB_Qyl8lsTJ4UzviPfi8MS_f66s6vCL1_JOg2aBiyVTjy_d_Xk6LS7K6T8-5wtuJsz7TTSFzmSsrkrpMap1t2RDmzbNdYiTna0S0CAVWtoS8pZOr_MxUpfvEvrFrcS_EJfg37XzWnT5djVZGcpIs9xYGCechoH6t6Vptn4hYgBBmxUbPfl_LiCU0qevJeyd6rNbg-_23tX7owRUR1GzLBov2o4FRI5A2A2xuP6unNdLWoXOSc0DY5rupToQbj4DjYK1cbeCbvJcGi6MadRaxSRushhRyhhF1ugdwOj7VRPw_m41VR1pm5S4MWuPIWnSUNDgULkFRKKs4XUJLmon77AHlDHvymYVuNFEBXmoWdcvqakcsq60D7irlsmmFiyyg\",\n       \"block_hash\": \"LUIt2kLzASel09V0VhYQWd4cyrNtTW_QVqOXakuuIZLALWE87t88LQjCZl9aA9XV\"\n     },\n     {\n       \"timestamp\": 1648520642,\n       \"transaction_hash\": \"UygVPWgsvFYJnie_VmFXq4sXkq_48AxMQ2AuGTWWwVM\",\n       \"block\": 902106,\n       \"from\": \"iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys\",\n       \"to\": \"4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o\",\n       \"value\": \"263.746368279452\",\n       \"gas_price\": \"0.000000731880\",\n       \"date\": \"29/03/2022\",\n       \"time\": \"07:54:02\",\n       \"signature\": \"fLsUf_CNzFi2uRje-L4lRd2d4uDAuoZkml9XUn4dyZ4aPsEQZHOMPLuwT3w2nubO0PHvIdPPNPmvjQtcCsc9BIhjXPJWNT3mig03l9s66x1BWaikkbKPYhQ5AF457AhEwqVkXTDARMWSURc3rbjhCAzeHwnwNGmkDd9CS3OGLwfboJa_MArbArzIgz80cuBZ6LCtAWz1xzZ_4TZycKrbhhrXpjeGkYrYxpNJSSK8gaKJTnln2Nb24JkprNtSJtTnmdrg4_iyDbHyj2kYopDtNXOhwx2Q6QqjgmxRC35z5F-QqCwlzJRBQsNkNNEjsszI4klfenQCa9slnCukPuPW1gVzV6RmzYcXApHL_M8ZSF38qCMok67qhbPAnl0psv1Vkz9lXBTixA26UVg4fJRALGxsu5jp3dxbKmZCDWZciSXctjjYj1CAyXcPY-UDkdWleOAAKUFUvfs8G2S9JeNwO-g3J_VOticujYgB6Aypac8LJFAiBpRAZP8tspqsZBDXxw3X0u9s3mk715mIWLDExhg6D38LD75Ve2XeM1iDEJ19DBfeom3kHoX3gP3NPIYMuPqMw1b9nliTQGBNkswP-kNqurGLooiFh_vKQsRKCeHeN1sdiaaVGKZ6DteEEl7ETcWZPh3Grmi0gDVexWj7_prnGCBtESMKCkkAlY5UyNg\",\n       \"block_hash\": \"6hC5-XX2FQYHNgxx_2_fXGLF8rOt5JJXify0CJk2NzzeXrNKB_B_6HJn1RKH0Fpi\"\n     }\n   ]\n }\n
"},{"location":"tools/dojima-faas/transactiondetails/#get-bitcoin","title":"GET Bitcoin","text":"
https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet\n

Returns list of transactions done by an address for bitcoin.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_1","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_1","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description address Required: Public address of the user to which transactions history to be displayed. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions."},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_1","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet' \\\n    --header 'X-API-KEY: ****************'\n

Java Script

  var myHeaders = new Headers();\n  myHeaders.append(\"X-API-KEY\", \"****************\");\n\n  var requestOptions = {\n    method: 'GET',\n    headers: myHeaders,\n    redirect: 'follow'\n  };\n\n  fetch(\"https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet\", requestOptions)\n    .then(response => response.text())\n    .then(result => console.log(result))\n    .catch(error => console.log('error', error));\n

``` json

{ \u201ctxs\u201d: [ { \u201ctransaction_hash\u201d: \u201c8f035c2dbfbf459e34a9d480d1881095225c9d0801901b9387f2cd4b7533f16b\u201d, \u201cblock\u201d: 2311311 }, { \u201ctransaction_hash\u201d: \u201cf51dd2de32005d1289feef06d1ae37da08611f4755210ac8f3545a4cd9de27d8\u201d, \u201cblock\u201d: 2287294 }, { \u201ctransaction_hash\u201d: \u201c86809c56e572ec254a87fe3eafa8acc44b9d380dce7677f95662a6901034e071\u201d, \u201cblock\u201d: 2286923 }, { \u201ctransaction_hash\u201d: \u201cd5b0fe15206e3895222b9453891b625b5fa0847cb138d5e43755aac770de9b39\u201d, \u201cblock\u201d: 2286923 }, { \u201ctransaction_hash\u201d: \u201c6f8f8ace22a5f20582b26d64f9fabf964af2001350cab8379ef86d4b58649732\u201d, \u201cblock\u201d: 2286587 }, { \u201ctransaction_hash\u201d: \u201c5529b297e8d29bfbb1b5916ae8dca461d852a17f88d5fa78828314830c3007db\u201d, \u201cblock\u201d: 2285931 }, { \u201ctransaction_hash\u201d: \u201c2a2731428b3bd122d214e65e68521f88342463f02a11d612c682b4e49387f116\u201d, \u201cblock\u201d: 2285906 } ] }

 ```\n
"},{"location":"tools/dojima-faas/transactiondetails/#get-ethereum","title":"GET Ethereum","text":"
https://faas-test.dojima.network/dojima-faas/v1/txs/history/ethereum?address=0x0577e1E35C4f30cA8379269B7Fd85cBCE7F084f4&network=testnet\n

Returns list of transactions done by an address for ethereum.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_2","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_2","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description address Required: Public address of the user to which transactions history to be displayed. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions. limit Optional. Default 100. Number of transactions to be displayed per call. sort Optional. Default \u2018desc\u2019. Display of transactions order asc or desc. startBlock Optional. Default 0. Start block number to display transactions from. endBlock Optional. Default 99999999. End block number to display transactions until. page Optional. Default 1. Transactions page number."},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_2","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet' \\\n  --header 'X-API-KEY: ****************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"****************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
{\n   \"txs\": [\n     {\n       \"transaction_hash\": \"8f035c2dbfbf459e34a9d480d1881095225c9d0801901b9387f2cd4b7533f16b\",\n       \"block\": 2311311\n     },\n     {\n       \"transaction_hash\": \"f51dd2de32005d1289feef06d1ae37da08611f4755210ac8f3545a4cd9de27d8\",\n       \"block\": 2287294\n     },\n     {\n       \"transaction_hash\": \"86809c56e572ec254a87fe3eafa8acc44b9d380dce7677f95662a6901034e071\",\n       \"block\": 2286923\n     },\n     {\n       \"transaction_hash\": \"d5b0fe15206e3895222b9453891b625b5fa0847cb138d5e43755aac770de9b39\",\n       \"block\": 2286923\n     },\n     {\n       \"transaction_hash\": \"6f8f8ace22a5f20582b26d64f9fabf964af2001350cab8379ef86d4b58649732\",\n       \"block\": 2286587\n     },\n     {\n       \"transaction_hash\": \"5529b297e8d29bfbb1b5916ae8dca461d852a17f88d5fa78828314830c3007db\",\n       \"block\": 2285931\n     },\n     {\n       \"transaction_hash\": \"2a2731428b3bd122d214e65e68521f88342463f02a11d612c682b4e49387f116\",\n       \"block\": 2285906\n     }\n   ]\n }\n
"},{"location":"tools/dojima-faas/transactiondetails/#get-solana","title":"GET Solana","text":"
https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet\n

Returns list of transactions done by an address for solana.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_3","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_3","title":"Params","text":"

Note

Public address of the respective tokens were generated:

  • Bitcoin
  • Arweave
  • Ethereum
  • Solana
Parameter Description address Required: Public address of the user to which transactions history to be displayed. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions. offset Optional. Default 100. Number of transactions to be displayed per call. beforeHash Optional. Default null. Search list of txs backwards before hash untilHash Optional. Default null. Search list of txs until hash"},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_3","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet' \\\n    --header 'X-API-KEY: *********************'\n

Java Script

  var myHeaders = new Headers();\n  myHeaders.append(\"X-API-KEY\", \"*********************\");\n\n  var requestOptions = {\n    method: 'GET',\n    headers: myHeaders,\n    redirect: 'follow'\n  };\n\n  fetch(\"https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet\", requestOptions)\n    .then(response => response.text())\n    .then(result => console.log(result))\n    .catch(error => console.log('error', error));\n
{\n   \"txs\": [\n     {\n       \"transaction_hash\": \"PGgVXU6HCwtQf6td5niURcYtNHru4YWZgWBNBBS1pg2uUcSwcBEUFUTqmNaFbMCdbKfsqTPCwG7CHmKquoeREsH\",\n       \"block\": 150376165,\n       \"date\": \"25/07/2022\",\n       \"time\": \"14:17:52\"\n     },\n     {\n       \"transaction_hash\": \"2eYrMHzEHVtGf5XtCfvzi3NFNXA4o8tmH8UBUrE4pPT9VigWHtXo7ttDAbTWjJp3mDan7cuBW5BtCV2UD1Nzn684\",\n       \"block\": 149736491,\n       \"date\": \"22/07/2022\",\n       \"time\": \"18:51:56\"\n     },\n     {\n       \"transaction_hash\": \"2irwfmujx2BWsWEWfwcXwV3dZqoiYtn7HMNBF13z33QngNpF1JiifsE3Nuw6gJKxBbpERhf2WLpdg2ZfDE2EevU2\",\n       \"block\": 149428445,\n       \"date\": \"21/07/2022\",\n       \"time\": \"10:21:40\"\n     },\n     {\n       \"transaction_hash\": \"3ZAhtNmTtx4vXFYmPqKbVZrgHaydhrFPZ8TGFZvLfh9SMrooVyEtXVrADidgt7kHVFRZQtMctA4yqmz5kLRR5EDa\",\n       \"block\": 149317976,\n       \"date\": \"20/07/2022\",\n       \"time\": \"22:42:38\"\n     },\n     {\n       \"transaction_hash\": \"3Gof6XhyeqgEW3wYV7DZCixom4zmRn3n6idn95fHJtWV1EAi3zP2cWq7AfRvfRpkDMmbA1FGm3bf6mMC411Yhhy5\",\n       \"block\": 149260715,\n       \"date\": \"20/07/2022\",\n       \"time\": \"16:39:47\"\n     }\n   ]\n }\n
"},{"location":"tools/dojima-faas/transactiondetails/#hash-data","title":"Hash data","text":"

Returns transaction details by hash based on respective token and network.

"},{"location":"tools/dojima-faas/transactiondetails/#get-arweave_1","title":"GET Arweave","text":"
https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet\n

Returns transaction details by hash for arweave.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_4","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_4","title":"Params","text":"Parameter Description hash Required. Transaction hash to display in detail about the transaction. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions."},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_4","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet' \\\n    --header 'X-API-KEY: ******************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"******************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
  {\n     \"transaction_hash\": \"3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac\",\n     \"from\": \"1BmeoGRnPXOv2eyl5CnccIPBrD0axEPQBal3NuSJCvI\",\n     \"to\": \"MBB9dcPWUG_t75ezcBwt7u3C0vCyu4tuwxjstlCpvIE\",\n     \"value\": 12734.9,\n     \"gas_price\": \"0.000000862848\",\n     \"signature\": \"K61Z7EDckRRyxY_dRRd3cy_6P72fwCEkifl1QQp9cOxXmhSSMKJcIESwYM_6jFT-XEMVGqDWXTrG6sKRp4KhvietgTV0Bk09GSMMjtDZb7SFqW-uDo6ivL4UjV_9fFYqzWuD7QU5NQbZvNXHm-Lea6tQ6_Rod2nLMiBsazWoy7kV6JSQVP1hZeIcAthc4wPgUcolTqo7zQ2a9xV0V8ClsmaqzNorUaztdUghAKBXJWmipwO-W0xhWnQlXFmE_QvikO8OI2b3YvsaOMaVdMdtI4cvUlcXmYW0xZXbQ6sTt4K3b9mXUWg5CNWasBi_d_zGY8jo6uczn6JJsqjA5dc5rtIZdJk3iBOEKm_WTyHAC2Q8Zac6CVKwjOW9zZ63znqEX0RHbUHdT9TtFme14NaYjLH6oS_KT2mi3BoCy39JBcCiprmbsWjlaqVicoJKdhPebS4KlXx3PLyxPP9EfbhopQ3YO55lI6tVp37R4LvHnekgmebjpwAK7g-N_RTG3HX_qCAltaayVMdVpn0zaYo_rYSTcfNhlN5emAF4PyeyLaOEc-5dXUQoidKE29T-ijRPr95cDEX205rmd8tpHsWq1bDyqlVsyvWKgHjffj8KbPAWUvEfONj3GD2IsaHEvYn6KFPQ5UV-WN4lxOWWHnnEhHZxXzirDjhFjkC2dJ3MjRQ\"\n   }\n
"},{"location":"tools/dojima-faas/transactiondetails/#get-bitcoin_1","title":"GET Bitcoin","text":"
https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet\n

Returns transaction details by hash for bitcoin.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_5","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_5","title":"Params","text":"Parameter Description hash Required. Transaction hash to display in detail about the transaction. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions."},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_5","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet' \\\n--header 'X-API-KEY: *******************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"*******************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
 {\n   \"txid\": \"40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84\",\n   \"size\": 245,\n   \"version\": 2,\n   \"locktime\": 0,\n   \"fee\": 0.00028386,\n   \"inputs\": [\n     {\n       \"coinbase\": false,\n       \"txid\": \"a10a458b4816dd38d5104db5b493519801faa56bfcb30cbcfc0afbe7f1851397\",\n       \"output\": 2,\n       \"sigscript\": \"\",\n       \"sequence\": 4294967295,\n       \"pkscript\": \"00143b8b9de28b699d8f3621bf0383fd617b65b84f0a\",\n       \"value\": 61755,\n       \"address\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n       \"witness\": [\n         \"3044022030820c9664c5244a1e285aa1c77f485e7dfad9ff656ac05ec5cc98203c52d46602201eddb2f9f063f4611656dcee1c203fda42933dc7e6eb970355867da1c43f4a1701\",\n         \"025cfbe662e8c3e660094116f94d3020f30787c8252a62b32088464e65cf700e8c\"\n       ]\n     }\n   ],\n   \"outputs\": [\n     {\n       \"address\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n       \"pkscript\": \"00143b8b9de28b699d8f3621bf0383fd617b65b84f0a\",\n       \"value\": 317,\n       \"spent\": false,\n       \"spender\": null\n     },\n     {\n       \"address\": null,\n       \"pkscript\": \"6a0c535741503a4254432e425443\",\n       \"value\": 0,\n       \"spent\": false,\n       \"spender\": null\n     },\n     {\n       \"address\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n       \"pkscript\": \"00143b8b9de28b699d8f3621bf0383fd617b65b84f0a\",\n       \"value\": 33052,\n       \"spent\": false,\n       \"spender\": null\n     }\n   ],\n   \"block\": {\n     \"height\": 2252852,\n     \"position\": 3\n   },\n   \"deleted\": false,\n   \"timestamp\": \"Tue, 31 May 2022 14:49:29 GMT\",\n   \"rbf\": false,\n   \"weight\": 653,\n   \"from\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n   \"fromValue\": 0.00061755,\n   \"to1\": \"tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp\",\n   \"to1Value\": 0.00000317,\n   \"to2\": null,\n   \"to2Value\": 0\n }\n
"},{"location":"tools/dojima-faas/transactiondetails/#get-solana_1","title":"GET Solana","text":"
https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=34RSHscH1t8vgfBjmrtaSbWwMb514ACX9wgXniq6FkjYU9dvqnYJxrMuhnbJWYpekQt1NJpHPo2yroFFmqTMUkFX&network=devne\n

Returns transaction details by hash for solana.

"},{"location":"tools/dojima-faas/transactiondetails/#headers_6","title":"HEADERS","text":"

Doesn\u2019t have one? Navigate to \u201cUser->Create user\u201d endpoint and get one. Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Note

Note: Never share, disclouse or save \u2018apikey\u2019 publicly.

Parameter Description X-API-KEY Required: Api Key of the user for endpoint to generate result"},{"location":"tools/dojima-faas/transactiondetails/#params_6","title":"Params","text":"Parameter Description hash Required. Transaction hash to display in detail about the transaction. network Required: Default \u2018mainnet\u2019. Arweave doesn\u2019t have \u2018testnet\u2019 explorer to display transactions. state Optional. Default \u2018confirmed\u2019. Either \u2018confirmed\u2019 or \u2018finality\u2019\u2018"},{"location":"tools/dojima-faas/transactiondetails/#example-request-and-response_6","title":"Example Request and Response","text":"REQUESTResponse

cURL Commands

 curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=2dQaVetThxgW4v3qn2aPVa5cNQ21HgeMYHrSq7G2sxS4rFn25f9PpjjvUBdVzJdqWYbsMV7AY6x8M653DJeGdPuu&network=devnet' \\\n --header 'X-API-KEY: **********************'\n

Java Script

var myHeaders = new Headers();\nmyHeaders.append(\"X-API-KEY\", \"**********************\");\n\nvar requestOptions = {\n  method: 'GET',\n  headers: myHeaders,\n  redirect: 'follow'\n};\n\nfetch(\"https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=2dQaVetThxgW4v3qn2aPVa5cNQ21HgeMYHrSq7G2sxS4rFn25f9PpjjvUBdVzJdqWYbsMV7AY6x8M653DJeGdPuu&network=devnet\", requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));\n
   {\n     \"timeStamp\": 1654094563,\n     \"gasFee\": 0.000005,\n     \"amount\": 0.01,\n     \"status\": \"\",\n     \"block\": 138189622,\n     \"from\": \"DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS\",\n     \"to\": \"71RGPwytVSNgT9i5RJhwvt7mMSahqxEYFat43ijZ8hbU\",\n     \"recentBlockHash\": \"4dYWo3CgRGvjjxXgrgFo8wVYXRZuS8UCam5Ps7NM4BKg\",\n     \"instructionData\": \"3Bxs4NN8M2Yn4TLb\"\n   }\n
"},{"location":"tools/wallet/","title":"Create Account","text":"

Dojima wallet lets you organise the layer1 tokens in one place with just one seed phrase. Wallet also provides latest prices, 24 hours statistics, blockchain info, transfer tokens, transaction history, variable gas rates for transactions. We are supporting Arweave, Bitcoin, Binance, Cosmos, Ethereum, Polkadot, Solana chains.Go to Dojima Wallet by clicking here.

"},{"location":"tools/wallet/#getting-started","title":"Getting Started","text":"

To begin using the Dojima wallet, you\u2019ll first need to install our wallet extension. Follow these steps:

1. Visit the wallet page and link to \u201cConnect Wallet.\u201d

Info

Download the appropriate version of the wallet extension for your web browser (Chrome, Firefox, etc.).

2. If you don\u2019t have a seed phrase already, click on \u201cGet Started\u201d to get one.

3. In the next step you will have to create a password

Info

Make sure the password is a minimum of eight characters.

Info

This password is not saved on any server. Dojima Network will never save your passwords; this password will be on your local device, the one that you are using. The password is used to encrypt the seed phrase, which will be seen in the next step.

4. In this step, you will receive your seed phrase, which is a collection of words, typically 12 or 24, that users can choose based on their interests. For improved security, a 24-word seed phrase is suggested.

Warning

Before you proceed, save it somewhere, preferably a text file, because next time you log in, you will need to upload the seed phrase.

Info

To make things easy, we created a text file for you. Just click on \u201cproceed\u201d to download

Danger

Never reveal your seed phrase.

5. So in this step, You have to verify the seed phrase, so select the words in order from the seed phrase you copied earlier.

6. Click on \u201cconfirm\u201d

7. After installing the wallet extension, you\u2019ll need to log in to your account on the web. Just type the password, and you are good to go.

8. That\u2019s it. You are in your Dojima wallet now, and you can explore the dashboard.\u00a0

"},{"location":"tools/wallet/wallet-login/","title":"Login","text":"

To begin using the Dojima wallet, you\u2019ll first need to install our wallet extension.

1. Visit the wallet page and link to \u201cConnect Wallet.\u201d

Info

Download the appropriate version of the wallet extension for your web browser (Chrome, Firefox, etc.).

2. To login, click on \u201cimport with seed phrase.\u201d

3. In this step, you can drag and drop your seed phrase or upload a text file.

Tip

If you have registered with Dojima Wallet or if you have a seed phrase from any other wallet, you can use that seed phrase to link with Dojima Wallet.

Tip

You can enter your seed phrase manually also, but it is suggested that you upload a text file to save time.

4. In this step, you have to create a password to encrypt the seed phrase that you just uploaded.

Tip

Dojima wallet will never save your passwords it will reset every time you log out. So new password every time you log in making it more secure.

Tip

The password must be at least eight characters long.

5. After installing the wallet extension, you\u2019ll need to log in to your account on the web. Just type the password, and you are good to go.

6. That\u2019s it. You are in your Dojima wallet now, and you can explore the dashboard.\u00a0

"},{"location":"tools/wallet/wallet-swap/","title":"Swap","text":"

Users can swap any assets that are on connected chains and that have been added to the network. Users can swap from any connected asset to any other connected asset. They can also swap from any connected asset to DOJ.

"},{"location":"tools/wallet/wallet-swap/#follow-the-steps-to-perform-swap","title":"Follow the steps to perform Swap.","text":""},{"location":"tools/wallet/wallet-swap/#1-after-logging-into-wallet-navigate-to-the-swap-tab","title":"1. After logging into Wallet, navigate to the Swap tab","text":""},{"location":"tools/wallet/wallet-swap/#2-choose-the-coin-you-want-to-swap-and-enter-the-necessary-amount-now-click-on-swap","title":"2. Choose the coin you want to swap and enter the necessary amount. Now click on \u201cSwap.\u201d","text":""},{"location":"tools/wallet/wallet-swap/#3-enter-the-receipt-address-and-click-on-continue","title":"3. Enter the receipt address and click on \u201cContinue.\u201d","text":""},{"location":"tools/wallet/wallet-swap/#4-verify-the-amount-and-click-on-continue","title":"4. Verify the amount and click on \u201cContinue.\u201d","text":""},{"location":"tools/wallet/wallet-swap/#5-as-soon-as-you-click-on-continue-you-will-get-a-transaction-hash-which-can-be-used-to-check-the-status-of-the-swap-on-the-block-explorer","title":"5. As soon as you click on \u201cContinue\u201d, you will get a transaction hash, which can be used to check the status of the swap on the block explorer.\u201d","text":""},{"location":"validator/","title":"Validator","text":"Validator

Unlock the path to becoming a valued validator with our comprehensive documentation, empowering you to safeguard the integrity of our blockchain network.

Setup AWS

Step-by-step guide for configuring AWS infrastructure to become a reliable validator in our blockchain network.

"},{"location":"validator/hermesdeployment/deploying/","title":"Deploying","text":"

Deploying a HermesNode and its associated services.

"},{"location":"validator/hermesdeployment/deploying/#deploy-hermesnode-services","title":"Deploy HermesNode services","text":"

Now you have a Kubernetes cluster ready to use, you can install the HermesNode services.

Info

Helm charts are the defacto and currently easiest and simple way to package and deploy Kubernetes application. The team created different Helm charts to help to deploy all the necessary services. Please retrieve the source files from the Git repository here to follow the instructions below: https://github.com/dojimanetwork/validator-cluster-launcher

"},{"location":"validator/hermesdeployment/deploying/#requirements","title":"Requirements","text":"
  • Running Kubernetes cluster
  • Kubectl configured, ready and connected to running cluster

Info

If you came here from the Setup page, you are already good to go.

"},{"location":"validator/hermesdeployment/deploying/#steps","title":"Steps","text":"

Clone the node-launcher repo. All commands in this section are to be run inside of this repo.

git clone https://github.com/dojimanetwork/helm_charts\ncd node-launcher\ngit checkout master\n
"},{"location":"validator/hermesdeployment/deploying/#install-helm-3","title":"Install Helm 3","text":"

Install Helm 3 if not already available on your current machine:

make helm\nmake helm-plugins\n
"},{"location":"validator/hermesdeployment/deploying/#tools","title":"Tools","text":"DeployDestroy

To deploy all tools, metrics, logs management, Kubernetes Dashboard, run the command below.

make tools\n

To destroy all those resources run the command below.

make destroy-tools\n

If you are successful, you will see the following message:

If there are any errors, they are typically fixed by running the command again.

"},{"location":"validator/hermesdeployment/deploying/#deploy-hermesnode","title":"Deploy HermesNode","text":"

It is important to deploy the tools first before deploying the HermesNode services as some services will have metrics configuration that would fail and stop the HermesNode deployment.

You have multiple commands available to deploy different configurations of HermesNode. You can deploy testnet or chaosnet/mainnet. The commands deploy the umbrella chart hermesnode-stack in the background in the Kubernetes namespace hermesnode (or hermesnode-testnet for testnet) by default.

make install\n

Info

If you are intending to run all chain clients, bond in & earn rewards, you want to choose \u201cValidator\u201d.

Info

Deploying a HermesNode will take 1 day for every 3 months of ledger history, since it will validate every block. HermesNodes are \u201cfull nodes\u201d, not light clients.

If successful, you will see the following:

"},{"location":"validator/hermesdeployment/deploying/#debugging","title":"Debugging","text":"

Info

Set hermesnode to be your default namespace so you don\u2019t need to type -n hermesnode each time: kubectl config set-context \u2013current \u2013namespace=hermesnode

Use the following useful commands to view and debug accordingly. You should see everything running and active. Logs can be retrieved to find errors:

kubectl get pods -n hermesnode\nkubectl get pods --all-namespaces\nkubectl logs -f <pod> -n hermesnode\n

Kubernetes should automatically restart any service, but you can force a restart by running:

kubectl delete pod <pod> -n hermesnode\n

Warning

Note, to expedite syncing external chains, it is feasible to continually delete the pod that has the slow-syncing chain daemon (eg, binance-daemon-xxx). Killing it will automatically restart it with free resources and syncing is notably faster. You can check sync status by viewing logs for the client to find the synced chain tip and comparing it with the real-world blockheight, (\u201cxxx\u201d is your unique ID):

kubectl logs -f binance-daemon-xxx -n hermesnode\n

Info

Get real-world blockheights on the external blockchain explorers, eg: https://testnet-explorer.binance.org/

https://explorer.binance.org/

"},{"location":"validator/hermesdeployment/deploying/#chart-summary","title":"CHART SUMMARY","text":""},{"location":"validator/hermesdeployment/deploying/#hermesnode-full-stack-umbrella-chart","title":"HermesNode full stack umbrella chart","text":"
  • hermesnode: Umbrella chart packaging all services needed to run a fullnode or validator HermesNode.

This should be the only chart used to run HermesNode stack unless you know what you are doing and want to run each chart separately (not recommended).

HermesNode services:

  • hermes-daemon: HermesNode daemon
  • hermes-api: HermesNode API
  • hermes-gateway: HermesNode gateway proxy to get a single IP address for multiple deployments
  • narada: Narada service

External services:

  • binance-daemon: Binance fullnode daemon
  • bitcoin-daemon: Bitcoin fullnode daemon
  • ethereum-daemon: Ethereum fullnode daemon
  • chain-daemon: as required for supported chains
"},{"location":"validator/hermesdeployment/deploying/#tools_1","title":"Tools","text":"
  • elastic: ELK stack, deperecated. Use elastic-operator chart
  • elastic-operator: ELK stack using operator for logs management
  • prometheus: Prometheus stack for metrics
  • loki: Loki stack for logs
  • kubernetes-dashboard: Kubernetes dashboard
"},{"location":"validator/hermesdeployment/cluster-launcher/overview/","title":"Overview","text":""},{"location":"validator/hermesdeployment/cluster-launcher/overview/#cluster-launcher","title":"Cluster Launcher","text":"

Deploying a HERMESNode with Kubernetes

"},{"location":"validator/hermesdeployment/cluster-launcher/overview/#deploy-a-kubernetes-cluster","title":"Deploy a Kubernetes cluster","text":"

In order to deploy all the different services and provide a high availability environment to operate your node, Kubernetes is the preferred scheduling platform. Any production-grade Kubernetes cluster can be used to run and deploy a HERMESNode. You need your Kubernetes provider to offer external load balancers services type features. Azure, Digital Ocean, GCE, OpenStack are compatible with external load balancers.

Info

Terraform is a type of domain-specific language (DSL) used to describe code infrastructure. It is designed to make it easier to create/destroy infrastructure hosted locally or by a provider.

This Terraform deployment will deploy a Kubernetes cluster using your VPS provider credentials and EKS service. The cluster will have autoscaling capabilities, which means you don\u2019t have to deal with how many nodes you need to deploy to run your HERMESNode services.

All the default configurations used in these instructions are for a production environment with enough resources to run your HERMESNode in good conditions

Warning

LINUX/MAC is the preferred method of setup.

Windows should choose either:

  1. Deploy a HERMESNode from a Linux VPS.
  2. Use Windows Subsystem for Linux - https://docs.microsoft.com/en-us/windows/wsl/about
"},{"location":"validator/hermesdeployment/cluster-launcher/overview/#steps","title":"Steps","text":"

There are three important steps to getting your node set up, deployed and churned in.

  1. Setting up Cluster
  2. Deploying HERMESNode Services
"},{"location":"validator/hermesdeployment/cluster-launcher/overview/#repository-management","title":"Repository Management","text":"

Your repository should be organised as follows:

./hermesnode-ops\n  |./cluster-launcher\n  |./node-launcher\n
All of your set up commands are run in cluster-launcher and all of your deploying/joining/managing/leaving commands are run from node-launcher

"},{"location":"validator/hermesdeployment/cluster-launcher/overview/#running-two-or-more-nodes","title":"Running Two or More Nodes","text":"

Danger

To prevent a catastrophic mistake in handling multiple nodes, set them up on different machines, or use different user profiles on your machine, or in the least, use different repos:

./hermesnode-ops\n  |./cluster-launcher\n  |./node-launcher\n./hermesnode-ops2\n  |./cluster-launcher\n  |./node-launcher\n

All of your commands can now be run separately.

Info

It is heavily advised to not set up nodes on the same provider. Deploy 1 node on Azure, 1 node on Digital Ocean etc.

"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/","title":"Setup AWS","text":"

Setting up a Kubernetes Cluster with AWS

"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#deploy-a-kubernetes-cluster-in-aws-using-eks-service","title":"Deploy a Kubernetes cluster in AWS using EKS service.","text":""},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#requirements","title":"Requirements","text":"
  1. AWS account
  2. CLI and AWS credentials configured
  3. AWS IAM Authenticator
  4. kubectl
  5. wget (required for EKS module)

Warning

LINUX/MACI is preffered method of setup

Windows should choose either

  1. Deploy a HermesNode from a Linux VPS.
  2. Use Windows Subsystem for Linux - https://docs.microsoft.com/en-us/windows/wsl/about
"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#steps","title":"Steps","text":"

Firstly, clone and enter the cluster-launcher repository (Currently This Repo Link is Private Not Accessible By Outside Origanization). All commands in this section are to be run inside this repo.

git clone https://github.com/dojimanetwork/validator-cluster-launcher\ncd cluster-launcher\n

Then install the terraform CLI:

LINUX/MAC

Install Terraform:

brew install terraform\n
"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#aws-cli","title":"AWS CLI","text":"

In order for Terraform to run operations on your behalf, you must install and configure the AWS CLI tool. ****To install the AWS CLI, follow these instructions, or choose a package manager based on your operating system

LINUX/MAC

Use the package manager homebrew to install the AWS CLI.

```jsx\nbrew install awscli\naws configure\n```\n

Warning

You will be asked for you Personal Access Token with read/write privileges (retrieve from API Panel from the GCP web console.) API -> Tokens/Keys -> Create Token. Make sure you handle your secrets securely!

"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#aws-iam-authenticator","title":"AWS IAM Authenticator","text":"

You also must install and configure the AWS IAM Authenticator tool. To install, follow these instructions, or choose a package manager based on your operating system.

LINUX/MAC

Use the package manager homebrew to install the AWS IAM Authenticator.

brew install aws-iam-authenticator\n
"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#kubernetes-control-tool","title":"Kubernetes Control Tool","text":"

You must install and configure the Kubernetes CLI tool (kubectl). To install kubectl , follow these instructions, or choose a package manager based on your operating system.

Use the package manager homebrew to install the AWS IAM Authenticator.

LINUX/MAC

Use the package manager homebrew to install kubectl.

brew install kubernetes-cli\n
"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#wget-jq","title":"wget && jq","text":"

You also need wget and jq, follow these instructions, or choose a package manager based on your operating system.

LINUX/MAC

Use the package manager homebrew to install wget and jq Note: You most likely have these installed already.

brew install wget\nbrew install jq\n
"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#deploy-kubernetes-cluster","title":"Deploy Kubernetes Cluster","text":"

Use the commands below to deploy a DOKS cluster:

make aws\n

During the deploy, you will be asked to enter information about your cluster

  1. Name
  2. AWS Region \u2013 see valid List of Regions
  3. Confirm yes

Regions

Note: AWS EKS is not available in some regions

or manually

cd aws/\nterraform init\nterraform plan # to see the plan\nterraform apply\n

Final success message: Apply complete! Resources: 30 added, 0 changed, 0 destroyed.

Info

If you are a returning node operator and you wish to use the same node name, the Cloudwatch log files from your previous session will block this step. You need to manually delete the logs from your console: Cloudwatch / Cloudwatch Logs / Log Groups -> \u201cdelete\u201d

Info

Deploying a cluster takes ~10 minutes

"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#configure-kubectl","title":"CONFIGURE kubectl","text":"

This is done automatically during provisioning. To configure authentication from the command line, use the following command. It will get the access credentials for your cluster and automatically configure kubectl in case you need to to manually reconfigure kubectl.

make kubeconfig-aws\n

Or get your kubeconfig file manually:

(cd aws && aws eks --region $(terraform output -raw region) update-kubeconfig --name $(terraform output -raw cluster_name))\n

To verify, run this, and check the status is \u201cReady\u201d:

kubectl version\nkubectl cluster-info\nkubectl get nodes\n

You are now ready to deploy a HermeNode.

"},{"location":"validator/hermesdeployment/cluster-launcher/setup-aws/#backups-optional","title":"BACKUPS (OPTIONAL)","text":"

Once your node is running, use the following command to automatically backup the Persistent Volumes for your Kubernetes cluster. This may help in recovering your node in the event of a disaster.

Enable backups:

make aws-backups\n

Disable backups:

make aws-destroy-backups\n
"},{"location":"validator/hermesdeployment/cluster-launcher/system-requirements/","title":"System Requirements","text":"

The system requirements listed in this section are both for the Hermes node and the Dojima node.

The minimum system requirements mean you can run the nodes but the setup is not future-proof.

The recommended system requirements mean the nodes are future-proof. There is, however, no upper limit to future-proofing your nodes.

You must always run the hermes node and the dojima node on separate machines.

"},{"location":"validator/hermesdeployment/cluster-launcher/system-requirements/#minimum-system-requirements","title":"Minimum system requirements","text":"
  • RAM: 32 GB
  • CPU: 8-core
  • Storage: 2.5 TB SSD

Info

For Amazon Web Services (AWS), the equivalent of the minimum requirements instances are, with unlimited credits selected:

  • For Hermes: c5.2xlarge

  • For Dojima node: c5.4xlarge

"},{"location":"validator/hermesdeployment/cluster-launcher/system-requirements/#recommended-system-requirements","title":"Recommended system requirements","text":"
  • RAM: 64 GB
  • CPU: 16-core
  • Storage: 5 TB SSD
  • Bandwidth: 1 Gbit/s

Info

For Amazon Web Services (AWS), the equivalent of the recommended requirements instance is m5d.4xlarge.

For OVH, the equivalent of the recommended requirements instance is infra-3.

For network, expect 3-5 TB of data transferred per month.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..ab5bf07 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,378 @@ + + + + https://docs.polygon.technology/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/about-us/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/dojima-chain/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/hermes-chain/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/what-is-dojima-network/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/architecture/dojimachain/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/architecture/hermeschain/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/architecture/overview/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/architecture/contracts/inbound_state_sender/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/architecture/contracts/outbound_state_sender/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/evm/client/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/evm/hermes-bridge/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/evm/state-sender-contract/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/nonevm/arweave/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/nonevm/polkadot/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/nonevm/solana/solana-client/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/chain-clients/nonevm/solana/solana-state-sender/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/concepts/code.liberies/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/concepts/connecting.doj.chain/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/concepts/querying/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/concepts/transaction.memos/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/arweave/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/binance-becon/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/bitcoin/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/client/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/cosmos/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/crypto/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/ethereum/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/hermes/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/polkadot/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/solana/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/d11kguide/utils/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/sources/endpoints/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/sources/faucet/ + 2024-03-21 + daily + + + https://docs.polygon.technology/core/sources/transaction/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/faucet/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/quickstart/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/transactions/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/verifying-smart-contract/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/getstarted/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/MetaMask/config-dojima-on-metamask/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/MetaMask/custom-tokens/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/MetaMask/multiple-accounts/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/MetaMask/overview/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/Wallet/MetaMask/tutorial-metamask/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/contract/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/login/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/projects/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/xchain_connections/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/dashboard/new_project/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/developer-dashboard/dashboard/templates/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/sources/basic/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/sources/endpoints/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/sources/external/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/sources/faucet/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/templates/deposit_manager/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/templates/omni_chain_ERC20/ + 2024-03-21 + daily + + + https://docs.polygon.technology/developer/templates/omni_chain_NFT/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/dojima-faas/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/dojima-faas/faasaccount/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/dojima-faas/faaspricestats/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/dojima-faas/faasuser/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/dojima-faas/transactiondetails/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/wallet/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/wallet/wallet-login/ + 2024-03-21 + daily + + + https://docs.polygon.technology/tools/wallet/wallet-swap/ + 2024-03-21 + daily + + + https://docs.polygon.technology/validator/ + 2024-03-21 + daily + + + https://docs.polygon.technology/validator/hermesdeployment/deploying/ + 2024-03-21 + daily + + + https://docs.polygon.technology/validator/hermesdeployment/cluster-launcher/overview/ + 2024-03-21 + daily + + + https://docs.polygon.technology/validator/hermesdeployment/cluster-launcher/setup-aws/ + 2024-03-21 + daily + + + https://docs.polygon.technology/validator/hermesdeployment/cluster-launcher/system-requirements/ + 2024-03-21 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..4ac11cf Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/toc.py b/toc.py new file mode 100644 index 0000000..5e2b666 --- /dev/null +++ b/toc.py @@ -0,0 +1,27 @@ +# Author: Katharine Murphy +# -------------------------------------------------------------------------------------------------------------- +### INSTRUCTIONS FOR USE ### +# -------------------------------------------------------------------------------------------------------------- +# Originally created for the output of solidity-docgen plugin. +# +# Feel free to improve it. It may need tweaking as I haven't used it in a while. +# +# Paste the markdown files into the relevant folder. +# Run the script from the root `docs` and add the path to list_files(path_parameter). +# Paste the resulting output directly into the `mkdocs.yaml` file at the relevant spot. +# -------------------------------------------------------------------------------------------------------------- + +import os + +def list_files(startpath): + for root, dirs, files in sorted(os.walk(startpath)): + level = root.replace(startpath, '').count(os.sep) + indent = ' ' * 4 * (level) + print(' {}- {}:'.format(indent, os.path.basename(root).capitalize()),) + subindent = ' ' * 4 * (level + 1) + for f in sorted(files): + title = str(f).replace('.md', '') + filepath = os.path.join(root, f) + print(' {}- {}: {}'.format(subindent, title, filepath)) + +list_files("miden") \ No newline at end of file diff --git a/tools/dojima-faas/faasaccount/index.html b/tools/dojima-faas/faasaccount/index.html new file mode 100644 index 0000000..aad786c --- /dev/null +++ b/tools/dojima-faas/faasaccount/index.html @@ -0,0 +1,3640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Account - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + +

Account

+ +

These endpoints return details such as public address from seed phrase/mnemonic, balance of the respective input token.

+

GET Address

+
 https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn&network=testnet
+
+

Returns public addresses of the provided seed phrase of the user and network type.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYc226c9df7eb08c82c4f4c22266dd
Required: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
mnemonicletter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn
Required: Seed phrase of the user to generate addresses.
networktestnet
Required: ‘mainnet or testnet or devnet’
+

Example Request and Response

+
+
+
+

cURL. +

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet' \
+--header 'X-API-KEY: ********************'
+

+

Java Script.

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "********************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
 {
+   "arweave": "7zzxJgYHgDlaURc3xt3wvLITPp6I8oIpYj_yg_xirb4",
+   "bitcoin": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+   "ethereum": "0x0577e1E35C4f30cA8379269B7Fd85cBCE7F084f4",
+   "solana": "DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS"
+ }
+
+
+
+
+

GET Token Balance

+

https://faas-test.dojima.network/dojima-faas/v1/account/balance?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&asset=bitcoin&network=testnet
+
+Returns balance of the token based on inputs.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYc226c9df7eb08c82c4f4c22266dd
Required: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
mnemonicletter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn
Required: Seed phrase of the user to generate addresses.
networktestnet
Required: ‘mainnet or testnet or devnet’
+

Example Request and Response

+
+
+
+

cURL. +

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet' \
+--header 'X-API-KEY: ********************'
+

+

Java Script.

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "********************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=******************************************************&network=testnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
 {
+   "key": "6",
+   "name": "robot",
+   "email":  "robot@gmail.com",
+   "apiKey": "**********************",
+   "plan":"monthly",
+   "limit":"100000",
+   "createdAt": "2022-08-04T05:02:19.000Z",
+   "validUntil": "2022-09-03T05:02:19.623Z",
+   "updatedAt": "2022-08-04T05:02:19.000Z"
+ }
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/dojima-faas/faaspricestats/index.html b/tools/dojima-faas/faaspricestats/index.html new file mode 100644 index 0000000..4c9d6e7 --- /dev/null +++ b/tools/dojima-faas/faaspricestats/index.html @@ -0,0 +1,4549 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Prices Stats - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Price Stats

+ +

These endpoints return details such as token latest prices, stats, history based particular date or past n days or in between certain dates.

+

GET Token latest price

+
https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana
+
+

Returns token current price, market_cap, volume, supply, data related to ath (all time high), atl (all time low).

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
mnemonicRequired: Seed phrase of the user to generate addresses.
networkRequired: ‘mainnet or testnet or devnet’
+

Example Request and Response

+
+
+
+

cURL +

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana' \
+--header 'X-API-KEY: ****************'
+

+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "****************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/prices/latest/token?tokenName=solana", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
 {
+   "current_price": 39.19,
+   "market_cap": 13566176494,
+   "total_volume": 1491902699,
+   "circulating_supply": 346652190.616162,
+   "total_supply": 508180963.57,
+   "max_supply": null,
+   "ath": 259.96,
+   "ath_change_percentage": -84.96585,
+   "ath_date": "Sat, 06 Nov 2021 21:54:35 GMT",
+   "atl": 0.500801,
+   "atl_change_percentage": 7704.02799,
+   "atl_date": "Mon, 11 May 2020 19:35:23 GMT"
+ }
+
+
+
+
+

GET Token latest stats

+

https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC
+
+Returns token stats related to addresses, blocks, transactions, supply, etc.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Token list:

+
    +
  • btc
  • +
  • ar
  • +
  • eth
  • +
  • sol
  • +
+
+ + + + + + + + + + + + + +
ParameterDescription
tokenRequired: Token id to retrieve stats related to addresses, blocks, transactions, supply, etc.
+

Example Request and Response

+
+
+
+

cURL Commands +

curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC' \
+--header 'X-API-KEY: **********************'
+

+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "**********************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/prices/latest/stats?token=BTC", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
     {
+ "id": 1182,
+ "time": 1659484800,
+ "symbol": "BTC",
+ "partner_symbol": "BTC",
+ "zero_balance_addresses_all_time": 985144574,
+ "unique_addresses_all_time": 1027159686,
+ "new_addresses": 417758,
+ "active_addresses": 979238,
+ "average_transaction_value": 15.41044161368356,
+ "block_height": 747864,
+ "hashrate": 199187870.17167962,
+ "difficulty": 27692567959233.59,
+ "block_time": 597.1180555555553,
+ "block_size": 1292170,
+ "current_supply": 19111662,
+ "transaction_count": 282037,
+ "transaction_count_all_time": 753969557,
+ "large_transaction_count": 18486
+ }
+
+
+
+
+

GET History by date

+

https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=05-07-2021
+
+Returns token price, market_cap and total_volume on a particular date.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Token list:

+
    +
  • bitcoin
  • +
  • arweave
  • +
  • ethereum
  • +
  • solana
  • +
  • usd-coin
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
tokenNameRequired: token price, market_cap and total_volume on a particular date.
daysRequired. DD-MM-YYYY format date
+

Example Request and Response

+
+
+
+

cURL Commands

+
  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=22-05-2022' \
+--header 'X-API-KEY: *******************'
+
+

Java Script

+
  var myHeaders = new Headers();
+  myHeaders.append("X-API-KEY", "*******************");
+
+  var requestOptions = {
+    method: 'GET',
+    headers: myHeaders,
+    redirect: 'follow'
+  };
+
+  fetch("https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=22-05-2022", requestOptions)
+    .then(response => response.text())
+    .then(result => console.log(result))
+    .catch(error => console.log('error', error));
+
+
+
+
   [
+     {
+       "current_price": 29491.507947760598,
+       "market_cap": 561696351558.8424,
+       "total_volume": 13561006428.368963
+     }
+   ]
+
+
+
+
+

GET GET History by days

+

https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20
+
+Returns token prices, market_cap and total_volume for mentioned no. of days. Minutely data for 1 day, hourly data for 1.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Token list:

+
    +
  • bitcoin
  • +
  • arweave
  • +
  • ethereum
  • +
  • solana
  • +
  • usd-coin
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
tokenNameRequired: token price, market_cap and total_volume on a particular date.
dateRequired. Token prices, market_cap and total_volume for mentioned no. of days. Minutely data for 1 day, hourly data for 1<days<=10 and daily data for 10 < days
+

Example Request and Response

+
+
+
+

cURL Commands

+
  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20' \
+  --header 'X-API-KEY: *******************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "*******************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/prices/history/days?tokenName=bitcoin&days=20", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
 [
+   {
+     "prices": [
+       {
+         "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+         "price": 20794.811981436706
+       },
+       {
+         "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+         "price": 21193.08334336837
+       },
+       {
+         "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+         "price": 20824.36275165164
+       },
+       {
+         "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+         "price": 22395.365383103952
+       },
+       {
+         "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+         "price": 23366.90769792785
+       },
+       {
+         "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+         "price": 23313.296731959555
+       },
+       {
+         "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+         "price": 23155.207555248304
+       },
+       {
+         "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+         "price": 22696.902754290055
+       },
+       {
+         "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+         "price": 22506.199573628986
+       },
+       {
+         "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+         "price": 22613.719208248454
+       },
+       {
+         "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+         "price": 21330.295450788173
+       },
+       {
+         "date": "Wed, 27 Jul 2022 00:00:00 GMT",
+         "price": 21235.612316085775
+       },
+       {
+         "date": "Thu, 28 Jul 2022 00:00:00 GMT",
+         "price": 22908.884260468687
+       },
+       {
+         "date": "Fri, 29 Jul 2022 00:00:00 GMT",
+         "price": 23822.067597823116
+       },
+       {
+         "date": "Sat, 30 Jul 2022 00:00:00 GMT",
+         "price": 23847.58331873861
+       },
+       {
+         "date": "Sun, 31 Jul 2022 00:00:00 GMT",
+         "price": 23653.459549430798
+       },
+       {
+         "date": "Mon, 01 Aug 2022 00:00:00 GMT",
+         "price": 23379.70052509082
+       },
+       {
+         "date": "Tue, 02 Aug 2022 00:00:00 GMT",
+         "price": 23333.749243312184
+       },
+       {
+         "date": "Wed, 03 Aug 2022 00:00:00 GMT",
+         "price": 23053.846847482677
+       },
+       {
+         "date": "Thu, 04 Aug 2022 00:00:00 GMT",
+         "price": 22860.42098438317
+       },
+       {
+         "date": "Thu, 04 Aug 2022 10:25:46 GMT",
+         "price": 22950.523475823156
+       }
+     ],
+     "market_cap": [
+       {
+         "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+         "price": 397285233065.65533
+       },
+       {
+         "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+         "price": 404705642580.89075
+       },
+       {
+         "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+         "price": 397660610560.5498
+       },
+       {
+         "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+         "price": 425756736660.6174
+       },
+       {
+         "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+         "price": 445889013251.1064
+       },
+       {
+         "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+         "price": 446130012149.91077
+       },
+       {
+         "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+         "price": 442379611364.02734
+       },
+       {
+         "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+         "price": 433485926857.3929
+       },
+       {
+         "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+         "price": 429803379587.55133
+       },
+       {
+         "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+         "price": 433819662321.5266
+       },
+       {
+         "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+         "price": 407480099599.8142
+       },
+       {
+         "date": "Wed, 27 Jul 2022 00:00:00 GMT",
+         "price": 405692421501.52716
+       },
+       {
+         "date": "Thu, 28 Jul 2022 00:00:00 GMT",
+         "price": 437193517021.8447
+       },
+       {
+         "date": "Fri, 29 Jul 2022 00:00:00 GMT",
+         "price": 454806622614.75885
+       },
+       {
+         "date": "Sat, 30 Jul 2022 00:00:00 GMT",
+         "price": 459609388579.5554
+       },
+       {
+         "date": "Sun, 31 Jul 2022 00:00:00 GMT",
+         "price": 451726702392.36206
+       },
+       {
+         "date": "Mon, 01 Aug 2022 00:00:00 GMT",
+         "price": 447051019373.1847
+       },
+       {
+         "date": "Tue, 02 Aug 2022 00:00:00 GMT",
+         "price": 445958949620.3002
+       },
+       {
+         "date": "Wed, 03 Aug 2022 00:00:00 GMT",
+         "price": 440954684720.7478
+       },
+       {
+         "date": "Thu, 04 Aug 2022 00:00:00 GMT",
+         "price": 437035641450.2815
+       },
+       {
+         "date": "Thu, 04 Aug 2022 10:25:46 GMT",
+         "price": 438396573850.57587
+       }
+     ],
+     "total_volume": [
+       {
+         "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+         "price": 46542248374.33238
+       },
+       {
+         "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+         "price": 42051101694.797554
+       },
+       {
+         "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+         "price": 29615794461.49923
+       },
+       {
+         "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+         "price": 58636734705.48306
+       },
+       {
+         "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+         "price": 57338223361.51413
+       },
+       {
+         "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+         "price": 40775718993.79776
+       },
+       {
+         "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+         "price": 63224249257.511284
+       },
+       {
+         "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+         "price": 40304373301.41499
+       },
+       {
+         "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+         "price": 42519262113.1533
+       },
+       {
+         "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+         "price": 33108916659.05373
+       },
+       {
+         "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+         "price": 42667548128.932236
+       },
+       {
+         "date": "Wed, 27 Jul 2022 00:00:00 GMT",
+         "price": 53995620035.18145
+       },
+       {
+         "date": "Thu, 28 Jul 2022 00:00:00 GMT",
+         "price": 54498281944.45157
+       },
+       {
+         "date": "Fri, 29 Jul 2022 00:00:00 GMT",
+         "price": 55609627980.6571
+       },
+       {
+         "date": "Sat, 30 Jul 2022 00:00:00 GMT",
+         "price": 41089335195.63975
+       },
+       {
+         "date": "Sun, 31 Jul 2022 00:00:00 GMT",
+         "price": 62102072346.807785
+       },
+       {
+         "date": "Mon, 01 Aug 2022 00:00:00 GMT",
+         "price": 31786729326.443203
+       },
+       {
+         "date": "Tue, 02 Aug 2022 00:00:00 GMT",
+         "price": 44489771146.510735
+       },
+       {
+         "date": "Wed, 03 Aug 2022 00:00:00 GMT",
+         "price": 35151096516.75639
+       },
+       {
+         "date": "Thu, 04 Aug 2022 00:00:00 GMT",
+         "price": 41334593234.075066
+       },
+       {
+         "date": "Thu, 04 Aug 2022 10:25:46 GMT",
+         "price": 23908600834.73234
+       }
+     ]
+   }
+ ]
+
+
+
+
+

GET History by date range

+

https://faas-test.dojima.network/dojima-faas/v1/prices/history/date?tokenName=bitcoin&date=05-07-2021
+
+Returns token price, market_cap and total_volume for date range. 5 minute interval data data if date difference 1 day, hourly data if date difference is between 1 and 90 and daily data if date difference is more than 90.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Token list:

+
    +
  • bitcoin
  • +
  • arweave
  • +
  • ethereum
  • +
  • solana
  • +
  • usd-coin
  • +
+
+ + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
tokenNameRequired: token price, market_cap and total_volume on a particular date.
fromDateRequired: YYYY-MM-DD format date
thruDateRequired. YYYY-MM-DD format date
+

Example Request and Response

+
+
+
+

cURL Commands

+
  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/prices/history/date/range?tokenName=bitcoin&fromDate=2022-05-01&thruDate=2022-05-11' \
+  --header 'X-API-KEY: *****************'
+
+

Java Script

+
  var myHeaders = new Headers();
+  myHeaders.append("X-API-KEY", "*****************");
+
+  var requestOptions = {
+    method: 'GET',
+    headers: myHeaders,
+    redirect: 'follow'
+  };
+
+  fetch("https://faas-test.dojima.network/dojima-faas/v1/prices/history/date/range?tokenName=bitcoin&fromDate=2022-05-01&thruDate=2022-05-31", requestOptions)
+    .then(response => response.text())
+    .then(result => console.log(result))
+    .catch(error => console.log('error', error));
+
+
+
+
 {
+   "prices": [
+     {
+       "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+       "price": 1234.0991389763224
+     },
+     {
+       "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+       "price": 1355.04564021949
+     },
+     {
+       "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+       "price": 1344.7202840019017
+     },
+     {
+       "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+       "price": 1570.6589588642053
+     },
+     {
+       "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+       "price": 1542.6298214332235
+     },
+     {
+       "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+       "price": 1527.4139307593093
+     },
+     {
+       "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+       "price": 1576.8252394976823
+     },
+     {
+       "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+       "price": 1536.124922238913
+     },
+     {
+       "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+       "price": 1552.4964891908746
+     },
+     {
+       "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+       "price": 1601.2079670127046
+     },
+     {
+       "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+       "price": 1450.4822852139405
+     },
+     {
+       "date": "Tue, 26 Jul 2022 04:59:49 GMT",
+       "price": 1431.2771658285428
+     }
+   ],
+   "market_cap": [
+     {
+       "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+       "price": 147677565536.3019
+     },
+     {
+       "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+       "price": 161839496479.48514
+     },
+     {
+       "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+       "price": 161551223982.244
+     },
+     {
+       "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+       "price": 187518878564.43118
+     },
+     {
+       "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+       "price": 184299116474.0005
+     },
+     {
+       "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+       "price": 183383314168.63928
+     },
+     {
+       "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+       "price": 188807814065.77225
+     },
+     {
+       "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+       "price": 183933879174.97644
+     },
+     {
+       "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+       "price": 185766674503.14
+     },
+     {
+       "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+       "price": 192833875418.8718
+     },
+     {
+       "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+       "price": 176371406952.78534
+     },
+     {
+       "date": "Tue, 26 Jul 2022 04:59:49 GMT",
+       "price": 171509003635.7274
+     }
+   ],
+   "total_volume": [
+     {
+       "date": "Sat, 16 Jul 2022 00:00:00 GMT",
+       "price": 16817194904.2499
+     },
+     {
+       "date": "Sun, 17 Jul 2022 00:00:00 GMT",
+       "price": 19025831554.91271
+     },
+     {
+       "date": "Mon, 18 Jul 2022 00:00:00 GMT",
+       "price": 15797648344.457474
+     },
+     {
+       "date": "Tue, 19 Jul 2022 00:00:00 GMT",
+       "price": 26437290054.27533
+     },
+     {
+       "date": "Wed, 20 Jul 2022 00:00:00 GMT",
+       "price": 27749085857.707005
+     },
+     {
+       "date": "Thu, 21 Jul 2022 00:00:00 GMT",
+       "price": 21728126383.56131
+     },
+     {
+       "date": "Fri, 22 Jul 2022 00:00:00 GMT",
+       "price": 19411405082.967407
+     },
+     {
+       "date": "Sat, 23 Jul 2022 00:00:00 GMT",
+       "price": 18084368731.242767
+     },
+     {
+       "date": "Sun, 24 Jul 2022 00:00:00 GMT",
+       "price": 14901008279.154797
+     },
+     {
+       "date": "Mon, 25 Jul 2022 00:00:00 GMT",
+       "price": 16058331978.02615
+     },
+     {
+       "date": "Tue, 26 Jul 2022 00:00:00 GMT",
+       "price": 19852493229.276333
+     },
+     {
+       "date": "Tue, 26 Jul 2022 04:59:49 GMT",
+       "price": 19607955073.403877
+     }
+   ]
+ }
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/dojima-faas/faasuser/index.html b/tools/dojima-faas/faasuser/index.html new file mode 100644 index 0000000..cd05259 --- /dev/null +++ b/tools/dojima-faas/faasuser/index.html @@ -0,0 +1,3528 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + User - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

User

+ +

These endpoints are used to create, delete, find or update user.

+

POST Create user

+
 https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot1&email=robot1@gmail.com&plan=monthly
+
+

Returns user details along with apikey based on inputs provided.

+

PARAMS

+ + + + + + + + + + + + + + + + + + + + + +
namerobot1
Required. Name of the user
emailrobot1@gmail.com
Required. Provide valid email of the user to receive updates or notifications
planmonthly
Required. ‘monthly or yearly’. Provide a plan type to get access until the selected period.
> monthly - 10,000 calls/month yearly - 1,80,000 calls/year
+

Example Request and Response

+
+
+
+

cURL Commands

+
 curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************'
+
+

Java Script

+
   var requestOptions = {
+  method: 'POST',
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot&email=robot@gmail.com&plan=monthly", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
   {
+     "key": 6,
+     "name": "robot",
+     "email": "robot@gmail.com",
+     "apiKey": "**********************",
+     "plan": "monthly",
+     "limit": 100000,
+     "createdAt": "2022-08-04T05:02:19.000Z",
+     "validUntil": "2022-09-03T05:02:19.623Z",
+     "updatedAt": "2022-08-04T05:02:19.000Z"
+   }
+
+
+
+
+

GET Find user

+

https://faas-test.dojima.network/dojima-faas/v1/user/data?api=c226c9df7eb08c82c4f4c22266dd
+
+Query Parameters

+ + + + + + + + + + + + + +
ParametersDescription
apic226c9df7eb08c82c4f4c22266dd
+

Example Request and Response

+
+
+
+

cURL Commands

+
curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "****************");
+
+var requestOptions = {
+  method: 'GET',
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/user/data?api=*******************", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+

``` json +{ + “key”: 6, + “name”: “robot”, + “email”: “robot@gmail.com”, + “apiKey”: “******”, + “plan”: “monthly”, + “limit”: 100000, + “createdAt”: “2022-08-04T05:02:19.000Z”, + “validUntil”: “2022-09-03T05:02:19.623Z”, + “updatedAt”: “2022-08-04T05:02:19.000Z” +}

+

```

+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/dojima-faas/index.html b/tools/dojima-faas/index.html new file mode 100644 index 0000000..a9db556 --- /dev/null +++ b/tools/dojima-faas/index.html @@ -0,0 +1,3426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Dojima-FaaS - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Dojima Fass

+ +

Dojima faas

+

Dojima faas provides you blockchain functionality as a service. Blockchain functionality such as creating an account, gas rates for transaction, signing transaction, dollar price, transaction history, submit transaction e.t.c.

+

Features

+
    +
  • One Api - Single endpoint for all blockchain functionality to develop dapps.
  • +
  • Create Account - create an account for any blockchain by just providing a chain name.
  • +
  • Gas Rates - slow, average, fast gas rates for transaction to be processed.
  • +
  • Dollar price - dollar price of any token instantly.
  • +
  • Transaction history - transaction history of any blockchain providing necessary details.
  • +
  • Price History - price of daily, weekly, yearly, all-time token.
  • +
+

User

+

These endpoints are used to create, delete, find or update user.

+

POST Create user

+
 https://faas-test.dojima.network/dojima-faas/v1/user/create?name=robot1&email=robot1@gmail.com&plan=monthly
+
+

Returns user details along with apikey based on inputs provided.

+

PARAMS

+ + + + + + + + + + + + + + + + + + + + + +
namerobot1
Required. Name of the user
emailrobot1@gmail.com
Required. Provide valid email of the user to receive updates or notifications
planmonthly
Required. ‘monthly or yearly’. Provide a plan type to get access until the selected period.
> monthly - 10,000 calls/month yearly - 1,80,000 calls/year
+

GET Find user

+
 https://faas-test.dojima.network/dojima-faas/v1/user/data?api=c226c9df7eb08c82c4f4c22266dd
+
+ + + + + + + + + + + + + +
apic226c9df7eb08c82c4f4c22266dd
+

Account

+

These endpoints return details such as public address from seed phrase/mnemonic, balance of the respective input token.

+

GET Address

+
 https://faas-test.dojima.network/dojima-faas/v1/account/address?mnemonic=letter ethics correct bus asset pipe tourist vapor envelope kangaroo warm dawn&network=testnet
+
+

Returns public addresses of the provided seed phrase of the user and network type.

+

HEADERS

+ + + + + + + + + + + + + +
X-API-KEYc226c9df7eb08c82c4f4c22266dd
Required. Api Key of the user for endpoint to generate result
Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/dojima-faas/transactiondetails/index.html b/tools/dojima-faas/transactiondetails/index.html new file mode 100644 index 0000000..60938c3 --- /dev/null +++ b/tools/dojima-faas/transactiondetails/index.html @@ -0,0 +1,4700 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Transaction Details - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Transaction Details

+ +

Returns transaction details such as detailed transaction data, transactions history based on mentioned token, network and related data.

+

History

+

Returns list of transactions done by an address based on respective token input and network.

+

GET Arweave

+
https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet
+
+

Returns list of transactions done by an address for arweave.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
addressRequired: Public address of the user to which transactions history to be displayed.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
limitOptional. Default 100. Number of transactions to be displayed per call.
+

Example Request and Response

+
+
+
+

cURL Commands

+
https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet
+
+

Java Script

+
  var myHeaders = new Headers();
+  myHeaders.append("X-API-KEY", "******************");
+
+  var requestOptions = {
+    method: 'GET',
+    headers: myHeaders,
+    redirect: 'follow'
+  };
+
+  fetch("https://faas-test.dojima.network/dojima-faas/v1/txs/history/arweave?address=iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys&network=mainnet", requestOptions)
+    .then(response => response.text())
+    .then(result => console.log(result))
+    .catch(error => console.log('error', error));
+
+
+
+
 {
+   "outer": [
+     {
+       "timestamp": 1648533262,
+       "transaction_hash": "sAn6BS_kQXYO2tq9NdNcQInzQBy8ai05T1lIoLVOFSE",
+       "block": 902207,
+       "from": "iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys",
+       "to": "4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o",
+       "value": "0.212303132894",
+       "gas_price": "0.000000724176",
+       "date": "29/03/2022",
+       "time": "11:24:22"
+     },
+     {
+       "timestamp": 1648520642,
+       "transaction_hash": "UygVPWgsvFYJnie_VmFXq4sXkq_48AxMQ2AuGTWWwVM",
+       "block": 902106,
+       "from": "iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys",
+       "to": "4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o",
+       "value": "263.746368279452",
+       "gas_price": "0.000000731880",
+       "date": "29/03/2022",
+       "time": "07:54:02"
+     }
+   ],
+   "inner": [
+     {
+       "timestamp": 1648533262,
+       "transaction_hash": "sAn6BS_kQXYO2tq9NdNcQInzQBy8ai05T1lIoLVOFSE",
+       "block": 902207,
+       "from": "iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys",
+       "to": "4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o",
+       "value": "0.212303132894",
+       "gas_price": "0.000000724176",
+       "date": "29/03/2022",
+       "time": "11:24:22",
+       "signature": "FTALC7RxZVXkd1cETUl83Zt8ZV-zOfy2lqPpC8XzKdzcu_pLBGCdq-UNT-YMfgiurPm4Tt673p7VgudNu55Lu76njnFi2oqnK7Ixn9pp3oMZVtNFEFf3u_MILeRC45arkzFUhZkPDRJkvHIDiKvDKHF1fUkJw20Eg0EiCZTjlkm7g-Uw3vHdESEwNVUv8O43Hg60yvk3Ky8c7k-blVxoD1GRcmLiayLoYRbpYLYyiyYgHZXkdeXLDll2DVjnjVT8RaQqG_EBlZRMkMKHX-FLmwFwmA0nM9PSaz9jQqk8ostxB_Qyl8lsTJ4UzviPfi8MS_f66s6vCL1_JOg2aBiyVTjy_d_Xk6LS7K6T8-5wtuJsz7TTSFzmSsrkrpMap1t2RDmzbNdYiTna0S0CAVWtoS8pZOr_MxUpfvEvrFrcS_EJfg37XzWnT5djVZGcpIs9xYGCechoH6t6Vptn4hYgBBmxUbPfl_LiCU0qevJeyd6rNbg-_23tX7owRUR1GzLBov2o4FRI5A2A2xuP6unNdLWoXOSc0DY5rupToQbj4DjYK1cbeCbvJcGi6MadRaxSRushhRyhhF1ugdwOj7VRPw_m41VR1pm5S4MWuPIWnSUNDgULkFRKKs4XUJLmon77AHlDHvymYVuNFEBXmoWdcvqakcsq60D7irlsmmFiyyg",
+       "block_hash": "LUIt2kLzASel09V0VhYQWd4cyrNtTW_QVqOXakuuIZLALWE87t88LQjCZl9aA9XV"
+     },
+     {
+       "timestamp": 1648520642,
+       "transaction_hash": "UygVPWgsvFYJnie_VmFXq4sXkq_48AxMQ2AuGTWWwVM",
+       "block": 902106,
+       "from": "iy3E3sNIM42BPCMIUYns7YZVeNr9Fphg3EjtAxidXys",
+       "to": "4JOmaT9fFe2ojFJEls3Zow5UKO2CBOk7lOirbPTtX1o",
+       "value": "263.746368279452",
+       "gas_price": "0.000000731880",
+       "date": "29/03/2022",
+       "time": "07:54:02",
+       "signature": "fLsUf_CNzFi2uRje-L4lRd2d4uDAuoZkml9XUn4dyZ4aPsEQZHOMPLuwT3w2nubO0PHvIdPPNPmvjQtcCsc9BIhjXPJWNT3mig03l9s66x1BWaikkbKPYhQ5AF457AhEwqVkXTDARMWSURc3rbjhCAzeHwnwNGmkDd9CS3OGLwfboJa_MArbArzIgz80cuBZ6LCtAWz1xzZ_4TZycKrbhhrXpjeGkYrYxpNJSSK8gaKJTnln2Nb24JkprNtSJtTnmdrg4_iyDbHyj2kYopDtNXOhwx2Q6QqjgmxRC35z5F-QqCwlzJRBQsNkNNEjsszI4klfenQCa9slnCukPuPW1gVzV6RmzYcXApHL_M8ZSF38qCMok67qhbPAnl0psv1Vkz9lXBTixA26UVg4fJRALGxsu5jp3dxbKmZCDWZciSXctjjYj1CAyXcPY-UDkdWleOAAKUFUvfs8G2S9JeNwO-g3J_VOticujYgB6Aypac8LJFAiBpRAZP8tspqsZBDXxw3X0u9s3mk715mIWLDExhg6D38LD75Ve2XeM1iDEJ19DBfeom3kHoX3gP3NPIYMuPqMw1b9nliTQGBNkswP-kNqurGLooiFh_vKQsRKCeHeN1sdiaaVGKZ6DteEEl7ETcWZPh3Grmi0gDVexWj7_prnGCBtESMKCkkAlY5UyNg",
+       "block_hash": "6hC5-XX2FQYHNgxx_2_fXGLF8rOt5JJXify0CJk2NzzeXrNKB_B_6HJn1RKH0Fpi"
+     }
+   ]
+ }
+
+
+
+
+

GET Bitcoin

+
https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet
+
+

Returns list of transactions done by an address for bitcoin.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + +
ParameterDescription
addressRequired: Public address of the user to which transactions history to be displayed.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
+

Example Request and Response

+
+
+
+

cURL Commands

+
    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet' \
+    --header 'X-API-KEY: ****************'
+
+

Java Script

+
  var myHeaders = new Headers();
+  myHeaders.append("X-API-KEY", "****************");
+
+  var requestOptions = {
+    method: 'GET',
+    headers: myHeaders,
+    redirect: 'follow'
+  };
+
+  fetch("https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet", requestOptions)
+    .then(response => response.text())
+    .then(result => console.log(result))
+    .catch(error => console.log('error', error));
+
+
+
+

``` json

+
+
+
+

{ + “txs”: [ + { + “transaction_hash”: “8f035c2dbfbf459e34a9d480d1881095225c9d0801901b9387f2cd4b7533f16b”, + “block”: 2311311 + }, + { + “transaction_hash”: “f51dd2de32005d1289feef06d1ae37da08611f4755210ac8f3545a4cd9de27d8”, + “block”: 2287294 + }, + { + “transaction_hash”: “86809c56e572ec254a87fe3eafa8acc44b9d380dce7677f95662a6901034e071”, + “block”: 2286923 + }, + { + “transaction_hash”: “d5b0fe15206e3895222b9453891b625b5fa0847cb138d5e43755aac770de9b39”, + “block”: 2286923 + }, + { + “transaction_hash”: “6f8f8ace22a5f20582b26d64f9fabf964af2001350cab8379ef86d4b58649732”, + “block”: 2286587 + }, + { + “transaction_hash”: “5529b297e8d29bfbb1b5916ae8dca461d852a17f88d5fa78828314830c3007db”, + “block”: 2285931 + }, + { + “transaction_hash”: “2a2731428b3bd122d214e65e68521f88342463f02a11d612c682b4e49387f116”, + “block”: 2285906 + } + ] + }

+
 ```
+
+ +

GET Ethereum

+
https://faas-test.dojima.network/dojima-faas/v1/txs/history/ethereum?address=0x0577e1E35C4f30cA8379269B7Fd85cBCE7F084f4&network=testnet
+
+

Returns list of transactions done by an address for ethereum.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
addressRequired: Public address of the user to which transactions history to be displayed.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
limitOptional. Default 100. Number of transactions to be displayed per call.
sortOptional. Default ‘desc’. Display of transactions order asc or desc.
startBlockOptional. Default 0. Start block number to display transactions from.
endBlockOptional. Default 99999999. End block number to display transactions until.
pageOptional. Default 1. Transactions page number.
+

Example Request and Response

+
+
+
+

cURL Commands

+
  curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet' \
+  --header 'X-API-KEY: ****************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "****************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/txs/history/bitcoin?address=tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp&network=testnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
{
+   "txs": [
+     {
+       "transaction_hash": "8f035c2dbfbf459e34a9d480d1881095225c9d0801901b9387f2cd4b7533f16b",
+       "block": 2311311
+     },
+     {
+       "transaction_hash": "f51dd2de32005d1289feef06d1ae37da08611f4755210ac8f3545a4cd9de27d8",
+       "block": 2287294
+     },
+     {
+       "transaction_hash": "86809c56e572ec254a87fe3eafa8acc44b9d380dce7677f95662a6901034e071",
+       "block": 2286923
+     },
+     {
+       "transaction_hash": "d5b0fe15206e3895222b9453891b625b5fa0847cb138d5e43755aac770de9b39",
+       "block": 2286923
+     },
+     {
+       "transaction_hash": "6f8f8ace22a5f20582b26d64f9fabf964af2001350cab8379ef86d4b58649732",
+       "block": 2286587
+     },
+     {
+       "transaction_hash": "5529b297e8d29bfbb1b5916ae8dca461d852a17f88d5fa78828314830c3007db",
+       "block": 2285931
+     },
+     {
+       "transaction_hash": "2a2731428b3bd122d214e65e68521f88342463f02a11d612c682b4e49387f116",
+       "block": 2285906
+     }
+   ]
+ }
+
+
+
+
+

GET Solana

+
https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet
+
+

Returns list of transactions done by an address for solana.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+
+

Note

+

Public address of the respective tokens were generated:

+
    +
  • Bitcoin
  • +
  • Arweave
  • +
  • Ethereum
  • +
  • Solana
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
addressRequired: Public address of the user to which transactions history to be displayed.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
offsetOptional. Default 100. Number of transactions to be displayed per call.
beforeHashOptional. Default null. Search list of txs backwards before hash
untilHashOptional. Default null. Search list of txs until hash
+

Example Request and Response

+
+
+
+

cURL Commands

+
    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet' \
+    --header 'X-API-KEY: *********************'
+
+

Java Script

+
  var myHeaders = new Headers();
+  myHeaders.append("X-API-KEY", "*********************");
+
+  var requestOptions = {
+    method: 'GET',
+    headers: myHeaders,
+    redirect: 'follow'
+  };
+
+  fetch("https://faas-test.dojima.network/dojima-faas/v1/txs/history/solana?address=DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS&network=devnet", requestOptions)
+    .then(response => response.text())
+    .then(result => console.log(result))
+    .catch(error => console.log('error', error));
+
+
+
+
{
+   "txs": [
+     {
+       "transaction_hash": "PGgVXU6HCwtQf6td5niURcYtNHru4YWZgWBNBBS1pg2uUcSwcBEUFUTqmNaFbMCdbKfsqTPCwG7CHmKquoeREsH",
+       "block": 150376165,
+       "date": "25/07/2022",
+       "time": "14:17:52"
+     },
+     {
+       "transaction_hash": "2eYrMHzEHVtGf5XtCfvzi3NFNXA4o8tmH8UBUrE4pPT9VigWHtXo7ttDAbTWjJp3mDan7cuBW5BtCV2UD1Nzn684",
+       "block": 149736491,
+       "date": "22/07/2022",
+       "time": "18:51:56"
+     },
+     {
+       "transaction_hash": "2irwfmujx2BWsWEWfwcXwV3dZqoiYtn7HMNBF13z33QngNpF1JiifsE3Nuw6gJKxBbpERhf2WLpdg2ZfDE2EevU2",
+       "block": 149428445,
+       "date": "21/07/2022",
+       "time": "10:21:40"
+     },
+     {
+       "transaction_hash": "3ZAhtNmTtx4vXFYmPqKbVZrgHaydhrFPZ8TGFZvLfh9SMrooVyEtXVrADidgt7kHVFRZQtMctA4yqmz5kLRR5EDa",
+       "block": 149317976,
+       "date": "20/07/2022",
+       "time": "22:42:38"
+     },
+     {
+       "transaction_hash": "3Gof6XhyeqgEW3wYV7DZCixom4zmRn3n6idn95fHJtWV1EAi3zP2cWq7AfRvfRpkDMmbA1FGm3bf6mMC411Yhhy5",
+       "block": 149260715,
+       "date": "20/07/2022",
+       "time": "16:39:47"
+     }
+   ]
+ }
+
+
+
+
+

Hash data

+

Returns transaction details by hash based on respective token and network.

+

GET Arweave

+
https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet
+
+

Returns transaction details by hash for arweave.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+ + + + + + + + + + + + + + + + + +
ParameterDescription
hashRequired. Transaction hash to display in detail about the transaction.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
+

Example Request and Response

+
+
+
+

cURL Commands

+
    curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet' \
+    --header 'X-API-KEY: ******************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "******************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/tx/data/arweave?hash=3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac&network=mainnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
  {
+     "transaction_hash": "3NDXWouOXjWCVAkdIbjXTw91SNVRljwHiMoR3IavEac",
+     "from": "1BmeoGRnPXOv2eyl5CnccIPBrD0axEPQBal3NuSJCvI",
+     "to": "MBB9dcPWUG_t75ezcBwt7u3C0vCyu4tuwxjstlCpvIE",
+     "value": 12734.9,
+     "gas_price": "0.000000862848",
+     "signature": "K61Z7EDckRRyxY_dRRd3cy_6P72fwCEkifl1QQp9cOxXmhSSMKJcIESwYM_6jFT-XEMVGqDWXTrG6sKRp4KhvietgTV0Bk09GSMMjtDZb7SFqW-uDo6ivL4UjV_9fFYqzWuD7QU5NQbZvNXHm-Lea6tQ6_Rod2nLMiBsazWoy7kV6JSQVP1hZeIcAthc4wPgUcolTqo7zQ2a9xV0V8ClsmaqzNorUaztdUghAKBXJWmipwO-W0xhWnQlXFmE_QvikO8OI2b3YvsaOMaVdMdtI4cvUlcXmYW0xZXbQ6sTt4K3b9mXUWg5CNWasBi_d_zGY8jo6uczn6JJsqjA5dc5rtIZdJk3iBOEKm_WTyHAC2Q8Zac6CVKwjOW9zZ63znqEX0RHbUHdT9TtFme14NaYjLH6oS_KT2mi3BoCy39JBcCiprmbsWjlaqVicoJKdhPebS4KlXx3PLyxPP9EfbhopQ3YO55lI6tVp37R4LvHnekgmebjpwAK7g-N_RTG3HX_qCAltaayVMdVpn0zaYo_rYSTcfNhlN5emAF4PyeyLaOEc-5dXUQoidKE29T-ijRPr95cDEX205rmd8tpHsWq1bDyqlVsyvWKgHjffj8KbPAWUvEfONj3GD2IsaHEvYn6KFPQ5UV-WN4lxOWWHnnEhHZxXzirDjhFjkC2dJ3MjRQ"
+   }
+
+
+
+
+

GET Bitcoin

+
https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet
+
+

Returns transaction details by hash for bitcoin.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+ + + + + + + + + + + + + + + + + +
ParameterDescription
hashRequired. Transaction hash to display in detail about the transaction.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
+

Example Request and Response

+
+
+
+

cURL Commands

+
curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet' \
+--header 'X-API-KEY: *******************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "*******************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/tx/data/bitcoin?hash=40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84&network=testnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
 {
+   "txid": "40a9606c5b8a3375a345f110ac81685848f75ab4bd1896ce90383826eeecdd84",
+   "size": 245,
+   "version": 2,
+   "locktime": 0,
+   "fee": 0.00028386,
+   "inputs": [
+     {
+       "coinbase": false,
+       "txid": "a10a458b4816dd38d5104db5b493519801faa56bfcb30cbcfc0afbe7f1851397",
+       "output": 2,
+       "sigscript": "",
+       "sequence": 4294967295,
+       "pkscript": "00143b8b9de28b699d8f3621bf0383fd617b65b84f0a",
+       "value": 61755,
+       "address": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+       "witness": [
+         "3044022030820c9664c5244a1e285aa1c77f485e7dfad9ff656ac05ec5cc98203c52d46602201eddb2f9f063f4611656dcee1c203fda42933dc7e6eb970355867da1c43f4a1701",
+         "025cfbe662e8c3e660094116f94d3020f30787c8252a62b32088464e65cf700e8c"
+       ]
+     }
+   ],
+   "outputs": [
+     {
+       "address": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+       "pkscript": "00143b8b9de28b699d8f3621bf0383fd617b65b84f0a",
+       "value": 317,
+       "spent": false,
+       "spender": null
+     },
+     {
+       "address": null,
+       "pkscript": "6a0c535741503a4254432e425443",
+       "value": 0,
+       "spent": false,
+       "spender": null
+     },
+     {
+       "address": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+       "pkscript": "00143b8b9de28b699d8f3621bf0383fd617b65b84f0a",
+       "value": 33052,
+       "spent": false,
+       "spender": null
+     }
+   ],
+   "block": {
+     "height": 2252852,
+     "position": 3
+   },
+   "deleted": false,
+   "timestamp": "Tue, 31 May 2022 14:49:29 GMT",
+   "rbf": false,
+   "weight": 653,
+   "from": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+   "fromValue": 0.00061755,
+   "to1": "tb1q8w9emc5tdxwc7d3phupc8ltp0djmsnc2ngxnpp",
+   "to1Value": 0.00000317,
+   "to2": null,
+   "to2Value": 0
+ }
+
+
+
+
+

GET Solana

+
https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=34RSHscH1t8vgfBjmrtaSbWwMb514ACX9wgXniq6FkjYU9dvqnYJxrMuhnbJWYpekQt1NJpHPo2yroFFmqTMUkFX&network=devne
+
+

Returns transaction details by hash for solana.

+

HEADERS

+
+

Doesn’t have one? Navigate to “User->Create user” endpoint and get one.
Note: Never share, disclouse or save ‘apikey’ publicly.

+
+
+

Note

+

Note: Never share, disclouse or save ‘apikey’ publicly.

+
+ + + + + + + + + + + + + +
ParameterDescription
X-API-KEYRequired: Api Key of the user for endpoint to generate result
+

Params

+ + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
hashRequired. Transaction hash to display in detail about the transaction.
networkRequired: Default ‘mainnet’. Arweave doesn’t have ‘testnet’ explorer to display transactions.
stateOptional. Default ‘confirmed’. Either ‘confirmed’ or ‘finality’‘
+

Example Request and Response

+
+
+
+

cURL Commands

+
 curl --location --request GET 'https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=2dQaVetThxgW4v3qn2aPVa5cNQ21HgeMYHrSq7G2sxS4rFn25f9PpjjvUBdVzJdqWYbsMV7AY6x8M653DJeGdPuu&network=devnet' \
+ --header 'X-API-KEY: **********************'
+
+

Java Script

+
var myHeaders = new Headers();
+myHeaders.append("X-API-KEY", "**********************");
+
+var requestOptions = {
+  method: 'GET',
+  headers: myHeaders,
+  redirect: 'follow'
+};
+
+fetch("https://faas-test.dojima.network/dojima-faas/v1/tx/data/solana?hash=2dQaVetThxgW4v3qn2aPVa5cNQ21HgeMYHrSq7G2sxS4rFn25f9PpjjvUBdVzJdqWYbsMV7AY6x8M653DJeGdPuu&network=devnet", requestOptions)
+  .then(response => response.text())
+  .then(result => console.log(result))
+  .catch(error => console.log('error', error));
+
+
+
+
   {
+     "timeStamp": 1654094563,
+     "gasFee": 0.000005,
+     "amount": 0.01,
+     "status": "",
+     "block": 138189622,
+     "from": "DxehLnrWp8iP5ahoG413BD4azVrkgA8Pob4rXco3mpCS",
+     "to": "71RGPwytVSNgT9i5RJhwvt7mMSahqxEYFat43ijZ8hbU",
+     "recentBlockHash": "4dYWo3CgRGvjjxXgrgFo8wVYXRZuS8UCam5Ps7NM4BKg",
+     "instructionData": "3Bxs4NN8M2Yn4TLb"
+   }
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/index.html b/tools/index.html new file mode 100644 index 0000000..1167988 --- /dev/null +++ b/tools/index.html @@ -0,0 +1,3307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Tools - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+

Tools

+

Explore our versatile tools section featuring a cross-chain wallet, innovative FAAS solution, and developer dashboard for seamless integration.

+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/wallet/index.html b/tools/wallet/index.html new file mode 100644 index 0000000..d434653 --- /dev/null +++ b/tools/wallet/index.html @@ -0,0 +1,3337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Create Account - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Create Account

+ +

Dojima wallet lets you organise the layer1 tokens in one place with just one seed phrase. Wallet also provides latest prices, 24 hours statistics, blockchain info, transfer tokens, transaction history, variable gas rates for transactions. We are supporting Arweave, Bitcoin, Binance, Cosmos, Ethereum, Polkadot, Solana chains.Go to Dojima Wallet by clicking here.

+

Getting Started

+

To begin using the Dojima wallet, you’ll first need to install our wallet extension. Follow these steps:

+

1. Visit the wallet page and link to “Connect Wallet.”

+

connect-wallet

+
+

Info

+

Download the appropriate version of the wallet extension for your web browser (Chrome, Firefox, etc.). +add-chrome

+
+

2. If you don’t have a seed phrase already, click on “Get Started” to get one.

+

medium

+

3. In the next step you will have to create a password

+

medium

+
+

Info

+

Make sure the password is a minimum of eight characters.

+
+
+

Info

+

This password is not saved on any server. Dojima Network will never save your passwords; this password will be on your local device, the one that you are using. The password is used to encrypt the seed phrase, which will be seen in the next step.

+
+

4. In this step, you will receive your seed phrase, which is a collection of words, typically 12 or 24, that users can choose based on their interests. For improved security, a 24-word seed phrase is suggested.

+

medium 

+

medium 

+
+

Warning

+

Before you proceed, save it somewhere, preferably a text file, because next time you log in, you will need to upload the seed phrase.

+
+
+

Info

+

To make things easy, we created a text file for you. Just click on “proceed” to download +download-seed-phrase

+
+
+

Danger

+

Never reveal your seed phrase.

+
+

5. So in this step, You have to verify the seed phrase, so select the words in order from the seed phrase you copied earlier.

+

medium

+

6. Click on “confirm”

+

medium 

+

7. After installing the wallet extension, you’ll need to log in to your account on the web. Just type the password, and you are good to go.

+

password-web

+

8. That’s it. You are in your Dojima wallet now, and you can explore the dashboard. 

+

medium 

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/wallet/wallet-login/index.html b/tools/wallet/wallet-login/index.html new file mode 100644 index 0000000..1471ed3 --- /dev/null +++ b/tools/wallet/wallet-login/index.html @@ -0,0 +1,3312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Login - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Wallet Login

+ +

To begin using the Dojima wallet, you’ll first need to install our wallet extension.

+

1. Visit the wallet page and link to “Connect Wallet.”

+

connect-wallet

+
+

Info

+

Download the appropriate version of the wallet extension for your web browser (Chrome, Firefox, etc.). +add-chrome

+
+

2. To login, click on “import with seed phrase.”

+

medium

+

3. In this step, you can drag and drop your seed phrase or upload a text file.

+
+

Tip

+

If you have registered with Dojima Wallet or if you have a seed phrase from any other wallet, you can use that seed phrase to link with Dojima Wallet.

+
+
+

Tip

+

You can enter your seed phrase manually also, but it is suggested that you upload a text file to save time.

+
+

medium

+

4. In this step, you have to create a password to encrypt the seed phrase that you just uploaded.

+

medium 

+
+

Tip

+

Dojima wallet will never save your passwords it will reset every time you log out. So new password every +time you log in making it more secure.

+
+
+

Tip

+

The password must be at least eight characters long.

+
+

5. After installing the wallet extension, you’ll need to log in to your account on the web. Just type the password, and you are good to go.

+

password-web

+

6. That’s it. You are in your Dojima wallet now, and you can explore the dashboard. 

+

medium 

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/wallet/wallet-swap/index.html b/tools/wallet/wallet-swap/index.html new file mode 100644 index 0000000..4ef171c --- /dev/null +++ b/tools/wallet/wallet-swap/index.html @@ -0,0 +1,3451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Swap - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Wallet Swap

+ +

Users can swap any assets that are on connected chains and that have been added to the network. Users can swap from any connected asset to any other connected asset. They can also swap from any connected asset to DOJ.

+

Follow the steps to perform Swap.

+

1. After logging into Wallet, navigate to the Swap tab

+

medium 

+

2. Choose the coin you want to swap and enter the necessary amount. Now click on “Swap.”

+

medium 

+

medium 

+

3. Enter the receipt address and click on “Continue.”

+

medium 

+

4. Verify the amount and click on “Continue.”

+

medium 

+

5. As soon as you click on “Continue”, you will get a transaction hash, which can be used to check the status of the swap on the block explorer.”

+

medium 

+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/validator/hermesdeployment/cluster-launcher/overview/index.html b/validator/hermesdeployment/cluster-launcher/overview/index.html new file mode 100644 index 0000000..554a5d1 --- /dev/null +++ b/validator/hermesdeployment/cluster-launcher/overview/index.html @@ -0,0 +1,3480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Overview - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Overview

+ +

Cluster Launcher

+

Deploying a HERMESNode with Kubernetes

+

Deploy a Kubernetes cluster

+

In order to deploy all the different services and provide a high availability environment to operate your node, Kubernetes is the preferred scheduling platform. Any production-grade Kubernetes cluster can be used to run and deploy a HERMESNode. You need your Kubernetes provider to offer external load balancers services type features. Azure, Digital Ocean, GCE, OpenStack are compatible with external load balancers.

+
+

Info

+

Terraform is a type of domain-specific language (DSL) used to describe code infrastructure. It is designed to make it easier to create/destroy infrastructure hosted locally or by a provider.

+
+

This Terraform deployment will deploy a Kubernetes cluster using your VPS provider credentials and EKS service. The cluster will have autoscaling capabilities, which means you don’t have to deal with how many nodes you need to deploy to run your HERMESNode services.

+

All the default configurations used in these instructions are for a production environment with enough resources to run your HERMESNode in good conditions

+
+

Warning

+

LINUX/MAC is the preferred method of setup.

+

Windows should choose either:

+
    +
  1. Deploy a HERMESNode from a Linux VPS.
  2. +
  3. Use Windows Subsystem for Linux - https://docs.microsoft.com/en-us/windows/wsl/about
  4. +
+
+

Steps

+

There are three important steps to getting your node set up, deployed and churned in.

+
    +
  1. Setting up Cluster
  2. +
  3. Deploying HERMESNode Services
  4. +
+

Repository Management

+

Your repository should be organised as follows: +

./hermesnode-ops
+  |./cluster-launcher
+  |./node-launcher
+
+All of your set up commands are run in cluster-launcher and all of your deploying/joining/managing/leaving commands are run from node-launcher

+

Running Two or More Nodes

+
+

Danger

+

To prevent a catastrophic mistake in handling multiple nodes, set them up on different machines, or use different user profiles on your machine, or in the least, use different repos:

+
+
./hermesnode-ops
+  |./cluster-launcher
+  |./node-launcher
+./hermesnode-ops2
+  |./cluster-launcher
+  |./node-launcher
+
+

All of your commands can now be run separately.

+
+

Info

+

It is heavily advised to not set up nodes on the same provider. Deploy 1 node on Azure, 1 node on Digital Ocean etc.

+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/validator/hermesdeployment/cluster-launcher/setup-aws/index.html b/validator/hermesdeployment/cluster-launcher/setup-aws/index.html new file mode 100644 index 0000000..0d46b7d --- /dev/null +++ b/validator/hermesdeployment/cluster-launcher/setup-aws/index.html @@ -0,0 +1,3663 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Setup AWS - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + +

Setup AWS

+ +

Setting up a Kubernetes Cluster with AWS

+

Deploy a Kubernetes cluster in AWS using EKS service.

+

Requirements

+
    +
  1. AWS account
  2. +
  3. CLI and AWS credentials configured
  4. +
  5. AWS IAM Authenticator
  6. +
  7. kubectl
  8. +
  9. wget (required for EKS module)
  10. +
+
+

Warning

+

LINUX/MACI is preffered method of setup

+

Windows should choose either

+
    +
  1. Deploy a HermesNode from a Linux VPS.
  2. +
  3. Use Windows Subsystem for Linux - https://docs.microsoft.com/en-us/windows/wsl/about
  4. +
+
+

Steps

+

Firstly, clone and enter the cluster-launcher repository (Currently This Repo Link is Private Not Accessible By Outside Origanization). All commands in this section are to be run inside this repo.

+
git clone https://github.com/dojimanetwork/validator-cluster-launcher
+cd cluster-launcher
+
+

Then install the terraform CLI:

+
+
+
+

Install Terraform:

+
brew install terraform
+
+
+
+
+

AWS CLI

+

In order for Terraform to run operations on your behalf, you must install and configure the AWS CLI tool. ****To install the AWS CLI, follow these instructions, or choose a package manager based on your operating system

+
+
+
+

Use the package manager homebrew to install the AWS CLI.

+
```jsx
+brew install awscli
+aws configure
+```
+
+ +
+
+
+
+

Warning

+

You will be asked for you Personal Access Token with read/write privileges (retrieve from API Panel from the GCP web console.) +API -> Tokens/Keys -> Create Token. +Make sure you handle your secrets securely!

+
+

AWS IAM Authenticator

+

You also must install and configure the AWS IAM Authenticator tool. To install, follow these instructions, or choose a package manager based on your operating system.

+
+
+
+

Use the package manager homebrew to install the AWS IAM Authenticator.

+
brew install aws-iam-authenticator
+
+
+
+
+

Kubernetes Control Tool

+

You must install and configure the Kubernetes CLI tool (kubectl). To install kubectl , follow these instructions, or choose a package manager based on your operating system.

+

Use the package manager homebrew to install the AWS IAM Authenticator.

+
+
+
+

Use the package manager homebrew to install kubectl.

+
brew install kubernetes-cli
+
+
+
+
+

wget && jq

+

You also need wget and jq, follow these instructions, or choose a package manager based on your operating system.

+
+
+
+

Use the package manager homebrew to install wget and jq Note: You most likely have these installed already.

+
brew install wget
+brew install jq
+
+
+
+
+

Deploy Kubernetes Cluster

+

Use the commands below to deploy a DOKS cluster:

+
make aws
+
+

During the deploy, you will be asked to enter information about your cluster

+

medium

+
    +
  1. Name
  2. +
  3. AWS Region – see valid List of Regions
  4. +
  5. Confirm yes
  6. +
+

medium

+

Regions

+

medium

+

Note: AWS EKS is not available in some regions

+

or manually

+
cd aws/
+terraform init
+terraform plan # to see the plan
+terraform apply
+
+

Final success message: Apply complete! Resources: 30 added, 0 changed, 0 destroyed.

+
+

Info

+

If you are a returning node operator and you wish to use the same node name, the Cloudwatch log files from your previous session will block this step. You need to manually delete the logs from your console: +Cloudwatch / Cloudwatch Logs / Log Groups -> “delete”

+
+
+

Info

+

Deploying a cluster takes ~10 minutes

+
+

CONFIGURE kubectl

+

This is done automatically during provisioning. To configure authentication from the command line, use the following command. It will get the access credentials for your cluster and automatically configure kubectl in case you need to to manually reconfigure kubectl.

+
make kubeconfig-aws
+
+

Or get your kubeconfig file manually:

+
(cd aws && aws eks --region $(terraform output -raw region) update-kubeconfig --name $(terraform output -raw cluster_name))
+
+

To verify, run this, and check the status is “Ready”:

+
kubectl version
+kubectl cluster-info
+kubectl get nodes
+
+

You are now ready to deploy a HermeNode.

+

BACKUPS (OPTIONAL)

+

Once your node is running, use the following command to automatically backup the Persistent Volumes for your Kubernetes cluster. This may help in recovering your node in the event of a disaster.

+

Enable backups:

+
make aws-backups
+
+

Disable backups:

+
make aws-destroy-backups
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/validator/hermesdeployment/cluster-launcher/system-requirements/index.html b/validator/hermesdeployment/cluster-launcher/system-requirements/index.html new file mode 100644 index 0000000..eae2c85 --- /dev/null +++ b/validator/hermesdeployment/cluster-launcher/system-requirements/index.html @@ -0,0 +1,3388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + System Requirements - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

System Requirements

+ +

The system requirements listed in this section are both for the Hermes node and the Dojima node.

+

The minimum system requirements mean you can run the nodes but the setup is not future-proof.

+

The recommended system requirements mean the nodes are future-proof. There is, however, no upper limit to future-proofing your nodes.

+

You must always run the hermes node and the dojima node on separate machines.

+

Minimum system requirements

+
    +
  • RAM: 32 GB
  • +
  • CPU: 8-core
  • +
  • Storage: 2.5 TB SSD
  • +
+
+

Info

+

For Amazon Web Services (AWS), the equivalent of the minimum requirements instances are, with unlimited credits selected:

+
    +
  • +

    For Hermes: c5.2xlarge

    +
  • +
  • +

    For Dojima node: c5.4xlarge

    +
  • +
+
+ +
    +
  • RAM: 64 GB
  • +
  • CPU: 16-core
  • +
  • Storage: 5 TB SSD
  • +
  • Bandwidth: 1 Gbit/s
  • +
+
+

Info

+

For Amazon Web Services (AWS), the equivalent of the recommended requirements instance is m5d.4xlarge.

+

For OVH, the equivalent of the recommended requirements instance is infra-3.

+

For network, expect 3-5 TB of data transferred per month.

+
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/validator/hermesdeployment/deploying/index.html b/validator/hermesdeployment/deploying/index.html new file mode 100644 index 0000000..e4697dd --- /dev/null +++ b/validator/hermesdeployment/deploying/index.html @@ -0,0 +1,3647 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploying - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + +

Deploying

+ +

Deploying a HermesNode and its associated services.

+

Deploy HermesNode services

+

Now you have a Kubernetes cluster ready to use, you can install the HermesNode services.

+
+

Info

+

Helm charts are the defacto and currently easiest and simple way to package and deploy Kubernetes application. The team created different Helm charts to help to deploy all the necessary services. Please retrieve the source files from the Git repository here to follow the instructions below: +https://github.com/dojimanetwork/validator-cluster-launcher

+
+

Requirements

+
    +
  • Running Kubernetes cluster
  • +
  • Kubectl configured, ready and connected to running cluster
  • +
+
+

Info

+

If you came here from the Setup page, you are already good to go.

+
+

Steps

+

Clone the node-launcher repo. All commands in this section are to be run inside of this repo.

+
git clone https://github.com/dojimanetwork/helm_charts
+cd node-launcher
+git checkout master
+
+

Install Helm 3

+

Install Helm 3 if not already available on your current machine:

+
make helm
+make helm-plugins
+
+

Tools

+
+
+
+

To deploy all tools, metrics, logs management, Kubernetes Dashboard, run the command below.

+
make tools
+
+
+
+

To destroy all those resources run the command below.

+
make destroy-tools
+
+
+
+
+

If you are successful, you will see the following message:

+

medium

+

If there are any errors, they are typically fixed by running the command again.

+

Deploy HermesNode

+

It is important to deploy the tools first before deploying the HermesNode services as some services will have metrics configuration that would fail and stop the HermesNode deployment.

+

You have multiple commands available to deploy different configurations of HermesNode. You can deploy testnet or chaosnet/mainnet. The commands deploy the umbrella chart hermesnode-stack in the background in the Kubernetes namespace hermesnode (or hermesnode-testnet for testnet) by default.

+
make install
+
+
+

Info

+

If you are intending to run all chain clients, bond in & earn rewards, you want to choose “Validator”.

+
+
+

Info

+

Deploying a HermesNode will take 1 day for every 3 months of ledger history, since it will validate every block. HermesNodes are “full nodes”, not light clients.

+
+

If successful, you will see the following:

+

medium

+

Debugging

+
+

Info

+

Set hermesnode to be your default namespace so you don’t need to type -n hermesnode each time: +kubectl config set-context –current –namespace=hermesnode

+
+

Use the following useful commands to view and debug accordingly. You should see everything running and active. Logs can be retrieved to find errors:

+
kubectl get pods -n hermesnode
+kubectl get pods --all-namespaces
+kubectl logs -f <pod> -n hermesnode
+
+

Kubernetes should automatically restart any service, but you can force a restart by running:

+
kubectl delete pod <pod> -n hermesnode
+
+
+

Warning

+

Note, to expedite syncing external chains, it is feasible to continually delete the pod that has the slow-syncing chain daemon (eg, binance-daemon-xxx). +Killing it will automatically restart it with free resources and syncing is notably faster. You can check sync status by viewing logs for the client to find the synced chain tip and comparing it with the real-world blockheight, (“xxx” is your unique ID):

+
kubectl logs -f binance-daemon-xxx -n hermesnode
+
+
+
+

Info

+

Get real-world blockheights on the external blockchain explorers, eg: +https://testnet-explorer.binance.org/

+

https://explorer.binance.org/

+
+

CHART SUMMARY

+

HermesNode full stack umbrella chart

+
    +
  • hermesnode: Umbrella chart packaging all services needed to run a fullnode or validator HermesNode.
  • +
+

This should be the only chart used to run HermesNode stack unless you know what you are doing and want to run each chart separately (not recommended).

+

HermesNode services:

+
    +
  • hermes-daemon: HermesNode daemon
  • +
  • hermes-api: HermesNode API
  • +
  • hermes-gateway: HermesNode gateway proxy to get a single IP address for multiple deployments
  • +
  • narada: Narada service
  • +
+

External services:

+
    +
  • binance-daemon: Binance fullnode daemon
  • +
  • bitcoin-daemon: Bitcoin fullnode daemon
  • +
  • ethereum-daemon: Ethereum fullnode daemon
  • +
  • chain-daemon: as required for supported chains
  • +
+

Tools

+
    +
  • elastic: ELK stack, deperecated. Use elastic-operator chart
  • +
  • elastic-operator: ELK stack using operator for logs management
  • +
  • prometheus: Prometheus stack for metrics
  • +
  • loki: Loki stack for logs
  • +
  • kubernetes-dashboard: Kubernetes dashboard
  • +
+ + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/validator/index.html b/validator/index.html new file mode 100644 index 0000000..3888450 --- /dev/null +++ b/validator/index.html @@ -0,0 +1,3303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Validator - Dojima Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file