diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml
index 720134d9c6..df78049252 100644
--- a/.github/workflows/buf-lint.yml
+++ b/.github/workflows/buf-lint.yml
@@ -11,11 +11,11 @@ jobs:
check-codegen:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: bufbuild/buf-setup-action@v1.28.0
+ - uses: bufbuild/buf-setup-action@v1.31.0
with:
- version: 1.28.0
+ version: 1.31.0
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Buf lint
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index cd9e42debc..5189e35dd4 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -14,16 +14,16 @@ jobs:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.12.1
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: ".nvmrc"
- uses: actions/setup-go@v3
with:
- go-version: "1.19"
+ go-version: "1.20"
- name: Install node modules
run: yarn
@@ -54,16 +54,16 @@ jobs:
runs-on: ${{ matrix.runner }}
continue-on-error: true
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
- cache: "npm"
+ cache: "yarn"
node-version-file: ".nvmrc"
- uses: actions/setup-go@v3
with:
- go-version: "1.19"
+ go-version: "1.20"
- name: Download web build
uses: actions/download-artifact@v3
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
new file mode 100644
index 0000000000..9af144d5b9
--- /dev/null
+++ b/.github/workflows/e2e.yml
@@ -0,0 +1,37 @@
+name: E2E Tests
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ merge_group:
+
+jobs:
+ e2e-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cancel Previous Runs
+ uses: styfle/cancel-workflow-action@0.12.1
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ cache: "yarn"
+ node-version-file: ".nvmrc"
+ - uses: actions/setup-go@v3
+ with:
+ go-version: "1.22"
+ - uses: cypress-io/github-action@v6
+ with:
+ browser: chrome
+ build: make install-gno
+ start: |
+ yarn start --minify
+ make start.gnodev-e2e
+ wait-on: "http://localhost:8888, http://localhost:8081"
+ - name: Upload errors screenshots
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: cypress-screenshots
+ path: cypress/screenshots
diff --git a/.github/workflows/gen.yml b/.github/workflows/gen.yml
index 381b22bdcb..830a588365 100644
--- a/.github/workflows/gen.yml
+++ b/.github/workflows/gen.yml
@@ -11,22 +11,22 @@ jobs:
check-codegen:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: ".nvmrc"
- uses: actions/setup-go@v3
with:
- go-version: "1.19"
+ go-version: "1.22"
- uses: dtolnay/rust-toolchain@stable
- - uses: bufbuild/buf-setup-action@v1.28.0
+ - uses: bufbuild/buf-setup-action@v1.31.0
with:
- version: 1.28.0
+ version: 1.31.0
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Install node modules
diff --git a/.github/workflows/gno-lint.yml b/.github/workflows/gno-lint.yml
index 608ddcbd2b..20a288ea15 100644
--- a/.github/workflows/gno-lint.yml
+++ b/.github/workflows/gno-lint.yml
@@ -18,7 +18,7 @@ jobs:
go-version: "1.22"
- name: Clean gno
run: make clean-gno
-
+
- name: Clone gno
run: make clone-gno
@@ -27,3 +27,16 @@ jobs:
- name: Lint gno
run: make lint-gno
+
+ - name: gno mod tidy
+ run: make gno-mod-tidy
+
+ - name: Check that there is no diff
+ run: |
+ mrdiff=$(git status --porcelain)
+ if [[ $mrdiff ]]; then
+ echo 'ERROR: Diff found!'
+ echo $mrdiff
+ git diff
+ exit 1
+ fi
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index f7e7d475e3..d1a51b13be 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -11,11 +11,11 @@ jobs:
go:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: actions/setup-go@v3
with:
- go-version: "1.19"
+ go-version: "1.22"
- name: Tidy go.mod
run: make go-mod-tidy
diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml
index 1e7b6e3341..208762797f 100644
--- a/.github/workflows/js.yml
+++ b/.github/workflows/js.yml
@@ -11,9 +11,9 @@ jobs:
lint-and-build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: ".nvmrc"
diff --git a/.github/workflows/mobile-build-android.yml b/.github/workflows/mobile-build-android.yml
index 5928813bd9..f9b910175b 100644
--- a/.github/workflows/mobile-build-android.yml
+++ b/.github/workflows/mobile-build-android.yml
@@ -29,11 +29,11 @@ jobs:
with:
go-version: "1.20"
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: ".nvmrc"
diff --git a/.github/workflows/mobile-build-ios.yml b/.github/workflows/mobile-build-ios.yml
index 2820081553..9a76e9a7df 100644
--- a/.github/workflows/mobile-build-ios.yml
+++ b/.github/workflows/mobile-build-ios.yml
@@ -22,11 +22,11 @@ jobs:
- name: Select xcode
run: sudo xcode-select -s /Applications/Xcode_15.2.app
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: ".nvmrc"
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 06fd669fa2..48bcfa9b5d 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -11,7 +11,7 @@ jobs:
rust:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
diff --git a/.nvmrc b/.nvmrc
index d576022ca0..6569dfa4f3 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-18.1.0
\ No newline at end of file
+20.8.1
diff --git a/Makefile b/Makefile
index 60288082e2..089359f9d4 100644
--- a/Makefile
+++ b/Makefile
@@ -416,19 +416,37 @@ generate.internal-contracts-clients: node_modules
npx tsx packages/scripts/makeTypescriptIndex $${outdir} || exit 1 ; \
done
+.PHONY: install-gno
+install-gno: node_modules
+ yarn install-gno
+
+.PHONY: start.gnodev-e2e
+start.gnodev-e2e:
+ gnodev --unsafe-api --server-mode --add-account g193vp9tjhfpldvgg3gn433ayv8pn7rtfv8shyeq $$(find gno -name gno.mod -type f -exec dirname {} \;)
+
+.PHONY: clone-gno
clone-gno:
+ mkdir -p gnobuild
cd gnobuild && git clone https://github.com/gnolang/gno.git && cd gno && git checkout 9b114172063feaf2da4ae7ebb8263cada3ba699b
cp -r ./gno/p ./gnobuild/gno/examples/gno.land/p/teritori
+.PHONY: build-gno
build-gno:
cd gnobuild/gno/gnovm && make build
+.PHONY: lint-gno
lint-gno:
./gnobuild/gno/gnovm/build/gno lint ./gno/. -v
+.PHONY: test-gno
test-gno:
./gnobuild/gno/gnovm/build/gno test ./gno/... -v
+.PHONY: gno-mod-tidy
+gno-mod-tidy:
+ export gno=$$(pwd)/gnobuild/gno/gnovm/build/gno; \
+ find gno -name gno.mod -type f | xargs -I'{}' sh -c 'cd $$(dirname {}); $$gno mod tidy' \;
+
+.PHONY: clean-gno
clean-gno:
rm -rf gnobuild
- mkdir gnobuild
diff --git a/assets/icons/github.svg b/assets/icons/github.svg
new file mode 100644
index 0000000000..e47beb5ffd
--- /dev/null
+++ b/assets/icons/github.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/no-tasks.svg b/assets/icons/no-tasks.svg
new file mode 100644
index 0000000000..696633adb9
--- /dev/null
+++ b/assets/icons/no-tasks.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/projects-completed.svg b/assets/icons/projects-completed.svg
new file mode 100644
index 0000000000..2c869a7177
--- /dev/null
+++ b/assets/icons/projects-completed.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/projects-inProgress.svg b/assets/icons/projects-inProgress.svg
new file mode 100644
index 0000000000..5653f3d15e
--- /dev/null
+++ b/assets/icons/projects-inProgress.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/projects-open.svg b/assets/icons/projects-open.svg
new file mode 100644
index 0000000000..0350aed0b1
--- /dev/null
+++ b/assets/icons/projects-open.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/projects-program.svg b/assets/icons/projects-program.svg
new file mode 100644
index 0000000000..2755ef7cc8
--- /dev/null
+++ b/assets/icons/projects-program.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/projects-review.svg b/assets/icons/projects-review.svg
new file mode 100644
index 0000000000..9651dd76bd
--- /dev/null
+++ b/assets/icons/projects-review.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/project-success-payment.png b/assets/project-success-payment.png
new file mode 100644
index 0000000000..eed3b2534d
Binary files /dev/null and b/assets/project-success-payment.png differ
diff --git a/cypress.config.ts b/cypress.config.ts
new file mode 100644
index 0000000000..546918bec2
--- /dev/null
+++ b/cypress.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from "cypress";
+
+export default defineConfig({
+ viewportWidth: 1900,
+ viewportHeight: 1280,
+ e2e: {
+ setupNodeEvents(on, config) {
+ // implement node event listeners here
+ },
+ },
+});
diff --git a/cypress/e2e/0_preload.cy.ts b/cypress/e2e/0_preload.cy.ts
new file mode 100644
index 0000000000..8a76fbfa12
--- /dev/null
+++ b/cypress/e2e/0_preload.cy.ts
@@ -0,0 +1,9 @@
+// this helps to get accurate test times by running first and preloading the app
+
+describe("Preload", () => {
+ it("successfully loads", () => {
+ cy.visit("http://localhost:8081", {
+ timeout: 300000,
+ });
+ });
+});
diff --git a/cypress/e2e/lib.ts b/cypress/e2e/lib.ts
new file mode 100644
index 0000000000..8b214e269c
--- /dev/null
+++ b/cypress/e2e/lib.ts
@@ -0,0 +1,16 @@
+export const changeTestUser = (user: string) => {
+ cy.window().then(async (win) => {
+ const newUserId = await (win as any).adena.SetTestUser(user);
+ cy.get(`*[data-testid='selected-wallet-${newUserId}']`).should("exist");
+ });
+};
+
+export const changeSelectedMilestoneStatus = (newStatus: string) => {
+ const getStatusDropdown = () =>
+ cy.get("*[data-testid='milestone-select-new-status']", { timeout: 20000 });
+ getStatusDropdown().click();
+ const statusElem = getStatusDropdown().contains(newStatus);
+ statusElem.click();
+ statusElem.should("not.exist");
+ cy.contains("Change Status").click();
+};
diff --git a/cypress/e2e/projects-contractor.cy.ts b/cypress/e2e/projects-contractor.cy.ts
new file mode 100644
index 0000000000..c3bfa71968
--- /dev/null
+++ b/cypress/e2e/projects-contractor.cy.ts
@@ -0,0 +1,93 @@
+import { changeSelectedMilestoneStatus, changeTestUser } from "./lib";
+
+describe("Contractor proposer full flow", () => {
+ it("works", () => {
+ cy.request("http://127.0.0.1:8888/reset");
+
+ const projectName = "Test Project";
+ const milestoneName = "Test Milestone";
+ const judgeAddr = "g1nyz430dsujj56ygllcaujkzagz54v0l6yusspy";
+
+ cy.visit("http://localhost:8081/projects?network=gno-dev", {
+ timeout: 300000,
+ });
+
+ cy.contains("Create a Project").click();
+
+ cy.contains("Connect wallet").click({ force: true });
+ cy.get("div[data-testid=connect-gnotest-wallet]").click({ force: true });
+ cy.contains("Connect wallet").should("not.exist");
+ changeTestUser("bob");
+
+ // first step: basic project info
+ cy.get("input[placeholder='Your Grant name']").type(projectName);
+ cy.get("textarea[placeholder='Your Grant description']").type(
+ "Bli blu Bli blu Bli blu Bli blu Bli blu",
+ );
+ cy.get(
+ "input[placeholder='Address of the authority that will resolve conflicts']",
+ ).type(judgeAddr);
+
+ cy.get("input[type=file]").selectFile("cypress/fixtures/image.png", {
+ force: true,
+ });
+ cy.get("div[data-testid=loader-full-screen]", { timeout: 10000 }).should(
+ "not.exist",
+ );
+
+ cy.get("input[placeholder='Add 1-5 main Grant tags using comma...']").type(
+ "ui,ux,frontend",
+ );
+ cy.contains("Next").click();
+
+ // second step: team info
+ // TODO: remove the default values and type them here
+ cy.contains("Next").click();
+
+ // third step: add milestones
+ cy.contains("Add").click();
+ cy.get("input[placeholder='⚡️ Type name here...']").type("Test Milestone");
+ cy.get("textarea[placeholder='Type description here...']").type(
+ "Bli blu bla bleh",
+ );
+ cy.get("input[data-testid='milestone-budget']").clear().type("42");
+ cy.get("input[data-testid='milestone-duration']").clear().type("3600");
+ cy.get("div[data-testid='milestone-confirm']").click();
+ cy.contains("Next").click();
+
+ // fourth step: review and create
+ cy.contains("Publish this request").click();
+ cy.get("div[data-testid='confirm-and-sign']").click();
+ cy.get("div[data-testid='confirm-and-sign']", { timeout: 20000 }).should(
+ "not.exist",
+ );
+ cy.contains("Back to Project Program").click();
+
+ // check that the project is present in manager as funder
+ cy.contains("Projects Manager").click();
+ cy.contains("My projects").click();
+ cy.contains("Test Project").should("exist");
+ cy.contains("Projects Program").click({ force: true });
+
+ // make alice fund the project
+ cy.contains(projectName).click();
+ changeTestUser("alice");
+ cy.contains("Fund this project").click();
+ cy.get("div[data-testid='confirm-and-sign']").click();
+ cy.get("div[data-testid='confirm-and-sign']", { timeout: 20000 }).should(
+ "not.exist",
+ );
+
+ // switch to bob and do milestone
+ changeTestUser("bob");
+ cy.contains(milestoneName).click();
+ // TODO: test in progress state
+ changeSelectedMilestoneStatus("Review");
+
+ // switch to alice and approve completion
+ changeTestUser("alice");
+ changeSelectedMilestoneStatus("Completed");
+
+ cy.get("*[data-testid='project-status-COMPLETED']").should("exist");
+ });
+});
diff --git a/cypress/e2e/projects-funder.cy.ts b/cypress/e2e/projects-funder.cy.ts
new file mode 100644
index 0000000000..72216449f1
--- /dev/null
+++ b/cypress/e2e/projects-funder.cy.ts
@@ -0,0 +1,102 @@
+import { changeSelectedMilestoneStatus, changeTestUser } from "./lib";
+
+describe("Funder proposer full flow", () => {
+ it("works", () => {
+ cy.request("http://127.0.0.1:8888/reset");
+
+ const projectName = "Test Project";
+ const milestoneName = "Test Milestone";
+ const judgeAddr = "g1nyz430dsujj56ygllcaujkzagz54v0l6yusspy";
+
+ cy.visit("http://localhost:8081/projects?network=gno-dev", {
+ timeout: 300000,
+ });
+
+ cy.contains("Create a Project").click();
+
+ cy.contains("Connect wallet").click({ force: true });
+ cy.get("div[data-testid=connect-gnotest-wallet]").click({ force: true });
+ cy.contains("Connect wallet").should("not.exist");
+ changeTestUser("alice");
+
+ // first step: basic project info
+ cy.contains("A funder looking for a developer").click();
+ cy.get("input[placeholder='Your Grant name']").type(projectName);
+ cy.get("textarea[placeholder='Your Grant description']").type(
+ "Bli blu Bli blu Bli blu Bli blu Bli blu",
+ );
+ cy.get(
+ "input[placeholder='Address of the authority that will resolve conflicts']",
+ ).type(judgeAddr);
+
+ cy.get("input[type=file]").selectFile("cypress/fixtures/image.png", {
+ force: true,
+ });
+ cy.get("div[data-testid=loader-full-screen]", { timeout: 10000 }).should(
+ "not.exist",
+ );
+
+ cy.get("input[placeholder='Add 1-5 main Grant tags using comma...']").type(
+ "ui,ux,frontend",
+ );
+ cy.contains("Next").click();
+
+ // second step: team info
+ // TODO: remove the default values and type them here
+ cy.contains("Next").click();
+
+ // third step: add milestones
+ cy.contains("Add").click();
+ cy.get("input[placeholder='⚡️ Type name here...']").type("Test Milestone");
+ cy.get("textarea[placeholder='Type description here...']").type(
+ "Bli blu bla bleh",
+ );
+ cy.get("input[data-testid='milestone-budget']").clear().type("42");
+ cy.get("input[data-testid='milestone-duration']").clear().type("3600");
+ cy.get("div[data-testid='milestone-confirm']").click();
+ cy.contains("Next").click();
+
+ // fourth step: review and create
+ cy.contains("Publish this request").click();
+ cy.get("div[data-testid='confirm-and-sign']").click();
+ cy.get("div[data-testid='confirm-and-sign']", { timeout: 20000 }).should(
+ "not.exist",
+ );
+ cy.contains("Back to Project Program").click();
+
+ // check that the project is present in manager as contractor
+ cy.contains("Projects Manager").click();
+ cy.contains("Test Project").should("exist");
+ cy.contains("Projects Program").click({ force: true });
+
+ // make bob candidate to project
+ cy.contains(projectName).click();
+ changeTestUser("bob");
+ cy.contains("Submit your candidacy as contractor").click();
+ cy.get("div[data-testid='confirm-and-sign']").click();
+ cy.get("div[data-testid='confirm-and-sign']", { timeout: 20000 }).should(
+ "not.exist",
+ );
+
+ // accept bob candidacy
+ changeTestUser("alice");
+ cy.contains("1 candidates").click({ timeout: 10000 });
+ cy.contains("Accept").click();
+ // check that the project is not present anymore in candidates list
+ cy.contains("Accept").should("not.exist");
+ cy.go("back");
+
+ // switch to bob and do milestone
+ changeTestUser("bob");
+ cy.contains("Test Project").click();
+ cy.contains(milestoneName).click({ force: true });
+ // TODO: test in progress state
+ changeSelectedMilestoneStatus("Review");
+
+ // switch to alice and approve completion
+ changeTestUser("alice");
+ changeSelectedMilestoneStatus("Completed");
+
+ cy.get("*[data-testid='project-status-COMPLETED']").should("exist");
+ });
+});
diff --git a/cypress/fixtures/image.png b/cypress/fixtures/image.png
new file mode 100644
index 0000000000..540c94958b
Binary files /dev/null and b/cypress/fixtures/image.png differ
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
new file mode 100644
index 0000000000..95857aea4c
--- /dev/null
+++ b/cypress/support/commands.ts
@@ -0,0 +1,37 @@
+///
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+// namespace Cypress {
+// interface Chainable {
+// login(email: string, password: string): Chainable
+// drag(subject: string, options?: Partial): Chainable
+// dismiss(subject: string, options?: Partial): Chainable
+// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
+// }
+// }
+// }
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts
new file mode 100644
index 0000000000..6a173d6fcb
--- /dev/null
+++ b/cypress/support/e2e.ts
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/e2e.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import "./commands";
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/gno/p/jsonutil/gno.mod b/gno/p/jsonutil/gno.mod
new file mode 100644
index 0000000000..8077020ff7
--- /dev/null
+++ b/gno/p/jsonutil/gno.mod
@@ -0,0 +1,7 @@
+module gno.land/p/teritori/jsonutil
+
+require (
+ gno.land/p/demo/avl v0.0.0-latest
+ gno.land/p/demo/json v0.0.0-latest
+ gno.land/p/demo/users v0.0.0-latest
+)
diff --git a/gno/p/jsonutil/jsonutil.gno b/gno/p/jsonutil/jsonutil.gno
new file mode 100644
index 0000000000..8bc5c05e68
--- /dev/null
+++ b/gno/p/jsonutil/jsonutil.gno
@@ -0,0 +1,131 @@
+package jsonutil
+
+import (
+ "std"
+ "strconv"
+ "time"
+
+ "gno.land/p/demo/avl"
+ "gno.land/p/demo/json"
+ "gno.land/p/demo/users"
+)
+
+func UnionNode(variant string, value *json.Node) *json.Node {
+ return json.ObjectNode("", map[string]*json.Node{
+ variant: value,
+ })
+}
+
+func MustUnion(value *json.Node) (string, *json.Node) {
+ obj := value.MustObject()
+ for key, value := range obj {
+ return key, value
+ }
+
+ panic("no variant in union")
+}
+
+func TimeNode(value time.Time) *json.Node {
+ j, err := value.MarshalJSON()
+ if err != nil {
+ panic(err)
+ }
+
+ return json.StringNode("", string(j[1:len(j)-1]))
+}
+
+func MustTime(value *json.Node) time.Time {
+ t := time.Time{}
+ err := t.UnmarshalJSON([]byte(value.String()))
+ if err != nil {
+ panic(err)
+ }
+
+ return t
+}
+
+func DurationNode(value time.Duration) *json.Node {
+ return Int64Node(value.Nanoseconds())
+}
+
+func MustDurationSeconds(value *json.Node) time.Duration {
+ return time.Duration(MustInt64(value)) * time.Second
+}
+
+func EmptyObjectNode() *json.Node {
+ return json.ObjectNode("", nil)
+}
+
+// int is always 64 bits in gno so we need a string to represent it without loss of precision in a lot of javascript environment, I wish bigint in json was more widely supported
+func IntNode(value int) *json.Node {
+ return json.StringNode("", strconv.Itoa(value))
+}
+
+func MustInt(value *json.Node) int {
+ i, err := strconv.Atoi(value.MustString())
+ if err != nil {
+ panic(err)
+ }
+
+ return i
+}
+
+func Uint32Node(value uint32) *json.Node {
+ return json.StringNode("", strconv.FormatUint(uint64(value), 10))
+}
+
+func MustUint32(value *json.Node) uint32 {
+ return uint32(MustInt(value))
+}
+
+func Int64Node(value int64) *json.Node {
+ return json.StringNode("", strconv.FormatInt(value, 10))
+}
+
+func MustInt64(value *json.Node) int64 {
+ return int64(MustInt(value))
+}
+
+func Uint64Node(value uint64) *json.Node {
+ return json.StringNode("", strconv.FormatUint(value, 10))
+}
+
+func MustUint64(value *json.Node) uint64 {
+ return uint64(MustInt(value)) // FIXME: full uint64 range support (currently limited to [-2^63, 2^63-1])
+}
+
+func AVLTreeNode(root *avl.Tree, transform func(elem interface{}) *json.Node) *json.Node {
+ if root == nil {
+ return EmptyObjectNode()
+ }
+
+ fields := make(map[string]*json.Node)
+ root.Iterate("", "", func(key string, val interface{}) bool {
+ fields[key] = transform(val)
+ return false
+ })
+
+ return json.ObjectNode("", fields)
+}
+
+func AddressNode(addr std.Address) *json.Node {
+ return json.StringNode("", addr.String())
+}
+
+func MustAddress(value *json.Node) std.Address {
+ addr := std.Address(value.MustString())
+ if !addr.IsValid() {
+ panic("invalid address")
+ }
+
+ return addr
+}
+
+func AddressOrNameNode(aon users.AddressOrName) *json.Node {
+ return json.StringNode("", string(aon))
+}
+
+func MustAddressOrName(value *json.Node) users.AddressOrName {
+ aon := users.AddressOrName(value.MustString())
+ return aon
+}
diff --git a/gno/p/ujson/gno.mod b/gno/p/ujson/gno.mod
index c0f2d826c5..99fa7080c8 100644
--- a/gno/p/ujson/gno.mod
+++ b/gno/p/ujson/gno.mod
@@ -2,6 +2,6 @@ module gno.land/p/teritori/ujson
require (
gno.land/p/demo/avl v0.0.0-latest
- gno.land/p/teritori/utf16 v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
+ gno.land/p/teritori/utf16 v0.0.0-latest
)
diff --git a/gno/r/projects_manager/filter.gno b/gno/r/projects_manager/filter.gno
new file mode 100644
index 0000000000..2913199307
--- /dev/null
+++ b/gno/r/projects_manager/filter.gno
@@ -0,0 +1,81 @@
+package projects_manager
+
+import (
+ "std"
+
+ "gno.land/p/demo/json"
+ "gno.land/p/demo/ufmt"
+ "gno.land/p/teritori/jsonutil"
+)
+
+type Filter interface {
+ FromJSON(ast *json.Node)
+}
+
+func FilterFromJSON(ast *json.Node) Filter {
+ if ast.IsNull() {
+ return nil
+ }
+ var filter Filter
+ key, member := jsonutil.MustUnion(ast)
+ switch key {
+ case "byCandidatesForFunder":
+ filter = &FilterByCandidatesForFunder{}
+ case "byFunder":
+ filter = &FilterByFunder{}
+ case "byContractor":
+ filter = &FilterByContractor{}
+ case "byContractorAndFunder":
+ filter = &FilterByContractorAndFunder{}
+ default:
+ panic(ufmt.Sprintf("invalid filter kind `%s`", key))
+ }
+ filter.FromJSON(member)
+ return filter
+}
+
+type FilterByCandidatesForFunder struct {
+ Funder std.Address
+}
+
+func (f *FilterByCandidatesForFunder) FromJSON(ast *json.Node) {
+ obj := ast.MustObject()
+ f.Funder = jsonutil.MustAddress(obj["funder"])
+}
+
+var _ Filter = &FilterByCandidatesForFunder{}
+
+type FilterByFunder struct {
+ Funder std.Address
+}
+
+func (f *FilterByFunder) FromJSON(ast *json.Node) {
+ obj := ast.MustObject()
+ f.Funder = jsonutil.MustAddress(obj["funder"])
+}
+
+var _ Filter = &FilterByFunder{}
+
+type FilterByContractor struct {
+ Contractor std.Address
+}
+
+func (f *FilterByContractor) FromJSON(ast *json.Node) {
+ obj := ast.MustObject()
+ f.Contractor = jsonutil.MustAddress(obj["contractor"])
+}
+
+var _ Filter = &FilterByContractor{}
+
+type FilterByContractorAndFunder struct {
+ Contractor std.Address
+ Funder std.Address
+}
+
+func (f *FilterByContractorAndFunder) FromJSON(ast *json.Node) {
+ obj := ast.MustObject()
+ f.Contractor = jsonutil.MustAddress(obj["contractor"])
+ f.Funder = jsonutil.MustAddress(obj["funder"])
+}
+
+var _ Filter = &FilterByContractorAndFunder{}
diff --git a/gno/r/projects_manager/gno.mod b/gno/r/projects_manager/gno.mod
new file mode 100644
index 0000000000..379bd441e7
--- /dev/null
+++ b/gno/r/projects_manager/gno.mod
@@ -0,0 +1,9 @@
+module gno.land/r/teritori/projects_manager
+
+require (
+ gno.land/p/demo/avl v0.0.0-latest
+ gno.land/p/demo/json v0.0.0-latest
+ gno.land/p/demo/seqid v0.0.0-latest
+ gno.land/p/demo/ufmt v0.0.0-latest
+ gno.land/p/teritori/jsonutil v0.0.0-latest
+)
diff --git a/gno/r/projects_manager/projects_manager.gno b/gno/r/projects_manager/projects_manager.gno
new file mode 100644
index 0000000000..948bf7fe23
--- /dev/null
+++ b/gno/r/projects_manager/projects_manager.gno
@@ -0,0 +1,941 @@
+package projects_manager
+
+import (
+ "std"
+ "strconv"
+ "strings"
+ "time"
+
+ "gno.land/p/demo/avl"
+ "gno.land/p/demo/json"
+ "gno.land/p/demo/seqid"
+ "gno.land/p/demo/ufmt"
+ "gno.land/p/teritori/jsonutil"
+)
+
+type ContractStatus uint32
+
+const (
+ CREATED ContractStatus = 1
+ ACCEPTED ContractStatus = 2
+ CANCELED ContractStatus = 3
+ COMPLETED ContractStatus = 5
+ REJECTED ContractStatus = 6
+ CONFLICT ContractStatus = 7
+ ABORTED_IN_FAVOR_OF_CONTRACTOR ContractStatus = 8
+ ABORTED_IN_FAVOR_OF_FUNDER ContractStatus = 9
+)
+
+func (x ContractStatus) String() string {
+ switch x {
+ case CREATED:
+ return "CREATED"
+ case ACCEPTED:
+ return "ACCEPTED"
+ case CANCELED:
+ return "CANCELED"
+ case COMPLETED:
+ return "COMPLETED"
+ case REJECTED:
+ return "REJECTED"
+ case CONFLICT:
+ return "CONFLICT"
+ case ABORTED_IN_FAVOR_OF_CONTRACTOR:
+ return "ABORTED_IN_FAVOR_OF_CONTRACTOR"
+ case ABORTED_IN_FAVOR_OF_FUNDER:
+ return "ABORTED_IN_FAVOR_OF_FUNDER"
+ }
+ return "UNKNOWN"
+}
+
+func (x ContractStatus) ToJSON() *json.Node {
+ return json.StringNode("", x.String())
+}
+
+type ConflictOutcome uint32
+
+const (
+ RESUME_CONTRACT ConflictOutcome = 1
+ REFUND_FUNDER ConflictOutcome = 2
+ PAY_CONTRACTOR ConflictOutcome = 3
+)
+
+func (x ConflictOutcome) String() string {
+ switch x {
+ case RESUME_CONTRACT:
+ return "RESUME_CONTRACT"
+ case REFUND_FUNDER:
+ return "REFUND_FUNDER"
+ case PAY_CONTRACTOR:
+ return "PAY_CONTRACTOR"
+ }
+ return "UNKNOWN"
+}
+
+func (x ConflictOutcome) ToJSON() *json.Node {
+ return json.StringNode("", x.String())
+}
+
+type MilestoneStatus uint32
+
+const (
+ MS_OPEN MilestoneStatus = 1
+ MS_PROGRESS MilestoneStatus = 2
+ MS_REVIEW MilestoneStatus = 3
+ MS_COMPLETED MilestoneStatus = 4
+)
+
+func (x MilestoneStatus) String() string {
+ switch x {
+ case MS_OPEN:
+ return "MS_OPEN"
+ case MS_PROGRESS:
+ return "MS_PROGRESS"
+ case MS_REVIEW:
+ return "MS_REVIEW"
+ case MS_COMPLETED:
+ return "MS_COMPLETED"
+ }
+ return "UNKNOWN"
+}
+
+func (x MilestoneStatus) ToJSON() *json.Node {
+ return json.StringNode("", x.String())
+}
+
+type MilestonePriority uint32
+
+const (
+ MS_PRIORITY_HIGH MilestonePriority = 1
+ MS_PRIORITY_MEDIUM MilestonePriority = 2
+ MS_PRIORITY_LOW MilestonePriority = 3
+)
+
+func (x MilestonePriority) String() string {
+ switch x {
+ case MS_PRIORITY_HIGH:
+ return "MS_PRIORITY_HIGH"
+ case MS_PRIORITY_MEDIUM:
+ return "MS_PRIORITY_MEDIUM"
+ case MS_PRIORITY_LOW:
+ return "MS_PRIORITY_LOW"
+ }
+ return "UNKNOWN"
+}
+
+func MilestonePriorityFromString(s string) MilestonePriority {
+ switch s {
+ case "MS_PRIORITY_HIGH":
+ return MS_PRIORITY_HIGH
+ case "MS_PRIORITY_MEDIUM":
+ return MS_PRIORITY_MEDIUM
+ case "MS_PRIORITY_LOW":
+ return MS_PRIORITY_LOW
+ }
+ panic("invalid MilestonePriority")
+}
+
+func (x MilestonePriority) ToJSON() *json.Node {
+ return json.StringNode("", x.String())
+}
+
+type Milestone struct {
+ id uint64
+ title string
+ desc string
+ amount int64
+ paid int64
+ duration time.Duration // marshal as seconds
+ link string // milestone reference link
+ funded bool
+ priority MilestonePriority
+ status MilestoneStatus
+}
+
+func (ms Milestone) ToJSON() *json.Node {
+ return json.ObjectNode("", map[string]*json.Node{
+ "id": json.StringNode("", strconv.FormatUint(ms.id, 10)),
+ "title": json.StringNode("", ms.title),
+ "desc": json.StringNode("", ms.desc),
+ "amount": json.StringNode("", strconv.FormatInt(ms.amount, 10)),
+ "paid": json.StringNode("", strconv.FormatInt(ms.paid, 10)),
+ "duration": json.NumberNode("", ms.duration.Seconds()),
+ "link": json.StringNode("", ms.link),
+ "funded": json.BoolNode("", ms.funded),
+ "priority": ms.priority.ToJSON(),
+ "status": ms.status.ToJSON(),
+ })
+}
+
+type Conflict struct {
+ initiator std.Address
+ createdAt time.Time
+ respondedAt *time.Time
+ resolvedAt *time.Time
+ initiatorMessage string
+ responseMessage *string
+ resolutionMessage *string
+ outcome *ConflictOutcome
+}
+
+func (c Conflict) ToJSON() *json.Node {
+ children := map[string]*json.Node{
+ "initiator": json.StringNode("", c.initiator.String()),
+ "createdAt": json.StringNode("", c.createdAt.Format(time.RFC3339)),
+ "initiatorMessage": json.StringNode("", c.initiatorMessage),
+ }
+
+ if c.responseMessage != nil {
+ children["responseMessage"] = json.StringNode("", *c.responseMessage)
+ }
+ if c.respondedAt != nil {
+ children["respondedAt"] = json.StringNode("", c.respondedAt.Format(time.RFC3339))
+ }
+ if c.resolvedAt != nil {
+ children["resolvedAt"] = json.StringNode("", c.resolvedAt.Format(time.RFC3339))
+ }
+ if c.resolutionMessage != nil {
+ children["resolutionMessage"] = json.StringNode("", *c.resolutionMessage)
+ }
+ if c.outcome != nil {
+ children["outcome"] = c.outcome.ToJSON()
+ }
+
+ return json.ObjectNode("", children)
+}
+
+type Contract struct {
+ id uint64
+ sender std.Address
+ contractor std.Address
+ contractorCandidates []std.Address
+ funder std.Address // funder address
+ paymentDenom string // banker denom
+ metadata string // store data forforimage, tags, name, description, links for twitter/github...
+ status ContractStatus
+ expireAt time.Time
+ funderFeedback string
+ contractorFeedback string
+ milestones []Milestone
+ pausedBy string
+ conflictHandler string // can be a realm path or a caller address
+ handlerCandidate string // conflict handler candidate suggested by one party
+ handlerSuggestor string // the suggestor off the conflict handler candidate
+ createdAt time.Time
+ budget int64
+ funded bool
+ rejectReason string
+ conflicts []Conflict
+}
+
+func (c Contract) ToJSON() *json.Node {
+ candidates := make([]*json.Node, len(c.contractorCandidates))
+ for i, candidate := range c.contractorCandidates {
+ candidates[i] = json.StringNode("", candidate.String())
+ }
+
+ milestones := make([]*json.Node, len(c.milestones))
+ for i, milestone := range c.milestones {
+ milestones[i] = milestone.ToJSON()
+ }
+
+ conflicts := make([]*json.Node, len(c.conflicts))
+ for i, conflict := range c.conflicts {
+ conflicts[i] = conflict.ToJSON()
+ }
+
+ return json.ObjectNode("", map[string]*json.Node{
+ "id": json.StringNode("", strconv.FormatUint(c.id, 10)),
+ "sender": json.StringNode("", c.sender.String()),
+ "contractor": json.StringNode("", c.contractor.String()),
+ "contractorCandidates": json.ArrayNode("", candidates),
+ "funder": json.StringNode("", c.funder.String()),
+ "paymentDenom": json.StringNode("", c.paymentDenom),
+ "metadata": json.StringNode("", c.metadata),
+ "status": c.status.ToJSON(),
+ "expireAt": json.StringNode("", c.expireAt.Format(time.RFC3339)),
+ "funderFeedback": json.StringNode("", c.funderFeedback),
+ "contractorFeedback": json.StringNode("", c.contractorFeedback),
+ "milestones": json.ArrayNode("", milestones),
+ "pausedBy": json.StringNode("", c.pausedBy),
+ "conflictHandler": json.StringNode("", c.conflictHandler),
+ "handlerCandidate": json.StringNode("", c.handlerCandidate),
+ "handlerSuggestor": json.StringNode("", c.handlerSuggestor),
+ "createdAt": json.StringNode("", c.createdAt.Format(time.RFC3339)),
+ "budget": json.StringNode("", strconv.FormatInt(c.budget, 10)),
+ "funded": json.BoolNode("", c.funded),
+ "rejectReason": json.StringNode("", c.rejectReason),
+ "conflicts": json.ArrayNode("", conflicts),
+ })
+}
+
+// State
+var (
+ contracts []*Contract
+ contractsByFunder = avl.NewTree() // std.Address(funder) => contractID => *Contract
+ contractsByContractor = avl.NewTree() // std.Address(contractor) => contractID => *Contract
+ contractsByFunderAndContractor = avl.NewTree() // std.Address(funder) + std.Address(contractor) => contractID => *Contract
+ contractsWithCandidates = avl.NewTree() // std.Address(funder) => contractID => *Contract
+)
+
+func setIndices(contract *Contract) {
+ if contract == nil {
+ panic("contract is nil")
+ }
+
+ if contract.contractor != "" {
+ contractorKey := std.Address(contract.contractor).String()
+ byIDTree, ok := contractsByContractor.Get(contractorKey)
+ if !ok {
+ byIDTree = avl.NewTree()
+ contractsByContractor.Set(contractorKey, byIDTree)
+ }
+
+ byIDTree.(*avl.Tree).Set(seqid.ID(contract.id).String(), contract)
+ }
+
+ if contract.funder != "" {
+ funderKey := std.Address(contract.funder).String()
+ byIDTree, ok := contractsByFunder.Get(funderKey)
+ if !ok {
+ byIDTree = avl.NewTree()
+ contractsByFunder.Set(funderKey, byIDTree)
+ }
+
+ byIDTree.(*avl.Tree).Set(seqid.ID(contract.id).String(), contract)
+ }
+
+ if contract.contractor != "" && contract.funder != "" {
+ byIDTree, ok := contractsByFunderAndContractor.Get(std.Address(contract.funder).String() + std.Address(contract.contractor).String())
+ if !ok {
+ byIDTree = avl.NewTree()
+ contractsByFunderAndContractor.Set(std.Address(contract.funder).String()+std.Address(contract.contractor).String(), byIDTree)
+ }
+
+ byIDTree.(*avl.Tree).Set(seqid.ID(contract.id).String(), contract)
+ }
+}
+
+func CurrentRealm() string {
+ return std.CurrentRealm().Addr().String()
+}
+
+type MilestoneDefinition struct {
+ Title string
+ Desc string
+ Amount int64
+ Duration time.Duration
+ Link string
+ Priority MilestonePriority
+}
+
+func CreateContract(
+ contractor std.Address,
+ funder std.Address,
+ paymentDenom string,
+ metadata string,
+ expiryDurationSeconds uint64,
+ milestones []MilestoneDefinition,
+ conflictHandler string,
+) {
+ if contractor != "" && !contractor.IsValid() {
+ panic("invalid contractor address")
+ }
+
+ if funder != "" && !funder.IsValid() {
+ panic("invalid funder address")
+ }
+
+ caller := std.PrevRealm().Addr()
+ if expiryDurationSeconds == 0 {
+ panic("invalid expiryDuration")
+ }
+ if paymentDenom == "" {
+ panic("empty escrow token")
+ }
+
+ // For now, one of funder or contract could be empty and can be set later
+ if contractor == "" && funder == "" {
+ panic("contractor and funder cannot be both empty")
+ }
+
+ if contractor != caller && funder != caller {
+ panic("caller should be one of contractor or funder")
+ }
+
+ if len(milestones) == 0 {
+ panic("milestones should not be empty")
+ }
+
+ mss := make([]Milestone, 0, len(milestones))
+ projectBudget := int64(0)
+ for _, ms := range milestones {
+ projectBudget += ms.Amount
+ mss = append(mss, Milestone{
+ id: uint64(len(mss)),
+ title: ms.Title,
+ desc: ms.Desc,
+ amount: ms.Amount,
+ paid: 0,
+ duration: ms.Duration,
+ link: ms.Link,
+ priority: ms.Priority,
+ status: MS_OPEN,
+ })
+ }
+
+ // If contract creator is funder then he needs to send all the needed fund to contract
+ funded := false
+ if caller == funder {
+ sent := std.GetOrigSend()
+ amount := sent.AmountOf(paymentDenom)
+ if amount != projectBudget {
+ panic(ufmt.Sprintf("funder `%s` should send `%d%s`, got `%d%s`", caller, projectBudget, paymentDenom, amount, paymentDenom))
+ }
+ funded = true
+ }
+
+ expiryDuration := time.Duration(expiryDurationSeconds) * time.Second
+ now := time.Now()
+
+ contractId := uint64(len(contracts))
+ contracts = append(contracts, &Contract{
+ id: contractId,
+ sender: caller,
+ contractor: contractor,
+ funder: funder,
+ paymentDenom: paymentDenom,
+ metadata: metadata,
+ status: CREATED,
+ expireAt: now.Add(expiryDuration),
+ milestones: mss,
+ conflictHandler: conflictHandler,
+ budget: projectBudget,
+ createdAt: now,
+ funded: funded,
+ })
+ setIndices(contracts[contractId])
+}
+
+func CreateContractJSON(
+ contractor std.Address,
+ funder std.Address,
+ paymentDenom string,
+ metadata string,
+ expiryDurationSeconds uint64,
+ milestonesJSON string,
+ conflictHandler string,
+) {
+ ast, err := json.Unmarshal([]byte(milestonesJSON))
+ if err != nil {
+ panic(err)
+ }
+ vals := ast.MustArray()
+ milestones := make([]MilestoneDefinition, 0, len(vals))
+ for _, val := range vals {
+ obj := val.MustObject()
+ milestone := MilestoneDefinition{
+ Title: obj["title"].MustString(),
+ Desc: obj["desc"].MustString(),
+ Amount: jsonutil.MustInt64(obj["amount"]),
+ Duration: jsonutil.MustDurationSeconds(obj["duration"]),
+ Link: obj["link"].MustString(),
+ Priority: MilestonePriorityFromString(obj["priority"].MustString()),
+ }
+ milestones = append(milestones, milestone)
+ }
+ CreateContract(contractor, funder, paymentDenom, metadata, expiryDurationSeconds, milestones, conflictHandler)
+}
+
+func CancelContract(contractId uint64) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.status != CREATED {
+ panic("contract can only be cancelled at CREATED status")
+ }
+
+ if contract.sender != caller {
+ panic("not authorized to cancel the contract")
+ }
+
+ contracts[contractId].status = CANCELED
+}
+
+func RejectContract(contractId uint64, rejectReason string) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.status != CREATED {
+ panic("contract can only be cancelled at CREATED status")
+ }
+
+ if contract.sender == contract.contractor && caller != contract.funder {
+ // If contract creator is contractor then only funder can reject
+ panic("only funder can reject a request from contractor")
+ } else if contract.sender == contract.funder && caller != contract.contractor {
+ // If contract creator is funder then only contractor can reject
+ panic("only contractor can reject a request from funder")
+ }
+
+ contracts[contractId].status = REJECTED
+ contracts[contractId].rejectReason = rejectReason
+}
+
+func AcceptContract(contractId uint64) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.status != CREATED {
+ panic("contract can only be accepted at CREATED status")
+ }
+
+ if time.Now().After(contract.expireAt) {
+ panic("contract already expired")
+ }
+
+ if contract.sender == caller {
+ panic("contract sender is not able to accept the contract")
+ }
+
+ if contract.funder != caller && contract.contractor != caller {
+ panic("only contract counterparty is allowed to accept")
+ }
+ contracts[contractId].status = ACCEPTED
+}
+
+// Submit a funder by putting funds for specific milestones
+func SubmitFunder(contractId uint64) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+
+ if contract.status != CREATED {
+ panic("can only submit candidate to a CREATED contract")
+ }
+
+ if contract.funder != "" {
+ panic("the contract has already a funder")
+ }
+
+ if caller == contract.contractor {
+ panic("you cannot become a funder of your requested contract")
+ }
+
+ sent := std.GetOrigSend()
+ amount := sent.AmountOf(contract.paymentDenom)
+ if amount != contract.budget {
+ panic("wrong amount of funds sent")
+ }
+
+ contracts[contractId].funded = true
+ contracts[contractId].status = ACCEPTED
+ contracts[contractId].funder = caller
+}
+
+// Accept candidate as a contractor
+func AcceptContractor(contractId uint64, contractor std.Address) {
+ if !contractor.IsValid() {
+ panic("invalid contractor address")
+ }
+
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+
+ if contract.status != CREATED {
+ panic("can only submit candidate to a CREATED contract")
+ }
+
+ if contract.contractor != "" {
+ panic("the contract has already a contractor")
+ }
+
+ if caller != contract.funder {
+ panic("Only contract funder can accept contractor")
+ }
+
+ candidates := contracts[contractId].contractorCandidates
+ for _, candidate := range candidates {
+ // Accept the contract if the address already submitted candidate request
+ if candidate == contractor {
+ contracts[contractId].status = ACCEPTED
+ }
+ }
+
+ contracts[contractId].contractor = contractor
+
+ funderKey := contract.funder.String()
+ byIDTreeIface, ok := contractsWithCandidates.Get(funderKey)
+ if !ok {
+ byIDTreeIface = avl.NewTree()
+ contractsWithCandidates.Set(funderKey, byIDTreeIface)
+ }
+ byIDTree := byIDTreeIface.(*avl.Tree)
+ byIDTree.Remove(seqid.ID(contract.id).String())
+ if byIDTree.Size() == 0 {
+ contractsWithCandidates.Remove(funderKey)
+ }
+}
+
+func SubmitContractorCandidate(contractId uint64) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+
+ if contract.status != CREATED {
+ panic("can only submit candidate to a CREATED contract")
+ }
+
+ if contract.contractor != "" {
+ panic("the contract has already a contractor")
+ }
+
+ if caller == contract.funder {
+ panic("you cannot become a contractor of your funded contract")
+ }
+
+ candidates := contracts[contractId].contractorCandidates
+ for _, candidate := range candidates {
+ if candidate == caller {
+ panic("already a contractor candidate")
+ }
+ }
+
+ contracts[contractId].contractorCandidates = append(candidates, caller)
+
+ funderKey := contract.funder.String()
+ byIDTree, ok := contractsWithCandidates.Get(funderKey)
+ if !ok {
+ byIDTree = avl.NewTree()
+ contractsWithCandidates.Set(funderKey, byIDTree)
+ }
+ byIDTree.(*avl.Tree).Set(seqid.ID(contract.id).String(), contract)
+}
+
+// Complete any milestone in review status and pay the needed amount
+func CompleteMilestoneAndPay(contractId uint64, milestoneId uint64) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.funder != caller {
+ panic("only contract funder can pay the milestone")
+ }
+
+ if contract.status != ACCEPTED {
+ panic("only accepted contract can be paid")
+ }
+
+ milestone := contract.milestones[milestoneId]
+ if milestone.status != MS_REVIEW {
+ panic("can only complete and pay a milestone which is in review status")
+ }
+
+ // Pay the milestone
+ unpaid := milestone.amount - milestone.paid
+ if unpaid > 0 {
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ banker.SendCoins(
+ std.CurrentRealm().Addr(),
+ contract.contractor,
+ std.Coins{std.Coin{contract.paymentDenom, int64(unpaid)}})
+ contracts[contractId].milestones[milestoneId].paid += unpaid
+ }
+
+ contracts[contractId].milestones[milestoneId].status = MS_COMPLETED
+
+ // If finish all milestone then complete the contract
+ completedCount := 0
+ for _, milestone := range contract.milestones {
+ if milestone.status == MS_COMPLETED {
+ completedCount++
+ }
+ }
+
+ if completedCount == len(contract.milestones) {
+ contracts[contractId].status = COMPLETED
+ }
+}
+
+// Set milestone status
+func ChangeMilestoneStatus(contractId uint64, milestoneId int, newStatus MilestoneStatus) {
+ if newStatus == MS_COMPLETED {
+ panic("use CompleteMilestoneAndPay to complete and pay the milestone")
+ }
+
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+ contract := contracts[contractId]
+
+ caller := std.PrevRealm().Addr()
+ if contract.funder != caller && contract.contractor != caller {
+ panic("only contract participant can execute the action")
+ }
+
+ if contract.status != ACCEPTED {
+ panic("contract is not on accepted status")
+ }
+
+ if len(contract.milestones) <= milestoneId {
+ panic("milestone Id does not exist in contract")
+ }
+ milestone := contract.milestones[milestoneId]
+
+ if milestone.status == MS_COMPLETED {
+ panic("milestone is completed")
+ }
+
+ contracts[contractId].milestones[milestoneId].status = newStatus
+}
+
+func RequestConflictResolution(contractId uint64, message string) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.funder != caller && contract.contractor != caller {
+ panic("only contract participants can request conflict resolution")
+ }
+
+ if contract.status != ACCEPTED {
+ panic("conflict resolution can only be requested at ACCEPTED status")
+ }
+
+ contracts[contractId].status = CONFLICT
+
+ contracts[contractId].conflicts = append(contract.conflicts, Conflict{
+ initiator: caller,
+ createdAt: time.Now(),
+ initiatorMessage: message,
+ })
+}
+
+func RespondToConflict(contractId uint64, message string) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.status != CONFLICT {
+ panic("conflict can only be responded at CONFLICT status")
+ }
+
+ if len(contract.conflicts) == 0 {
+ panic("no conflict exists, this should not happen")
+ }
+
+ conflictId := len(contract.conflicts) - 1
+ conflict := contract.conflicts[conflictId]
+
+ if conflict.initiator == contract.funder {
+ if contract.contractor != caller {
+ panic("only contract funder can respond to this conflict")
+ }
+ } else if conflict.initiator == contract.contractor {
+ if contract.funder != caller {
+ panic("only contract contractor can respond to this conflict")
+ }
+ } else {
+ panic("conflict initiator is not valid")
+ }
+
+ contracts[contractId].conflicts[conflictId].responseMessage = &message
+ now := time.Now()
+ contracts[contractId].conflicts[conflictId].respondedAt = &now
+}
+
+func ResolveConflict(contractId uint64, outcome ConflictOutcome, resolutionMessage string) {
+ caller := std.PrevRealm().Addr()
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ contract := contracts[contractId]
+ if contract.conflictHandler != caller.String() {
+ panic("only conflictHandler is allowed for this operation")
+ }
+
+ if contract.status != CONFLICT {
+ panic("conflict can only be resolved at CONFLICT status")
+ }
+
+ if len(contract.conflicts) == 0 {
+ panic("no conflict exists")
+ }
+
+ conflictId := len(contract.conflicts) - 1
+
+ switch outcome {
+ case RESUME_CONTRACT:
+ contracts[contractId].status = ACCEPTED
+ case REFUND_FUNDER:
+ totalPaid := int64(0)
+ for _, milestone := range contract.milestones {
+ totalPaid += milestone.paid
+ }
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ banker.SendCoins(
+ std.CurrentRealm().Addr(),
+ contract.funder,
+ std.Coins{std.Coin{contract.paymentDenom, contract.budget - totalPaid}})
+ contracts[contractId].status = ABORTED_IN_FAVOR_OF_FUNDER
+ case PAY_CONTRACTOR:
+ totalPaid := int64(0)
+ for _, milestone := range contract.milestones {
+ totalPaid += milestone.paid
+ }
+ banker := std.GetBanker(std.BankerTypeRealmSend)
+ banker.SendCoins(
+ std.CurrentRealm().Addr(),
+ contract.contractor,
+ std.Coins{std.Coin{contract.paymentDenom, contract.budget - totalPaid}})
+ contracts[contractId].status = ABORTED_IN_FAVOR_OF_CONTRACTOR
+ default:
+ panic("invalid outcome")
+ }
+
+ contracts[contractId].conflicts[conflictId].resolutionMessage = &resolutionMessage
+ contracts[contractId].conflicts[conflictId].outcome = &outcome
+ now := time.Now()
+ contracts[contractId].conflicts[conflictId].resolvedAt = &now
+}
+
+func GetContractorCandidatesJSON(contractId uint64) string {
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ candidates := contracts[contractId].contractorCandidates
+ candidatesJSON := make([]*json.Node, len(candidates))
+ for i, candidate := range candidates {
+ candidatesJSON[i] = json.StringNode("", candidate.String())
+ }
+
+ ret, err := json.Marshal(json.ArrayNode("", candidatesJSON))
+ if err != nil {
+ panic(err)
+ }
+ return string(ret)
+}
+
+func GetContracts(offset, limit int, filter Filter) []*Contract {
+ if offset < 0 {
+ offset = 0
+ }
+
+ if limit <= 0 || offset >= len(contracts) {
+ return nil
+ }
+
+ if filter == nil {
+ end := offset + limit
+ if end > len(contracts) {
+ end = len(contracts)
+ }
+ return contracts[offset:end]
+ }
+
+ var tree interface{}
+ switch f := filter.(type) {
+ case *FilterByCandidatesForFunder:
+ tree, _ = contractsWithCandidates.Get(f.Funder.String())
+ case *FilterByContractorAndFunder:
+ tree, _ = contractsByFunderAndContractor.Get(f.Funder.String() + f.Contractor.String())
+ case *FilterByContractor:
+ tree, _ = contractsByContractor.Get(f.Contractor.String())
+ case *FilterByFunder:
+ tree, _ = contractsByFunder.Get(f.Funder.String())
+ default:
+ panic("unknown filter")
+ }
+
+ if tree == nil {
+ return nil
+ }
+
+ var results []*Contract
+ tree.(*avl.Tree).IterateByOffset(offset, limit, func(key string, value interface{}) bool {
+ results = append(results, value.(*Contract))
+ return false
+ })
+
+ return results
+}
+
+func RenderContractJSON(contractId uint64) string {
+ if int(contractId) >= len(contracts) {
+ panic("invalid contract id")
+ }
+
+ c := contracts[contractId]
+ ret, err := json.Marshal(c.ToJSON())
+ if err != nil {
+ panic(err)
+ }
+
+ return string(ret)
+}
+
+func RenderContractsJSON(offset, limit int, filterJSON string) string {
+ filter := FilterFromJSON(json.Must(json.Unmarshal([]byte(filterJSON))))
+ contractsRes := GetContracts(offset, limit, filter)
+ return renderContractsJSON(contractsRes)
+}
+
+func renderContractsJSON(contractsRes []*Contract) string {
+ contractsJSON := make([]*json.Node, len(contractsRes))
+ for i, c := range contractsRes {
+ contractsJSON[i] = c.ToJSON()
+ }
+
+ ret, err := json.Marshal(json.ArrayNode("", contractsJSON))
+ if err != nil {
+ panic(err)
+ }
+ return string(ret)
+}
+
+func Render(path string) string {
+ b := strings.Builder{}
+ b.WriteString("# Projects Manager\n")
+ b.WriteString("## Overview\n")
+ b.WriteString("This contract is a simple project manager that allows users to create projects and manage them.\n")
+ b.WriteString(ufmt.Sprintf("Contracts managed: %d\n", len(contracts)))
+ b.WriteString("## Latest projects\n")
+ numContracts := 3
+ if len(contracts) < 3 {
+ numContracts = len(contracts)
+ }
+ for i := 0; i < numContracts; i++ {
+ b.WriteString("```json\n")
+ b.WriteString(RenderContractJSON(uint64(len(contracts) - (i + 1))))
+ b.WriteRune('\n')
+ b.WriteString("```\n")
+ }
+ return b.String()
+}
diff --git a/gno/r/projects_manager/projects_manager_test.gno b/gno/r/projects_manager/projects_manager_test.gno
new file mode 100644
index 0000000000..f9c5d7d9dc
--- /dev/null
+++ b/gno/r/projects_manager/projects_manager_test.gno
@@ -0,0 +1,74 @@
+package projects_manager
+
+import (
+ "std"
+ "testing"
+ "time"
+
+ "gno.land/p/demo/json"
+)
+
+func TestJSONRender(t *testing.T) {
+ createdAt := time.Date(2021, time.August, 1, 0, 0, 0, 0, time.UTC)
+ duration := time.Hour * 24 * 30
+ expireAt := createdAt.Add(duration)
+
+ // golden contract
+ contract := Contract{
+ id: 1,
+ sender: std.Address("sender"),
+ contractor: std.Address("contractor2"),
+ contractorCandidates: []std.Address{"contractor1", "contractor2"},
+ funder: "funder",
+ paymentDenom: "denom",
+ metadata: "metadata",
+ status: CREATED,
+ expireAt: expireAt,
+ funderFeedback: "funderFeedback",
+ contractorFeedback: "contractorFeedback",
+ milestones: []Milestone{
+ {
+ id: 1,
+ title: "title",
+ desc: "desc",
+ amount: 100,
+ paid: 0,
+ duration: duration,
+ link: "link",
+ funded: false,
+ priority: MS_PRIORITY_HIGH,
+ status: MS_OPEN,
+ },
+ },
+ pausedBy: "pausedBy",
+ conflictHandler: "conflictHandler",
+ handlerCandidate: "handlerCandidate",
+ handlerSuggestor: "handlerSuggestor",
+ createdAt: createdAt,
+ budget: 1000,
+ funded: false,
+ rejectReason: "rejectReason",
+ conflicts: []Conflict{
+ {
+ initiator: "initiator",
+ createdAt: createdAt,
+ respondedAt: nil,
+ resolvedAt: nil,
+ initiatorMessage: "initiatorMessage",
+ responseMessage: nil,
+ resolutionMessage: nil,
+ outcome: nil,
+ },
+ },
+ }
+
+ output, err := json.Marshal(contract.ToJSON())
+ if err != nil {
+ t.Fatalf("Error marshalling contract to JSON: %s", err)
+ }
+
+ expected := `{"id":"1","sender":"sender","contractor":"contractor2","contractorCandidates":["contractor1","contractor2"],"funder":"funder","paymentDenom":"denom","metadata":"metadata","status":"CREATED","expireAt":"2021-08-31T00:00:00Z","funderFeedback":"funderFeedback","contractorFeedback":"contractorFeedback","milestones":[{"id":"1","title":"title","desc":"desc","amount":"100","paid":"0","duration":2592000,"link":"link","funded":false,"priority":"MS_PRIORITY_HIGH","status":"MS_OPEN"}],"pausedBy":"pausedBy","conflictHandler":"conflictHandler","handlerCandidate":"handlerCandidate","handlerSuggestor":"handlerSuggestor","createdAt":"2021-08-01T00:00:00Z","budget":"1000","funded":false,"rejectReason":"rejectReason","conflicts":[{"initiator":"initiator","createdAt":"2021-08-01T00:00:00Z","initiatorMessage":"initiatorMessage"}]}`
+ if string(output) != expected {
+ t.Errorf("Expected output to be `%s`, got:\n`%s`", expected, string(output))
+ }
+}
diff --git a/gno/r/social_feeds/gno.mod b/gno/r/social_feeds/gno.mod
index 29da62ea3d..4da5feb0eb 100644
--- a/gno/r/social_feeds/gno.mod
+++ b/gno/r/social_feeds/gno.mod
@@ -2,9 +2,9 @@ module gno.land/r/teritori/social_feeds
require (
gno.land/p/demo/avl v0.0.0-latest
+ gno.land/p/demo/testutils v0.0.0-latest
+ gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/teritori/dao_interfaces v0.0.0-latest
gno.land/p/teritori/flags_index v0.0.0-latest
gno.land/p/teritori/ujson v0.0.0-latest
- gno.land/p/demo/testutils v0.0.0-latest
- gno.land/p/demo/ufmt v0.0.0-latest
)
diff --git a/go/pkg/networks/features.gen.go b/go/pkg/networks/features.gen.go
index 06b1db6db7..176738c009 100644
--- a/go/pkg/networks/features.gen.go
+++ b/go/pkg/networks/features.gen.go
@@ -18,6 +18,7 @@ const (
FeatureTypeRiotP2E = FeatureType("RiotP2E")
FeatureTypeNFTBridge = FeatureType("NFTBridge")
FeatureTypeCosmWasmPremiumFeed = FeatureType("CosmWasmPremiumFeed")
+ FeatureTypeGnoProjectManager = FeatureType("GnoProjectManager")
FeatureTypeNFTMarketplaceLeaderboard = FeatureType("NFTMarketplaceLeaderboard")
FeatureTypeCosmWasmNFTsBurner = FeatureType("CosmWasmNFTsBurner")
)
@@ -61,6 +62,26 @@ func (nb *NetworkBase) GetFeatureCosmWasmNFTsBurner() (*FeatureCosmWasmNFTsBurne
return feature.(*FeatureCosmWasmNFTsBurner), nil
}
+type FeatureGnoProjectManager struct {
+ *FeatureBase
+ ProjectsManagerPkgPath string `json:"projectsManagerPkgPath"`
+ PaymentsDenom string `json:"paymentsDenom"`
+}
+
+var _ Feature = &FeatureGnoProjectManager{}
+
+func (f FeatureGnoProjectManager) Type() FeatureType {
+ return FeatureTypeGnoProjectManager
+}
+
+func (nb *NetworkBase) GetFeatureGnoProjectManager() (*FeatureGnoProjectManager, error) {
+ feature, err := nb.GetFeature(FeatureTypeGnoProjectManager)
+ if err != nil {
+ return nil, err
+ }
+ return feature.(*FeatureGnoProjectManager), nil
+}
+
func UnmarshalFeature(b []byte) (Feature, error) {
var base FeatureBase
if err := json.Unmarshal(b, &base); err != nil {
@@ -79,6 +100,12 @@ func UnmarshalFeature(b []byte) (Feature, error) {
return nil, errors.Wrap(err, "failed to unmarshal feature CosmWasmNFTsBurner")
}
return &f, nil
+ case FeatureTypeGnoProjectManager:
+ var f FeatureGnoProjectManager
+ if err := json.Unmarshal(b, &f); err != nil {
+ return nil, errors.Wrap(err, "failed to unmarshal feature GnoProjectManager")
+ }
+ return &f, nil
}
return nil, errors.Errorf("unknown feature type %s", base.Type)
}
diff --git a/networks.json b/networks.json
index e001ce5d81..12a222e74e 100644
--- a/networks.json
+++ b/networks.json
@@ -10,6 +10,7 @@
"kind": "native",
"denom": "uebl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EBL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/8ball/images/8ball.svg",
@@ -48,6 +49,7 @@
"kind": "native",
"denom": "aacre",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ACRE",
"coingeckoId": "arable-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/acrechain/images/acre.svg",
@@ -57,6 +59,7 @@
"kind": "native",
"denom": "erc20/0x2Cbea61fdfDFA520Ee99700F104D5b75ADf50B0c",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "arUSD",
"coingeckoId": "arable-usd",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/acrechain/images/arusd.svg",
@@ -66,6 +69,7 @@
"kind": "native",
"denom": "erc20/0xAE6D3334989a22A65228732446731438672418F2",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CNTO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/acrechain/images/cnto.svg",
@@ -104,6 +108,7 @@
"kind": "native",
"denom": "ubld",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLD",
"coingeckoId": "agoric",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/agoric/images/bld.svg",
@@ -113,6 +118,7 @@
"kind": "native",
"denom": "uist",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IST",
"coingeckoId": "inter-stable-token",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/agoric/images/ist.svg",
@@ -151,6 +157,7 @@
"kind": "native",
"denom": "attoaioz",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "AIOZ",
"coingeckoId": "aioz-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/aioz/images/aioz.svg",
@@ -189,6 +196,7 @@
"kind": "native",
"denom": "uakt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AKT",
"coingeckoId": "akash-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/akash/images/akt.svg",
@@ -227,6 +235,7 @@
"kind": "native",
"denom": "uandr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ANDR",
"coingeckoId": "andromeda-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/andromeda/images/andromeda-logo.png",
@@ -265,6 +274,7 @@
"kind": "native",
"denom": "utia",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TIA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/celestiatestnet2/images/celestia.svg",
@@ -302,6 +312,7 @@
"kind": "native",
"denom": "aarch",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ARCH",
"coingeckoId": "archway",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/archway/images/archway.svg",
@@ -311,6 +322,7 @@
"kind": "native",
"denom": "cw20:archway1fwurjg7ah4v7hhs6xsc3wutqpvmahrfhns285s0lt34tgfdhplxq6m8xg5",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampARCH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/archway/images/amparch.png",
@@ -349,6 +361,7 @@
"kind": "native",
"denom": "aconst",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CONST",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -387,6 +400,7 @@
"kind": "native",
"denom": "uarkeo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ARKEO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/arkeonetworktestnet/images/arkeo.png",
@@ -424,6 +438,7 @@
"kind": "native",
"denom": "arkh",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ARKH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/arkh/images/arkh.svg",
@@ -462,6 +477,7 @@
"kind": "native",
"denom": "uart",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ART",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/artelatestnet/images/artela.png",
@@ -499,6 +515,7 @@
"kind": "native",
"denom": "umntl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MNTL",
"coingeckoId": "assetmantle",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/assetmantle/images/mntl.svg",
@@ -537,6 +554,7 @@
"kind": "native",
"denom": "ueaura",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EAURA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/aura/images/Aura-logo-2.2.svg",
@@ -575,6 +593,7 @@
"kind": "native",
"denom": "uaura",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AURA",
"coingeckoId": "aura-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/aura/images/Aura-logo-2.2.svg",
@@ -613,6 +632,7 @@
"kind": "native",
"denom": "uaxl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AXL",
"coingeckoId": "axelar",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axl.svg",
@@ -622,6 +642,7 @@
"kind": "native",
"denom": "uusdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "axlusdc",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/usdc.svg",
@@ -631,6 +652,7 @@
"kind": "native",
"denom": "frax-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "FRAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/frax.svg",
@@ -640,6 +662,7 @@
"kind": "native",
"denom": "dai-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/dai.svg",
@@ -649,6 +672,7 @@
"kind": "native",
"denom": "uusdt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/usdt.svg",
@@ -658,6 +682,7 @@
"kind": "native",
"denom": "weth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/weth.png",
@@ -667,6 +692,7 @@
"kind": "native",
"denom": "wbtc-satoshi",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "WBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/wbtc.png",
@@ -676,6 +702,7 @@
"kind": "native",
"denom": "aave-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "AAVE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/aave.svg",
@@ -685,6 +712,7 @@
"kind": "native",
"denom": "ape-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "APE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/ape.svg",
@@ -694,6 +722,7 @@
"kind": "native",
"denom": "axs-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "AXS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/axs.svg",
@@ -703,6 +732,7 @@
"kind": "native",
"denom": "link-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "LINK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/link.svg",
@@ -712,6 +742,7 @@
"kind": "native",
"denom": "mkr-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "MKR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/mkr.svg",
@@ -721,6 +752,7 @@
"kind": "native",
"denom": "rai-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "RAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/rai.svg",
@@ -730,6 +762,7 @@
"kind": "native",
"denom": "shib-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "SHIB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/shib.svg",
@@ -739,6 +772,7 @@
"kind": "native",
"denom": "steth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "stETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/steth.svg",
@@ -748,6 +782,7 @@
"kind": "native",
"denom": "uni-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "UNI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/uni.svg",
@@ -757,6 +792,7 @@
"kind": "native",
"denom": "xcn-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "XCN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/xcn.svg",
@@ -766,6 +802,7 @@
"kind": "native",
"denom": "dot-planck",
"decimals": 10,
+ "variant": "cosmos",
"displayName": "DOT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/polkadot/images/dot.svg",
@@ -775,6 +812,7 @@
"kind": "native",
"denom": "wglmr-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WGLMR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/moonbeam/images/glmr.svg",
@@ -784,6 +822,7 @@
"kind": "native",
"denom": "wmatic-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WMATIC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/polygon/images/wmatic.svg",
@@ -793,6 +832,7 @@
"kind": "native",
"denom": "wbnb-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WBNB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/binancesmartchain/images/wbnb.svg",
@@ -802,6 +842,7 @@
"kind": "native",
"denom": "busd-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "BUSD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/busd.png",
@@ -811,6 +852,7 @@
"kind": "native",
"denom": "wavax-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WAVAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/avalanche/images/wavax.svg",
@@ -820,6 +862,7 @@
"kind": "native",
"denom": "wftm-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WFTM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/fantom/images/ftm.png",
@@ -829,6 +872,7 @@
"kind": "native",
"denom": "polygon-uusdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/usdc.svg",
@@ -838,6 +882,7 @@
"kind": "native",
"denom": "avalanche-uusdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/usdc.svg",
@@ -847,6 +892,7 @@
"kind": "native",
"denom": "wfil-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "axlFIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/filecoin/images/wfil.svg",
@@ -856,6 +902,7 @@
"kind": "native",
"denom": "arb-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ARB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/arbitrum/images/arb.svg",
@@ -865,6 +912,7 @@
"kind": "native",
"denom": "pepe-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "PEPE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/pepe.svg",
@@ -874,6 +922,7 @@
"kind": "native",
"denom": "cbeth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "cbETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/cbeth.png",
@@ -883,6 +932,7 @@
"kind": "native",
"denom": "reth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "rETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/reth.png",
@@ -892,6 +942,7 @@
"kind": "native",
"denom": "sfrxeth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "sfrxETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/sfrxeth.svg",
@@ -901,6 +952,7 @@
"kind": "native",
"denom": "wsteth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "wstETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/wsteth.svg",
@@ -910,6 +962,7 @@
"kind": "native",
"denom": "yieldeth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "YieldETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/yieldeth.svg",
@@ -948,6 +1001,7 @@
"kind": "native",
"denom": "uaxl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AXL",
"coingeckoId": "axelar",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axl.svg",
@@ -957,6 +1011,7 @@
"kind": "native",
"denom": "uausdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "aUSDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -966,6 +1021,7 @@
"kind": "native",
"denom": "eth-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "axlWETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/weth.svg",
@@ -975,6 +1031,7 @@
"kind": "native",
"denom": "wglmr-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WDEV",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/moonbeam/images/glmr.svg",
@@ -984,6 +1041,7 @@
"kind": "native",
"denom": "wmatic-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WMATIC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/polygon/images/wmatic.svg",
@@ -993,6 +1051,7 @@
"kind": "native",
"denom": "wbnb-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WBNB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/binancesmartchain/images/wbnb.svg",
@@ -1002,6 +1061,7 @@
"kind": "native",
"denom": "wavax-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WAVAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/avalanche/images/wavax.svg",
@@ -1011,6 +1071,7 @@
"kind": "native",
"denom": "wftm-wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WFTM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/fantom/images/ftm.png",
@@ -1048,6 +1109,7 @@
"kind": "native",
"denom": "uatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BBN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/babylon/images/logo.svg",
@@ -1086,6 +1148,7 @@
"kind": "native",
"denom": "uband",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BAND",
"coingeckoId": "band-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bandchain/images/band.svg",
@@ -1124,6 +1187,7 @@
"kind": "native",
"denom": "ubze",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BZE",
"coingeckoId": "bzedge",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/beezee/images/bze.svg",
@@ -1162,6 +1226,7 @@
"kind": "native",
"denom": "ubcna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BCNA",
"coingeckoId": "bitcanna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitcanna/images/bcna.svg",
@@ -1200,6 +1265,7 @@
"kind": "native",
"denom": "ubcna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BCNA",
"coingeckoId": "bitcanna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/bitcannadevnet/images/bcna.svg",
@@ -1237,6 +1303,7 @@
"kind": "native",
"denom": "ubcna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BCNA",
"coingeckoId": "bitcanna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/bitcannadevnet2/images/bcna.svg",
@@ -1274,6 +1341,7 @@
"kind": "native",
"denom": "ubtsg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BTSG",
"coingeckoId": "bitsong",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/btsg.svg",
@@ -1283,6 +1351,7 @@
"kind": "native",
"denom": "ft2D8E7041556CE93E1EFD66C07C45D551A6AAAE09",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CLAY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft2D8E7041556CE93E1EFD66C07C45D551A6AAAE09.png",
@@ -1292,6 +1361,7 @@
"kind": "native",
"denom": "ft25B30C386CDDEBD1413D5AE1180956AE9EB3B9F7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FASANO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft25B30C386CDDEBD1413D5AE1180956AE9EB3B9F7.png",
@@ -1301,6 +1371,7 @@
"kind": "native",
"denom": "ft575B10B0CEE2C164D9ED6A96313496F164A9607C",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "D9X",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft575B10B0CEE2C164D9ED6A96313496F164A9607C.png",
@@ -1310,6 +1381,7 @@
"kind": "native",
"denom": "ft56664FC98A2CF5F4FBAC3566D1A11D891AD88305",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FONTI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft56664FC98A2CF5F4FBAC3566D1A11D891AD88305.png",
@@ -1319,6 +1391,7 @@
"kind": "native",
"denom": "ft52EEB0EE509AC546ED92EAC8591F731F213DDD16",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BJKS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft52EEB0EE509AC546ED92EAC8591F731F213DDD16.png",
@@ -1328,6 +1401,7 @@
"kind": "native",
"denom": "ftE4903ECC861CA45F2C2BC7EAB8255D2E6E87A33A",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RWNE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ftE4903ECC861CA45F2C2BC7EAB8255D2E6E87A33A.png",
@@ -1337,6 +1411,7 @@
"kind": "native",
"denom": "ft85AE1716C5E39EA6D64BBD7898C3899A7B500626",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ENMODA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft85AE1716C5E39EA6D64BBD7898C3899A7B500626.png",
@@ -1346,6 +1421,7 @@
"kind": "native",
"denom": "ft99091610CCC66F4277C66D14AF2BC4C5EE52E27A",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "404DR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft99091610CCC66F4277C66D14AF2BC4C5EE52E27A.png",
@@ -1355,6 +1431,7 @@
"kind": "native",
"denom": "ft387C1C279D962ED80C09C1D592A92C4275FD7C5D",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "N43",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft387C1C279D962ED80C09C1D592A92C4275FD7C5D.png",
@@ -1364,6 +1441,7 @@
"kind": "native",
"denom": "ft24C9FA4F10B0F235F4A815B15FC774E046A2B2EB",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOBO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft24C9FA4F10B0F235F4A815B15FC774E046A2B2EB.png",
@@ -1373,6 +1451,7 @@
"kind": "native",
"denom": "ft7020C2A8E984EEBCBB383E91CD6FBB067BB2272B",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "VIBRA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft7020C2A8E984EEBCBB383E91CD6FBB067BB2272B.png",
@@ -1382,6 +1461,7 @@
"kind": "native",
"denom": "ft2DD67F5D99E9A141142B48474FA7B6B3FF00A3FE",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KARINA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft2DD67F5D99E9A141142B48474FA7B6B3FF00A3FE.png",
@@ -1391,6 +1471,7 @@
"kind": "native",
"denom": "ft4B030260D99E3ABE2B604EA2B33BAF3C085CDA12",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TESTA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft4B030260D99E3ABE2B604EA2B33BAF3C085CDA12.png",
@@ -1400,6 +1481,7 @@
"kind": "native",
"denom": "ftD4B6290EDEE1EC7B97AB5A1DC6C177EFD08ADCC3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CMQZ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ftD4B6290EDEE1EC7B97AB5A1DC6C177EFD08ADCC3.png",
@@ -1409,6 +1491,7 @@
"kind": "native",
"denom": "ft347B1612A2B7659913679CF6CD45B8B130C50A00",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LDON",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bitsong/images/ft347B1612A2B7659913679CF6CD45B8B130C50A00.png",
@@ -1447,6 +1530,7 @@
"kind": "native",
"denom": "utia",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TIA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/celestiatestnet/images/celestia.svg",
@@ -1484,6 +1568,7 @@
"kind": "native",
"denom": "ubnt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLZ",
"coingeckoId": "bluzelle",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bluzelle/images/bluzelle.svg",
@@ -1493,6 +1578,7 @@
"kind": "native",
"denom": "uelt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ELT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bluzelle/images/elt.png",
@@ -1502,6 +1588,7 @@
"kind": "native",
"denom": "ug4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "G4",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bluzelle/images/g4.png",
@@ -1540,6 +1627,7 @@
"kind": "native",
"denom": "boot",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BOOT",
"coingeckoId": "bostrom",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bostrom/images/boot.svg",
@@ -1549,6 +1637,7 @@
"kind": "native",
"denom": "hydrogen",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HYDROGEN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bostrom/images/hydrogen.svg",
@@ -1558,6 +1647,7 @@
"kind": "native",
"denom": "milliampere",
"decimals": 3,
+ "variant": "cosmos",
"displayName": "A",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bostrom/images/ampere.svg",
@@ -1567,6 +1657,7 @@
"kind": "native",
"denom": "millivolt",
"decimals": 3,
+ "variant": "cosmos",
"displayName": "V",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bostrom/images/volt.svg",
@@ -1576,6 +1667,7 @@
"kind": "native",
"denom": "tocyb",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TOCYB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/bostrom/images/tocyb.svg",
@@ -1614,6 +1706,7 @@
"kind": "native",
"denom": "acanto",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CANTO",
"coingeckoId": "canto",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/canto/images/canto.svg",
@@ -1652,6 +1745,7 @@
"kind": "native",
"denom": "swth",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SWTH",
"coingeckoId": "switcheo",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/swth.svg",
@@ -1661,6 +1755,7 @@
"kind": "native",
"denom": "usc",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "USC",
"coingeckoId": "carbon-usd",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/usc.svg",
@@ -1670,6 +1765,7 @@
"kind": "native",
"denom": "bnb.1.6.773edb",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "BNB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/binancesmartchain/images/bnb.svg",
@@ -1679,6 +1775,7 @@
"kind": "native",
"denom": "bneo.1.14.e2e5f6",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "bNEO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/bneo.svg",
@@ -1688,6 +1785,7 @@
"kind": "native",
"denom": "busd.1.6.754a80",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "BUSD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/busd.png",
@@ -1697,6 +1795,7 @@
"kind": "native",
"denom": "cglp.1.19.1698d3",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CGLP",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/cglp.svg",
@@ -1706,6 +1805,7 @@
"kind": "native",
"denom": "cgt/1",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "USD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/carbon-grouped-usd.svg",
@@ -1715,6 +1815,7 @@
"kind": "native",
"denom": "eth.1.19.c3b805",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/eth.svg",
@@ -1724,6 +1825,7 @@
"kind": "native",
"denom": "eth.1.2.942d87",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/eth.svg",
@@ -1733,6 +1835,7 @@
"kind": "native",
"denom": "usdc.1.2.343151",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -1742,6 +1845,7 @@
"kind": "native",
"denom": "usdc.1.6.53ff75",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -1751,6 +1855,7 @@
"kind": "native",
"denom": "zil.1.18.1a4a06",
"decimals": 12,
+ "variant": "cosmos",
"displayName": "ZIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/carbon/images/zil.svg",
@@ -1789,6 +1894,7 @@
"kind": "native",
"denom": "aCC",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "TCC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/cascadiatestnet/images/cascadia.png",
@@ -1827,6 +1933,7 @@
"kind": "native",
"denom": "utia",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TIA",
"coingeckoId": "celestia",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/celestia/images/celestia.svg",
@@ -1865,6 +1972,7 @@
"kind": "native",
"denom": "ucrbrus",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CRBRUS",
"coingeckoId": "cerberus-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cerberus/images/crbrus.svg",
@@ -1903,6 +2011,7 @@
"kind": "native",
"denom": "uc4e",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "C4E",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chain4energy/images/c4e.png",
@@ -1941,6 +2050,7 @@
"kind": "native",
"denom": "uc4e",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "C4E",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/chain4energytestnet/images/c4e.png",
@@ -1979,6 +2089,7 @@
"kind": "native",
"denom": "ncheq",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "CHEQ",
"coingeckoId": "cheqd-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cheqd/images/cheq.svg",
@@ -2017,6 +2128,7 @@
"kind": "native",
"denom": "ncheq",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "CHEQ",
"coingeckoId": "cheqd-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/cheqdtestnet/images/cheq.svg",
@@ -2055,6 +2167,7 @@
"kind": "native",
"denom": "uhuahua",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HUAHUA",
"coingeckoId": "chihuahua-token",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/huahua.svg",
@@ -2064,6 +2177,7 @@
"kind": "native",
"denom": "cw20:chihuahua1yl8z39ugle8s02fpwkhh293509q5xcpalmdzc4amvchz8nkexrmsy95gef",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PUPPY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/puppyhuahua_logo.png",
@@ -2073,6 +2187,7 @@
"kind": "native",
"denom": "factory/chihuahua1x4q2vkrz4dfgd9hcw0p5m2f2nuv2uqmt9xr8k2/achihuahuawifhat",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BADDOG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/baddog.png",
@@ -2082,6 +2197,7 @@
"kind": "native",
"denom": "factory/chihuahua13jawsn574rf3f0u5rhu7e8n6sayx5gkw3eddhp/uwoof",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WOOF",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/woof.png",
@@ -2091,6 +2207,7 @@
"kind": "native",
"denom": "factory/chihuahua13jawsn574rf3f0u5rhu7e8n6sayx5gkw3eddhp/utacos",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TACOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/tacos.png",
@@ -2100,6 +2217,7 @@
"kind": "native",
"denom": "factory/chihuahua13jawsn574rf3f0u5rhu7e8n6sayx5gkw3eddhp/uweed",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WEED",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/weed.png",
@@ -2109,6 +2227,7 @@
"kind": "native",
"denom": "factory/chihuahua13jawsn574rf3f0u5rhu7e8n6sayx5gkw3eddhp/ubdog",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BDOG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/bdog.png",
@@ -2118,6 +2237,7 @@
"kind": "native",
"denom": "factory/chihuahua13jawsn574rf3f0u5rhu7e8n6sayx5gkw3eddhp/ucorso",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CORSO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chihuahua/images/corso.png",
@@ -2156,6 +2276,7 @@
"kind": "native",
"denom": "ucmba",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CMBA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chimba/images/chimba-blue.svg",
@@ -2194,6 +2315,7 @@
"kind": "native",
"denom": "ucmba",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CMBA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chimba/images/chimba-blue.svg",
@@ -2231,6 +2353,7 @@
"kind": "native",
"denom": "ucht",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CHT",
"coingeckoId": "cht",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chronicnetwork/images/cht.png",
@@ -2240,6 +2363,7 @@
"kind": "native",
"denom": "ucgas",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CGAS",
"coingeckoId": "cgas",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/chronicnetwork/images/cgas.png",
@@ -2277,6 +2401,7 @@
"kind": "native",
"denom": "ucmdx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CMDX",
"coingeckoId": "comdex",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg",
@@ -2286,6 +2411,7 @@
"kind": "native",
"denom": "uharbor",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HARBOR",
"coingeckoId": "harbor-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg",
@@ -2295,6 +2421,7 @@
"kind": "native",
"denom": "ucmst",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CMST",
"coingeckoId": "composite",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg",
@@ -2333,6 +2460,7 @@
"kind": "native",
"denom": "ucommercio",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "COM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/commercionetwork/images/com.svg",
@@ -2342,6 +2470,7 @@
"kind": "native",
"denom": "uccc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CCC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/commercionetwork/images/ccc.svg",
@@ -2380,6 +2509,7 @@
"kind": "native",
"denom": "ppica",
"decimals": 12,
+ "variant": "cosmos",
"displayName": "PICA",
"coingeckoId": "picasso",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/composable/images/pica.svg",
@@ -2418,6 +2548,7 @@
"kind": "native",
"denom": "ppica",
"decimals": 12,
+ "variant": "cosmos",
"displayName": "PICA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/composable/images/composable.svg",
@@ -2455,6 +2586,7 @@
"kind": "native",
"denom": "acvnt",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CVN",
"coingeckoId": "consciousdao",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/conscious/images/cvn.svg",
@@ -2493,6 +2625,7 @@
"kind": "native",
"denom": "uccat",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CCAT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/coolcattestnet/images/coolcat.svg",
@@ -2530,6 +2663,7 @@
"kind": "native",
"denom": "utestcore",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TESTCORE",
"coingeckoId": "coreum",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/coreum/images/coreum.svg",
@@ -2569,6 +2703,7 @@
"denom": "uatom",
"displayName": "ATOM",
"decimals": 6,
+ "variant": "cosmos",
"coingeckoId": "cosmos",
"icon": "cosmos-hub-circle.svg",
"kind": "native",
@@ -2614,6 +2749,7 @@
"denom": "uatom",
"displayName": "ATOM",
"decimals": 6,
+ "variant": "cosmos",
"coingeckoId": "cosmos",
"icon": "cosmos-hub-circle.svg",
"kind": "native",
@@ -2654,6 +2790,7 @@
"kind": "native",
"denom": "umlg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MLG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/cosmwasmtestnet/images/cosmwasm.svg",
@@ -2663,6 +2800,7 @@
"kind": "native",
"denom": "uand",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AND",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/cosmwasmtestnet/images/cosmwasm.svg",
@@ -2700,6 +2838,7 @@
"kind": "native",
"denom": "ucgas",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CGAS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/coss/images/cgas.svg",
@@ -2709,6 +2848,7 @@
"kind": "native",
"denom": "ucoss",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "COSS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/coss/images/coss.svg",
@@ -2747,6 +2887,7 @@
"kind": "native",
"denom": "ucgas",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "cgas",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -2784,6 +2925,7 @@
"kind": "native",
"denom": "ucre",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CRE",
"coingeckoId": "crescent-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/crescent/images/cre.svg",
@@ -2793,6 +2935,7 @@
"kind": "native",
"denom": "ubcre",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bCRE",
"coingeckoId": "liquid-staking-crescent",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/crescent/images/bcre.svg",
@@ -2831,6 +2974,7 @@
"kind": "native",
"denom": "basecro",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cronos/images/cro.svg",
@@ -2869,6 +3013,7 @@
"kind": "native",
"denom": "basecro",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "CRO",
"coingeckoId": "crypto-com-chain",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cronos/images/cro.svg",
@@ -2907,6 +3052,7 @@
"kind": "native",
"denom": "acudos",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CUDOS",
"coingeckoId": "cudos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cudos/images/cudos.svg",
@@ -2945,6 +3091,7 @@
"kind": "native",
"denom": "acudos",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "CUDOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/cudostestnet/images/cudos.svg",
@@ -2982,6 +3129,7 @@
"kind": "native",
"denom": "udear",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DEAR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/deardogetestnet/images/deardoge.png",
@@ -3019,6 +3167,7 @@
"kind": "native",
"denom": "udec",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DEC",
"coingeckoId": "decentr",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/decentr/images/dec.svg",
@@ -3057,6 +3206,7 @@
"kind": "native",
"denom": "udsm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DSM",
"coingeckoId": "desmos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/desmos/images/dsm.svg",
@@ -3095,6 +3245,7 @@
"kind": "native",
"denom": "udaric",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DARIC",
"coingeckoId": "desmos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/desmos/images/dsm.svg",
@@ -3133,6 +3284,7 @@
"kind": "native",
"denom": "uself",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SELF",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/selfchaindevnet/images/selfchain.png",
@@ -3170,6 +3322,7 @@
"kind": "native",
"denom": "udig",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DIG",
"coingeckoId": "dig-chain",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dig/images/dig.png",
@@ -3208,6 +3361,7 @@
"kind": "native",
"denom": "peaka",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DORA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/doravota/images/dora.svg",
@@ -3245,6 +3399,7 @@
"kind": "native",
"denom": "peaka",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DORA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/doravotatestnet/images/doravota.png",
@@ -3282,6 +3437,7 @@
"kind": "native",
"denom": "peaka",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DORA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/doravotatestnet/images/doravota.png",
@@ -3319,6 +3475,7 @@
"kind": "native",
"denom": "adydx",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DYDX",
"coingeckoId": "dydx",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg",
@@ -3357,6 +3514,7 @@
"kind": "native",
"denom": "adydx",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DYDX",
"coingeckoId": "dydx",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dydx/images/dydx.svg",
@@ -3395,6 +3553,7 @@
"kind": "native",
"denom": "dys",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DYS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/dyson/images/dys.svg",
@@ -3433,6 +3592,7 @@
"kind": "native",
"denom": "ungm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NGM",
"coingeckoId": "e-money",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/ngm.svg",
@@ -3442,6 +3602,7 @@
"kind": "native",
"denom": "eeur",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EEUR",
"coingeckoId": "e-money-eur",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/eeur.svg",
@@ -3451,6 +3612,7 @@
"kind": "native",
"denom": "echf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ECHF",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/echf.svg",
@@ -3460,6 +3622,7 @@
"kind": "native",
"denom": "enok",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ENOK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/enok.svg",
@@ -3469,6 +3632,7 @@
"kind": "native",
"denom": "edkk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EDKK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/edkk.svg",
@@ -3478,6 +3642,7 @@
"kind": "native",
"denom": "esek",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ESEK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/emoney/images/esek.svg",
@@ -3516,6 +3681,7 @@
"kind": "native",
"denom": "aechelon",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ECH",
"coingeckoId": "echelon",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/echelon/images/ech.svg",
@@ -3554,6 +3720,7 @@
"kind": "native",
"denom": "uelys",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ELYS",
"coingeckoId": "elys",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/elystestnet/images/elys.png",
@@ -3563,6 +3730,7 @@
"kind": "native",
"denom": "ueden",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EDEN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/elystestnet/images/eden.png",
@@ -3600,6 +3768,7 @@
"kind": "native",
"denom": "umpwr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MPWR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/empowertestnet/images/mpwr.png",
@@ -3637,6 +3806,7 @@
"kind": "native",
"denom": "umpwr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MPWR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/empowerchain/images/mpwr.svg",
@@ -3674,6 +3844,7 @@
"kind": "native",
"denom": "uentry",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ENTRY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/entrypointtestnet/images/entry.svg",
@@ -3717,6 +3888,7 @@
"denom": "0x0000000000000000000000000000000000000000",
"displayName": "ETH",
"decimals": 18,
+ "variant": "ethereum",
"coingeckoId": "ethereum",
"icon": "ethereum-circle.svg",
"kind": "native",
@@ -3762,6 +3934,7 @@
"denom": "0x0000000000000000000000000000000000000000",
"displayName": "GoerliETH",
"decimals": 18,
+ "variant": "ethereum",
"coingeckoId": "ethereum",
"icon": "ethereum-circle.svg",
"kind": "native",
@@ -3802,6 +3975,7 @@
"kind": "native",
"denom": "aRYT",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "RYT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/ethos/images/ethos.svg",
@@ -3840,6 +4014,7 @@
"kind": "native",
"denom": "aevmos",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "EVMOS",
"coingeckoId": "evmos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/evmos/images/evmos.svg",
@@ -3849,6 +4024,7 @@
"kind": "native",
"denom": "erc20/0x655ecB57432CC1370f65e5dc2309588b71b473A9",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "NEOK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/evmos/images/neok.svg",
@@ -3887,6 +4063,7 @@
"kind": "native",
"denom": "atevmos",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "TEVMOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/evmostestnet/images/evmos.svg",
@@ -3924,6 +4101,7 @@
"kind": "native",
"denom": "FX",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "FX",
"coingeckoId": "fx-coin",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/fxcore/images/fx.svg",
@@ -3933,6 +4111,7 @@
"kind": "native",
"denom": "eth0x0FD10b9899882a6f2fcb5c371E17e70FdEe00C38",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "PUNDIX",
"coingeckoId": "pundi-x-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/pundix/images/pundi-x-token-logo.svg",
@@ -3970,6 +4149,7 @@
"kind": "native",
"denom": "afet",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "FET",
"coingeckoId": "fetch-ai",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/fetchhub/images/fet.svg",
@@ -3979,6 +4159,7 @@
"kind": "native",
"denom": "nanomobx",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "MOBX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/fetchhub/images/mobx.svg",
@@ -4017,6 +4198,7 @@
"kind": "native",
"denom": "atestfet",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FET",
"coingeckoId": "fetch-ai",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/fetchhub/images/fet.svg",
@@ -4054,6 +4236,7 @@
"kind": "native",
"denom": "ufct",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FCT",
"coingeckoId": "firmachain",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/firmachain/images/fct.svg",
@@ -4092,6 +4275,7 @@
"kind": "native",
"denom": "ufury",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FURY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/furya/images/ufury.svg",
@@ -4130,6 +4314,7 @@
"kind": "native",
"denom": "uglx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GLX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/galaxy/images/glx.svg",
@@ -4168,6 +4353,7 @@
"kind": "native",
"denom": "el1",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "L1",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/genesisl1/images/l1.svg",
@@ -4206,6 +4392,7 @@
"kind": "native",
"denom": "ulore",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LORE",
"coingeckoId": "gitopia",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/gitopia/images/lore.svg",
@@ -4244,6 +4431,7 @@
"kind": "native",
"denom": "utlore",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TLORE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/gitopiatestnet/images/gitopia.png",
@@ -4278,13 +4466,32 @@
"features": [
"Organizations",
"SocialFeed",
- "UPP"
+ "UPP",
+ "GnoProjectManager"
+ ],
+ "featureObjects": [
+ {
+ "type": "GnoProjectManager",
+ "projectsManagerPkgPath": "gno.land/r/teritori/projects_manager",
+ "paymentsDenom": "ugnot"
+ }
],
"currencies": [
{
"denom": "ugnot",
"displayName": "GNOT",
"decimals": 6,
+ "variant": "gno",
+ "coingeckoId": "gno",
+ "icon": "gno.svg",
+ "kind": "native",
+ "color": "#232800"
+ },
+ {
+ "denom": "gno.land/r/demo/tori20",
+ "displayName": "TORI",
+ "decimals": 6,
+ "variant": "grc20",
"coingeckoId": "gno",
"icon": "gno.svg",
"kind": "native",
@@ -4294,23 +4501,23 @@
"stakeCurrency": "ugnot",
"idPrefix": "gnodev",
"chainId": "dev",
- "endpoint": "http://127.0.0.1:36657/http://127.0.0.1:26657",
+ "endpoint": "http://127.0.0.1:26657",
"txExplorer": "https://gnoscan.io/transactions/details?txhash=$hash",
"accountExplorer": "https://gnoscan.io/accounts/$address",
"contractExplorer": "https://gnoscan.io/realms/details?path=$address",
"testnet": true,
- "backendEndpoint": "http://localhost:9090",
+ "backendEndpoint": "https://dapp-backend.testnet.teritori.com",
"vaultContractAddress": "",
- "daoRegistryPkgPath": "gno.land/r/demo/teritori/dao_registry",
- "socialFeedsPkgPath": "gno.land/r/demo/teritori/social_feeds",
- "socialFeedsDAOPkgPath": "gno.land/r/demo/teritori/social_feeds_dao",
+ "daoRegistryPkgPath": "gno.land/r/teritori/dao_registry",
+ "socialFeedsPkgPath": "gno.land/r/teritori/social_feeds",
+ "socialFeedsDAOPkgPath": "gno.land/r/teritori/social_feeds_dao",
"nameServiceContractAddress": "gno.land/r/demo/users",
- "modboardsPkgPath": "gno.land/r/demo/teritori/modboards",
- "groupsPkgPath": "gno.land/r/demo/teritori/groups",
- "votingGroupPkgPath": "gno.land/p/demo/teritori/dao_voting_group",
- "daoProposalSinglePkgPath": "gno.land/p/demo/teritori/dao_proposal_single",
- "daoInterfacesPkgPath": "gno.land/p/demo/teritori/dao_interfaces",
- "daoCorePkgPath": "gno.land/p/demo/teritori/dao_core",
+ "modboardsPkgPath": "gno.land/r/teritori/modboards",
+ "groupsPkgPath": "gno.land/r/teritori/groups",
+ "votingGroupPkgPath": "gno.land/p/teritori/dao_voting_group",
+ "daoProposalSinglePkgPath": "gno.land/p/teritori/dao_proposal_single",
+ "daoInterfacesPkgPath": "gno.land/p/teritori/dao_interfaces",
+ "daoCorePkgPath": "gno.land/p/teritori/dao_core",
"nameServiceDefaultImage": "ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
"gnowebURL": "http://127.0.0.1:8888"
},
@@ -4332,7 +4539,8 @@
"coingeckoId": "gno",
"icon": "gno.svg",
"kind": "native",
- "color": "#232800"
+ "color": "#232800",
+ "variant": "gno"
}
],
"stakeCurrency": "ugnot",
@@ -4348,14 +4556,14 @@
"vaultContractAddress": "",
"nameServiceContractAddress": "gno.land/r/demo/users",
"nameServiceDefaultImage": "ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
- "daoRegistryPkgPath": "gno.land/r/demo/teritori/dao_registry",
- "socialFeedsPkgPath": "gno.land/r/demo/teritori/social_feeds",
- "socialFeedsDAOPkgPath": "gno.land/r/demo/teritori/social_feeds_dao",
- "groupsPkgPath": "gno.land/r/demo/teritori/groups",
- "votingGroupPkgPath": "gno.land/p/demo/teritori/dao_voting_group",
- "daoProposalSinglePkgPath": "gno.land/p/demo/teritori/dao_proposal_single",
- "daoInterfacesPkgPath": "gno.land/p/demo/teritori/dao_interfaces",
- "daoCorePkgPath": "gno.land/p/demo/teritori/dao_core"
+ "daoRegistryPkgPath": "gno.land/r/teritori/dao_registry",
+ "socialFeedsPkgPath": "gno.land/r/teritori/social_feeds",
+ "socialFeedsDAOPkgPath": "gno.land/r/teritori/social_feeds_dao",
+ "groupsPkgPath": "gno.land/r/teritori/groups",
+ "votingGroupPkgPath": "gno.land/p/teritori/dao_voting_group",
+ "daoProposalSinglePkgPath": "gno.land/p/teritori/dao_proposal_single",
+ "daoInterfacesPkgPath": "gno.land/p/teritori/dao_interfaces",
+ "daoCorePkgPath": "gno.land/p/teritori/dao_core"
},
{
"id": "gno-teritori",
@@ -4365,13 +4573,22 @@
"features": [
"Organizations",
"SocialFeed",
- "UPP"
+ "UPP",
+ "GnoProjectManager"
+ ],
+ "featureObjects": [
+ {
+ "type": "GnoProjectManager",
+ "projectsManagerPkgPath": "gno.land/r/teritori/escrow",
+ "paymentsDenom": "ugnot"
+ }
],
"currencies": [
{
"denom": "ugnot",
"displayName": "GNOT",
"decimals": 6,
+ "variant": "gno",
"coingeckoId": "gno",
"icon": "gno.svg",
"kind": "native",
@@ -4390,15 +4607,15 @@
"vaultContractAddress": "",
"nameServiceContractAddress": "gno.land/r/demo/users",
"nameServiceDefaultImage": "ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
- "daoRegistryPkgPath": "gno.land/r/demo/teritori/dao_registry_v4",
- "socialFeedsPkgPath": "gno.land/r/demo/teritori/social_feeds_v4",
- "socialFeedsDAOPkgPath": "gno.land/r/demo/teritori/social_feeds_dao_v2",
- "modboardsPkgPath": "gno.land/r/demo/teritori/modboards_v4",
- "groupsPkgPath": "gno.land/r/demo/teritori/groups_v4",
- "votingGroupPkgPath": "gno.land/p/demo/teritori/dao_voting_group_v2",
- "daoProposalSinglePkgPath": "gno.land/p/demo/teritori/dao_proposal_single_v4",
- "daoInterfacesPkgPath": "gno.land/p/demo/teritori/dao_interfaces_v5",
- "daoCorePkgPath": "gno.land/p/demo/teritori/dao_core_v4",
+ "daoRegistryPkgPath": "gno.land/r/teritori/dao_registry_v4",
+ "socialFeedsPkgPath": "gno.land/r/teritori/social_feeds_v4",
+ "socialFeedsDAOPkgPath": "gno.land/r/teritori/social_feeds_dao_v2",
+ "modboardsPkgPath": "gno.land/r/teritori/modboards_v4",
+ "groupsPkgPath": "gno.land/r/teritori/groups_v4",
+ "votingGroupPkgPath": "gno.land/p/teritori/dao_voting_group_v2",
+ "daoProposalSinglePkgPath": "gno.land/p/teritori/dao_proposal_single_v4",
+ "daoInterfacesPkgPath": "gno.land/p/teritori/dao_interfaces_v5",
+ "daoCorePkgPath": "gno.land/p/teritori/dao_core_v4",
"gnowebURL": "https://testnet.gno.teritori.com",
"faucetURL": "https://testnet.gno.teritori.com:5050/?toaddr=$addr"
},
@@ -4413,6 +4630,7 @@
"denom": "ugnot",
"displayName": "GNOT",
"decimals": 6,
+ "variant": "gno",
"coingeckoId": "gno",
"icon": "gno.svg",
"kind": "native",
@@ -4450,7 +4668,8 @@
"coingeckoId": "gno",
"icon": "gno.svg",
"kind": "native",
- "color": "#232800"
+ "color": "#232800",
+ "variant": "gno"
}
],
"stakeCurrency": "ugnot",
@@ -4481,6 +4700,7 @@
"kind": "native",
"denom": "ugraviton",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GRAV",
"coingeckoId": "graviton",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/gravitybridge/images/grav.svg",
@@ -4490,6 +4710,7 @@
"kind": "native",
"denom": "gravity0xfB5c6815cA3AC72Ce9F5006869AE67f18bF77006",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "PSTAKE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/pstake.svg",
@@ -4499,6 +4720,7 @@
"kind": "native",
"denom": "gravity0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "WETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/weth.svg",
@@ -4508,6 +4730,7 @@
"kind": "native",
"denom": "gravity0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -4517,6 +4740,7 @@
"kind": "native",
"denom": "gravity0xdAC17F958D2ee523a2206206994597C13D831ec7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.svg",
@@ -4526,6 +4750,7 @@
"kind": "native",
"denom": "gravity0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "WBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/wbtc.svg",
@@ -4535,6 +4760,7 @@
"kind": "native",
"denom": "gravity0x6B175474E89094C44Da98b954EedeAC495271d0F",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "DAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/dai.svg",
@@ -4544,6 +4770,7 @@
"kind": "native",
"denom": "gravity0x83F20F44975D03b1b09e64809B757c47f942BEeA",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "sDAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/sdai.svg",
@@ -4553,6 +4780,7 @@
"kind": "native",
"denom": "gravity0x2F109021aFe75B949429fe30523Ee7C0D5B27207",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "OCC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/occamfi.png",
@@ -4562,6 +4790,7 @@
"kind": "native",
"denom": "gravity0x60e683C6514Edd5F758A55b6f393BeBBAfaA8d5e",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "PAGE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/page.svg",
@@ -4600,6 +4829,7 @@
"kind": "native",
"denom": "aISLM",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ISLM",
"coingeckoId": "islamic-coin",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/haqq/images/islm.svg",
@@ -4638,6 +4868,7 @@
"kind": "native",
"denom": "ufury",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FURY",
"coingeckoId": "fanfury",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/highbury/images/fury.svg",
@@ -4647,6 +4878,7 @@
"kind": "native",
"denom": "jinx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JINX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/highbury/images/jinx.svg",
@@ -4656,6 +4888,7 @@
"kind": "native",
"denom": "jinxy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JINXy",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/highbury/images/jinxy.svg",
@@ -4694,6 +4927,7 @@
"kind": "native",
"denom": "uheart",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HEART",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/humanstestnet/images/humans.png",
@@ -4731,6 +4965,7 @@
"kind": "native",
"denom": "aheart",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "HEART",
"coingeckoId": "humans-ai",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/humans/images/humans_small_light.svg",
@@ -4769,6 +5004,7 @@
"kind": "native",
"denom": "uhid",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HID",
"coingeckoId": "hypersign-identity-token",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/hypersigntestnet/images/hypersign.png",
@@ -4806,6 +5042,7 @@
"kind": "native",
"denom": "idep",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IDEP",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/idep/images/idep.svg",
@@ -4844,6 +5081,7 @@
"kind": "native",
"denom": "aimv",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "IMV",
"coingeckoId": "imv",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/imversed/images/imversed.svg",
@@ -4882,6 +5120,7 @@
"kind": "native",
"denom": "nimv",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IMV",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/imversedtestnet/images/imversed.svg",
@@ -4919,6 +5158,7 @@
"kind": "native",
"denom": "inj",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "INJ",
"coingeckoId": "injective-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg",
@@ -4928,6 +5168,7 @@
"kind": "native",
"denom": "factory/inj1cdwt8g7nxgtg2k4fn8sj363mh9ahkw2qt0vrnc/ampINJ",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampINJ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/ampinj.png",
@@ -4937,6 +5178,7 @@
"kind": "native",
"denom": "factory/inj14lf8xm6fcvlggpa7guxzjqwjmtr24gnvf56hvz/autism",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AUTISM",
"coingeckoId": "autism",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/autism.png",
@@ -4946,6 +5188,7 @@
"kind": "native",
"denom": "factory/inj1xtel2knkt8hmc9dnzpjz6kdmacgcfmlv5f308w/ninja",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NINJA",
"coingeckoId": "dog-wif-nuchucks",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/ninja.png",
@@ -4955,6 +5198,7 @@
"kind": "native",
"denom": "factory/inj1rmjzj9fn47kdmfk4f3z39qr6czexxe0yjyc546/WGMI",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WGMI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/wgmi.png",
@@ -4993,6 +5237,7 @@
"kind": "native",
"denom": "inj",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "INJ",
"coingeckoId": "injective-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/injective/images/inj.svg",
@@ -5030,6 +5275,7 @@
"kind": "native",
"denom": "uiris",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IRIS",
"coingeckoId": "iris-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/irisnet/images/iris.svg",
@@ -5068,6 +5314,7 @@
"kind": "native",
"denom": "uixo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IXO",
"coingeckoId": "ixo",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/impacthub/images/ixo.svg",
@@ -5106,6 +5353,7 @@
"kind": "native",
"denom": "uixo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IXO",
"coingeckoId": "ixo",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/impacthubdevnet/images/ixo.svg",
@@ -5143,6 +5391,7 @@
"kind": "native",
"denom": "uixo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IXO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/impacthub/images/ixo.svg",
@@ -5181,6 +5430,7 @@
"kind": "native",
"denom": "ujkl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JKL",
"coingeckoId": "jackal-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/jackal/images/jkl.svg",
@@ -5219,6 +5469,7 @@
"kind": "native",
"denom": "ujkl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JKL",
"coingeckoId": "jackal",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/jackaltestnet/images/jkl.svg",
@@ -5256,6 +5507,7 @@
"kind": "native",
"denom": "ujuno",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JUNO",
"coingeckoId": "juno-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/juno.svg",
@@ -5265,6 +5517,7 @@
"kind": "native",
"denom": "cw20:juno168ctmpyppk90d34p3jjy658zf5a5l3w8wk35wht6ccqj4mr0yv8s4j5awr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NETA",
"coingeckoId": "neta",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/neta.svg",
@@ -5274,6 +5527,7 @@
"kind": "native",
"denom": "cw20:juno1g2g7ucurum66d42g8k5twk34yegdq8c82858gz0tq2fc75zy7khssgnhjl",
"decimals": 3,
+ "variant": "cosmos",
"displayName": "MARBLE",
"coingeckoId": "marble",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/marble.svg",
@@ -5283,6 +5537,7 @@
"kind": "native",
"denom": "cw20:juno1re3x67ppxap48ygndmrc7har2cnc7tcxtm9nplcas4v0gc3wnmvs3s807z",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HOPE",
"coingeckoId": "hope-galaxy",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/hope.svg",
@@ -5292,6 +5547,7 @@
"kind": "native",
"denom": "cw20:juno1r4pzw8f9z0sypct5l9j906d47z998ulwvhvqe5xdwgy8wf84583sxwh0pa",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RAC",
"coingeckoId": "racoon",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/rac.svg",
@@ -5301,6 +5557,7 @@
"kind": "native",
"denom": "cw20:juno1y9rf7ql6ffwkv02hsgd4yruz23pn4w97p75e2slsnkm0mnamhzysvqnxaq",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLOCK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/block.svg",
@@ -5310,6 +5567,7 @@
"kind": "native",
"denom": "cw20:juno1tdjwrqmnztn2j3sj2ln9xnyps5hs48q3ddwjrz7jpv6mskappjys5czd49",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DHK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/dhk.svg",
@@ -5319,6 +5577,7 @@
"kind": "native",
"denom": "cw20:juno15u3dt79t6sxxa3x3kpkhzsy56edaa5a66wvt3kxmukqjz2sx0hes5sn38g",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RAW",
"coingeckoId": "junoswap-raw-dao",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/raw.svg",
@@ -5328,6 +5587,7 @@
"kind": "native",
"denom": "cw20:juno17wzaxtfdw5em7lc94yed4ylgjme63eh73lm3lutp2rhcxttyvpwsypjm4w",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ASVT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/asvt.png",
@@ -5337,6 +5597,7 @@
"kind": "native",
"denom": "cw20:juno1ur4jx0sxchdevahep7fwq28yk4tqsrhshdtylz46yka3uf6kky5qllqp4k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HNS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/hns.svg",
@@ -5346,6 +5607,7 @@
"kind": "native",
"denom": "cw20:juno1n7n7d5088qlzlj37e9mgmkhx6dfgtvt02hqxq66lcap4dxnzdhwqfmgng3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JOE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/joe.png",
@@ -5355,6 +5617,7 @@
"kind": "native",
"denom": "cw20:juno1sfwye65qxcfsc837gu5qcprcz7w49gkv3wnat04764ld76hy3arqs779tr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DLA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/dla.svg",
@@ -5364,6 +5627,7 @@
"kind": "native",
"denom": "cw20:juno1j0a9ymgngasfn3l5me8qpd53l5zlm9wurfdk7r65s5mg6tkxal3qpgf5se",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GLTO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/glto.svg",
@@ -5373,6 +5637,7 @@
"kind": "native",
"denom": "cw20:juno1gz8cf86zr4vw9cjcyyv432vgdaecvr9n254d3uwwkx9rermekddsxzageh",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GKEY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/gkey.svg",
@@ -5382,6 +5647,7 @@
"kind": "native",
"denom": "cw20:juno1t46z6hg8vvsena7sue0vg6w85ljar3cundplkre9sz0skeqkap9sxyyy6m",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HOLE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/hole.svg",
@@ -5391,6 +5657,7 @@
"kind": "native",
"denom": "cw20:juno1dd0k0um5rqncfueza62w9sentdfh3ec4nw4aq4lk5hkjl63vljqscth9gv",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEJUNO",
"coingeckoId": "stakeeasy-juno-derivative",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/sejuno.svg",
@@ -5400,6 +5667,7 @@
"kind": "native",
"denom": "cw20:juno1wwnhkagvcd3tjz6f8vsdsw5plqnw8qy2aj3rrhqr2axvktzv9q2qz8jxn3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BJUNO",
"coingeckoId": "stakeeasy-bjuno",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/bjuno.svg",
@@ -5409,6 +5677,7 @@
"kind": "native",
"denom": "cw20:juno159q8t5g02744lxq8lfmcn6f78qqulq9wn3y9w7lxjgkz4e0a6kvsfvapse",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SOLAR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/solar.svg",
@@ -5418,6 +5687,7 @@
"kind": "native",
"denom": "cw20:juno19rqljkh95gh40s7qdx40ksx3zq5tm4qsmsrdz9smw668x9zdr3lqtg33mf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEASY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/seasy.svg",
@@ -5427,6 +5697,7 @@
"kind": "native",
"denom": "cw20:juno1p8x807f6h222ur0vssqy3qk6mcpa40gw2pchquz5atl935t7kvyq894ne3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MUSE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/muse.png",
@@ -5436,6 +5707,7 @@
"kind": "native",
"denom": "cw20:juno1qsrercqegvs4ye0yqg93knv73ye5dc3prqwd6jcdcuj8ggp6w0us66deup",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOOP",
"coingeckoId": "loop",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/loop.png",
@@ -5445,6 +5717,7 @@
"kind": "native",
"denom": "cw20:juno1cltgm8v842gu54srmejewghnd6uqa26lzkpa635wzra9m9xuudkqa2gtcz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FURY",
"coingeckoId": "fanfury",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/fanfury.png",
@@ -5454,6 +5727,7 @@
"kind": "native",
"denom": "cw20:juno1rws84uz7969aaa7pej303udhlkt3j9ca0l3egpcae98jwak9quzq8szn2l",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PHMN",
"coingeckoId": "posthuman",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/phmn.svg",
@@ -5463,6 +5737,7 @@
"kind": "native",
"denom": "cw20:juno1u45shlp0q4gcckvsj06ss4xuvsu0z24a0d0vr9ce6r24pht4e5xq7q995n",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HOPERS",
"coingeckoId": "hopers-io ",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/hopers.svg",
@@ -5472,6 +5747,7 @@
"kind": "native",
"denom": "cw20:juno1g647t78y2ulqlm3lss8rs3d0spzd0teuwhdvnqn92tr79yltk9dq2h24za",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RED",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/red.png",
@@ -5481,6 +5757,7 @@
"kind": "native",
"denom": "cw20:juno14q8kk464fafql2fwmlsgvgcdl6h2csqpzv4hr025fmcvgjahpess32k0j7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLUE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/blue.png",
@@ -5490,6 +5767,7 @@
"kind": "native",
"denom": "cw20:juno1mkw83sv6c7sjdvsaplrzc8yaes9l42p4mhy0ssuxjnyzl87c9eps7ce3m9",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WYND",
"coingeckoId": "wynd",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/wynd.svg",
@@ -5499,6 +5777,7 @@
"kind": "native",
"denom": "juno1s2dp05rspeuzzpzyzdchk262szehrtfpz847uvf98cnwh53ulx4qg20qwj",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BANANA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/banana.png",
@@ -5508,6 +5787,7 @@
"kind": "native",
"denom": "cw20:juno1qmlchtmjpvu0cr7u0tad2pq8838h6farrrjzp39eqa9xswg7teussrswlq",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NRIDE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/nride.svg",
@@ -5517,6 +5797,7 @@
"kind": "native",
"denom": "cw20:juno14lycavan8gvpjn97aapzvwmsj8kyrvf644p05r0hu79namyj3ens87650k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SGNL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/sgnl.png",
@@ -5526,6 +5807,7 @@
"kind": "native",
"denom": "cw20:juno1zkwveux7y6fmsr88atf3cyffx96p0c96qr8tgcsj7vfnhx7sal3s3zu3ps",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JAPE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/jape.png",
@@ -5535,6 +5817,7 @@
"kind": "native",
"denom": "cw20:juno12wxyvtqe76x2a5jj6ckp2hfq8v32m6rvyyxwwufl2tksqvkt7whqczv6pa",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/catom.png",
@@ -5544,6 +5827,7 @@
"kind": "native",
"denom": "cw20:juno1g0wuyu2f49ncf94r65278puxzclf5arse9f3kvffxyv4se4vgdmsk4dvqz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HOWL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/howl.png",
@@ -5553,6 +5837,7 @@
"kind": "native",
"denom": "cw20:juno1u8cr3hcjvfkzxcaacv9q75uw9hwjmn8pucc93pmy6yvkzz79kh3qncca8x",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FOX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/fox.png",
@@ -5562,6 +5847,7 @@
"kind": "native",
"denom": "cw20:juno1xekkh27punj0uxruv3gvuydyt856fax0nu750xns99t2qcxp7xmsqwhfma",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GRDN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/guardian.png",
@@ -5571,6 +5857,7 @@
"kind": "native",
"denom": "cw20:juno166heaxlyntd33a5euh4rrz26svhean4klzw594esmd02l4atan6sazy2my",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MNPU",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/mnpu.svg",
@@ -5580,6 +5867,7 @@
"kind": "native",
"denom": "cw20:juno10gthz5ufgrpuk5cscve2f0hjp56wgp90psqxcrqlg4m9mcu9dh8q4864xy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KLEO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/kleomedes.png",
@@ -5589,6 +5877,7 @@
"kind": "native",
"denom": "cw20:juno1qqwf3lkfjhp77yja7gmg3y95pda0e5xctqrdhf3wvwdd79flagvqfgrgxp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SKOJ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/sikoba.svg",
@@ -5598,6 +5887,7 @@
"kind": "native",
"denom": "cw20:juno1x5qt47rw84c4k6xvvywtrd40p8gxjt8wnmlahlqg07qevah3f8lqwxfs7z",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SHIBAC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/shibacosmos.png",
@@ -5607,6 +5897,7 @@
"kind": "native",
"denom": "cw20:juno1ngww7zxak55fql42wmyqrr4rhzpne24hhs4p3w4cwhcdgqgr3hxsmzl9zg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CLST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/celestims.png",
@@ -5616,6 +5907,7 @@
"kind": "native",
"denom": "cw20:juno1m4h8q4p305wgy7vkux0w6e5ylhqll3s6pmadhxkhqtuwd5wlxhxs8xklsw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WATR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/watr.png",
@@ -5625,6 +5917,7 @@
"kind": "native",
"denom": "cw20:juno1ju8k8sqwsqu5k6umrypmtyqu2wqcpnrkf4w4mntvl0javt4nma7s8lzgss",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CASA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/casa.png",
@@ -5634,6 +5927,7 @@
"kind": "native",
"denom": "cw20:juno1j4ux0f6gt7e82z7jdpm25v4g2gts880ap64rdwa49989wzhd0dfqed6vqm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SUMMIT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/summit.png",
@@ -5643,6 +5937,7 @@
"kind": "native",
"denom": "cw20:juno13ca2g36ng6etcfhr9qxx352uw2n5e92np54thfkm3w3nzlhsgvwsjaqlyq",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MANNA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/manna.png",
@@ -5652,6 +5947,7 @@
"kind": "native",
"denom": "cw20:juno12etxwkxvms0uy9ak8g3pyq6a53myukufdnx82pakzmjmpm77a0ksr9gs5v",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EMPWR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/empwr.png",
@@ -5661,6 +5957,7 @@
"kind": "native",
"denom": "cw20:juno1525fuspletvzykpgr2atxpymu9le4mghd7qq4a4u23uwqzc2f3fq7fmafd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MIDDLE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/middle.png",
@@ -5670,6 +5967,7 @@
"kind": "native",
"denom": "cw20:juno17703kcxtsg37hryxnestejyyycuv5yyvnghp2e7w0kqvafnnyetsgzq62w",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SUNSET",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/sunset.png",
@@ -5679,6 +5977,7 @@
"kind": "native",
"denom": "cw20:juno1uu3rxu7w7fpfj4sl4xpxppgymk57mzdzn6kg7492jdxh5dwk7d2qq9429e",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TREE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/livingtree.png",
@@ -5688,6 +5987,7 @@
"kind": "native",
"denom": "cw20:juno1jwdy7v4egw36pd84aeks3ww6n8k7zhsumd4ac8q5lts83ppxueus4626e8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "INVDRS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/invdrs.png",
@@ -5697,6 +5997,7 @@
"kind": "native",
"denom": "cw20:juno1jrr0tuuzxrrwcg6hgeqhw5wqpck2y55734e7zcrp745aardlp0qqg8jz06",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "APEMOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/apemos.png",
@@ -5706,6 +6007,7 @@
"kind": "native",
"denom": "cw20:juno1ytymtllllsp3hfmndvcp802p2xmy5s8m59ufel8xv9ahyxyfs4hs4kd4je",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OSDOGE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/osdoge.png",
@@ -5715,6 +6017,7 @@
"kind": "native",
"denom": "cw20:juno1k2ruzzvvwwtwny6gq6kcwyfhkzahaunp685wmz4hafplduekj98q9hgs6d",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DOGA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/doga.png",
@@ -5724,6 +6027,7 @@
"kind": "native",
"denom": "cw20:juno1zqrj3ta4u7ylv0wqzd8t8q3jrr9rdmn43zuzp9zemeunecnhy8fss778g7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PEPE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/pepe.png",
@@ -5733,6 +6037,7 @@
"kind": "native",
"denom": "cw20:juno1f5datjdse3mdgrapwuzs3prl7pvxxht48ns6calnn0t77v2s9l8s0qu488",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CATMOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/catmos.png",
@@ -5742,6 +6047,7 @@
"kind": "native",
"denom": "cw20:juno1dyyf7pxeassxvftf570krv7fdf5r8e4r04mp99h0mllsqzp3rs4q7y8yqg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SPACER",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/spacer.png",
@@ -5751,6 +6057,7 @@
"kind": "native",
"denom": "cw20:juno1dpany8c0lj526lsa02sldv7shzvnw5dt5ues72rk35hd69rrydxqeraz8l",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "LIGHT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/light.png",
@@ -5760,6 +6067,7 @@
"kind": "native",
"denom": "cw20:juno1llg7q2d5dqlrqzh5dxv8c7kzzjszld34s5vktqmlmaaxqjssz43sxyhq0d",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MILE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/mille.png",
@@ -5769,6 +6077,7 @@
"kind": "native",
"denom": "cw20:juno1lpvx3mv2a6ddzfjc7zzz2v2cm5gqgqf0hx67hc5p5qwn7hz4cdjsnznhu8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "VOID",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/void.png",
@@ -5778,6 +6087,7 @@
"kind": "native",
"denom": "cw20:juno10vgf2u03ufcf25tspgn05l7j3tfg0j63ljgpffy98t697m5r5hmqaw95ux",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SLCA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/silica.png",
@@ -5787,6 +6097,7 @@
"kind": "native",
"denom": "cw20:juno1epxnvge53c4hkcmqzlxryw5fp7eae2utyk6ehjcfpwajwp48km3sgxsh9k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PEPEC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/pepec.png",
@@ -5796,6 +6107,7 @@
"kind": "native",
"denom": "cw20:juno15au4k2jgwd0jnchy0fkg3lm00fpt7jt0j2duuzradn2q7sega2dszyn5pp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PLTN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/pltn.png",
@@ -5805,6 +6117,7 @@
"kind": "native",
"denom": "cw20:juno12mcwmd6wqhledkjsurlfqtc8j0pedvxlcxw3gs4kh2qf808ehehsen8nmw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "YFD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/yfd.svg",
@@ -5814,6 +6127,7 @@
"kind": "native",
"denom": "factory/juno1qly4zcmzr2gyxtze5yt9chv2srczwwunppxjfh/NEXX",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NEXX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/nexx.png",
@@ -5823,6 +6137,7 @@
"kind": "native",
"denom": "factory/juno1u805lv20qc6jy7c3ttre7nct6uyl20pfky5r7e/DGL",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DGL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/dgl.png",
@@ -5832,6 +6147,7 @@
"kind": "native",
"denom": "cw20:juno1a0khag6cfzu5lrwazmyndjgvlsuk7g4vn9jd8ceym8f4jf6v2l9q6d348a",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampJUNO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/ampjuno.svg",
@@ -5841,6 +6157,7 @@
"kind": "native",
"denom": "cw20:juno14fz92ehqt37e096xr95kmy8nc0kz803uezxtg4fwx7agjjma86sqm8mg3h",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "BITS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/bits.png",
@@ -5850,6 +6167,7 @@
"kind": "native",
"denom": "cw20:juno13epyeat7ef0k7q6kllmyvc8zpfd9xm7cqjrgtk0qkgrk7n5mjfmq8979jw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "POIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/poil.png",
@@ -5859,6 +6177,7 @@
"kind": "native",
"denom": "factory/juno195asgku87kxgu48s447z0ryhsyn5rl3yzvfw0d/uhava",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HAVA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/juno/images/hava.png",
@@ -5897,6 +6216,7 @@
"kind": "native",
"denom": "ujunox",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JUNOX",
"coingeckoId": "juno-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/junotestnet/images/juno.svg",
@@ -5906,6 +6226,7 @@
"kind": "native",
"denom": "factory/juno12klaltyqvg2j6v034jwdxrk5n4242ttse4sdpt/NEXX",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NEXX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/junotestnet/images/nexx.png",
@@ -5943,6 +6264,7 @@
"kind": "native",
"denom": "ukava",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KAVA",
"coingeckoId": "kava",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kava/images/kava.svg",
@@ -5952,6 +6274,7 @@
"kind": "native",
"denom": "hard",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HARD",
"coingeckoId": "kava-lend",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kava/images/hard.svg",
@@ -5961,6 +6284,7 @@
"kind": "native",
"denom": "swp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SWP",
"coingeckoId": "kava-swap",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kava/images/swp.svg",
@@ -5970,6 +6294,7 @@
"kind": "native",
"denom": "usdx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDX",
"coingeckoId": "usdx",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kava/images/usdx.svg",
@@ -5979,6 +6304,7 @@
"kind": "native",
"denom": "erc20/tether/usdt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDT",
"coingeckoId": "tether",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.svg",
@@ -6017,6 +6343,7 @@
"kind": "native",
"denom": "uxki",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XKI",
"coingeckoId": "ki",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kichain/images/xki.svg",
@@ -6026,6 +6353,7 @@
"kind": "native",
"denom": "cw20:ki1dt3lk455ed360pna38fkhqn0p8y44qndsr77qu73ghyaz2zv4whq83mwdy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LVN",
"coingeckoId": "lvn",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kichain/images/lvn.png",
@@ -6064,6 +6392,7 @@
"kind": "native",
"denom": "utki",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TKI",
"coingeckoId": "ki",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kichain/images/xki.svg",
@@ -6101,6 +6430,7 @@
"kind": "native",
"denom": "udarc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DARC",
"coingeckoId": "darcmatter-coin",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/konstellation/images/darc.svg",
@@ -6139,6 +6469,7 @@
"kind": "native",
"denom": "ukuji",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KUJI",
"coingeckoId": "kujira",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/kuji.svg",
@@ -6148,6 +6479,7 @@
"kind": "native",
"denom": "factory/kujira1qk00h5atutpsv900x202pxx42npjr9thg58dnqpa72f2p7m2luase444a7/uusk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USK",
"coingeckoId": "usk",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/usk.svg",
@@ -6157,6 +6489,7 @@
"kind": "native",
"denom": "factory/kujira1m96ucsfpt2yy72w09z2rxjdj38y5qd8lqx5jtggnejmdua2ynpnsxyvjex/urcpt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qcKUJI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/qckuji.svg",
@@ -6166,6 +6499,7 @@
"kind": "native",
"denom": "factory/kujira1n3fr5f56r2ce0s37wdvwrk98yhhq3unnxgcqus8nzsfxvllk0yxquurqty/ampKUJI",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampKUJI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/ampkuji.svg",
@@ -6175,6 +6509,7 @@
"kind": "native",
"denom": "factory/kujira1643jxg8wasy5cfcn7xm8rd742yeazcksqlg4d7/umnta",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MNTA",
"coingeckoId": "mantadao",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/mnta.svg",
@@ -6184,6 +6519,7 @@
"kind": "native",
"denom": "factory/kujira1qzu3up50auxhqyzfq56znuj8n38q2ra7daaf9ef7vg8gu66jh4fqd2wd2y/urcpt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qcMNTA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/qcmnta.svg",
@@ -6193,6 +6529,7 @@
"kind": "native",
"denom": "factory/kujira175yatpvkpgw07w0chhzuks3zrrae9z9g2y6r7u5pzqesyau4x9eqqyv0rr/ampMNTA",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampMNTA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/ampmnta.png",
@@ -6202,6 +6539,7 @@
"kind": "native",
"denom": "factory/kujira12cjjeytrqcj25uv349thltcygnp9k0kukpct0e/uwink",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WINK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/wink.svg",
@@ -6211,6 +6549,7 @@
"kind": "native",
"denom": "factory/kujira1slueerjz7mx9jp45u3y0rjwtvhcf8a68wf2mjt/ublend",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLEND",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/blend.svg",
@@ -6220,6 +6559,7 @@
"kind": "native",
"denom": "factory/kujira1sc6a0347cc5q3k890jj0pf3ylx2s38rh4sza4t/ufuzn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FUZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/fuzion.svg",
@@ -6229,6 +6569,7 @@
"kind": "native",
"denom": "factory/kujira1sc6a0347cc5q3k890jj0pf3ylx2s38rh4sza4t/urfuzn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "rFUZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/fuzionr.png",
@@ -6238,6 +6579,7 @@
"kind": "native",
"denom": "factory/kujira1sc6a0347cc5q3k890jj0pf3ylx2s38rh4sza4t/uyfuzn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "yFUZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/fuziony.svg",
@@ -6247,6 +6589,7 @@
"kind": "native",
"denom": "factory/kujira1l04ged98c7a7s9tllu62ld09ztylwf442qgm4thfgmadrvngeumsz4zrh2/urcpt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qcFUZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/qcfuzn.svg",
@@ -6256,6 +6599,7 @@
"kind": "native",
"denom": "factory/kujira1aaudpfr9y23lt9d45hrmskphpdfaq9ajxd3ukh/unstk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NSTK",
"coingeckoId": "unstake-fi",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/nstk.svg",
@@ -6265,6 +6609,7 @@
"kind": "native",
"denom": "factory/kujira1swkuyt08z74n5jl7zr6hx0ru5sa2yev5v896p6/local",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOCAL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/local.png",
@@ -6274,6 +6619,7 @@
"kind": "native",
"denom": "factory/kujira166ysf07ze5suazfzj0r05tv8amk2yn8zvsfuu7/uplnk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PLNK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kujira/images/PLNK_drk.png",
@@ -6312,6 +6658,7 @@
"kind": "native",
"denom": "ukuji",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KUJI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/kujiratestnet/images/kuji.png",
@@ -6321,6 +6668,7 @@
"kind": "native",
"denom": "factory/kujira16qpvzhmawvsm8mcj4hdvtz25dadatdhhgw79xa/FUZN",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FUZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/kujiratestnet/images/fuzn.png",
@@ -6358,6 +6706,7 @@
"kind": "native",
"denom": "ukyve",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KYVE",
"coingeckoId": "kyve-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kyve/images/kyve-token.svg",
@@ -6396,6 +6745,7 @@
"kind": "native",
"denom": "tkyve",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KYVE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/kyvetestnet/images/kyve.svg",
@@ -6433,6 +6783,7 @@
"kind": "native",
"denom": "tkyve",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "KYVE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/kyvedevnet/images/kyve.svg",
@@ -6470,6 +6821,7 @@
"kind": "native",
"denom": "ulamb",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "LAMB",
"coingeckoId": "lambda",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/lambda/images/lambda.svg",
@@ -6508,6 +6860,7 @@
"kind": "native",
"denom": "ulava",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LAVA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/lavatestnet/images/lava-icon.svg",
@@ -6546,6 +6899,7 @@
"kind": "native",
"denom": "nanolike",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "LIKE",
"coingeckoId": "likecoin",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/likecoin/images/like.svg",
@@ -6584,6 +6938,7 @@
"kind": "native",
"denom": "nanoekil",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "EKIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/likecoin/images/like.svg",
@@ -6622,6 +6977,7 @@
"kind": "native",
"denom": "aLYT",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "LYT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/logos/images/logos.svg",
@@ -6660,6 +7016,7 @@
"kind": "native",
"denom": "ulyl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LYL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/loyal/images/lyl.svg",
@@ -6698,6 +7055,7 @@
"kind": "native",
"denom": "ulum",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUM",
"coingeckoId": "lum-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/lumnetwork/images/lum.svg",
@@ -6736,6 +7094,7 @@
"kind": "native",
"denom": "ulumen",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUMEN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/lumenx/images/lumen.svg",
@@ -6774,6 +7133,7 @@
"kind": "native",
"denom": "ulumen",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUMEN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/lumenxtestnet/images/lumen.svg",
@@ -6811,6 +7171,7 @@
"kind": "native",
"denom": "umars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MARS",
"coingeckoId": "mars-protocol-a7fcbcfb-fd61-4017-92f0-7ee9f9cc6da3",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mars/images/mars-token.svg",
@@ -6849,6 +7210,7 @@
"kind": "native",
"denom": "umars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MARS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mars/images/mars-token.svg",
@@ -6887,6 +7249,7 @@
"kind": "native",
"denom": "cacao",
"decimals": 10,
+ "variant": "cosmos",
"displayName": "CACAO",
"coingeckoId": "cacao",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mayachain/images/cacao.svg",
@@ -6896,6 +7259,7 @@
"kind": "native",
"denom": "maya",
"decimals": 4,
+ "variant": "cosmos",
"displayName": "MAYA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mayachain/images/maya.svg",
@@ -6933,6 +7297,7 @@
"kind": "native",
"denom": "umedas",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MEDAS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/medasdigital/images/medas.svg",
@@ -6971,6 +7336,7 @@
"kind": "native",
"denom": "umed",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MED",
"coingeckoId": "medibloc",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/panacea/images/med.svg",
@@ -7009,6 +7375,7 @@
"kind": "native",
"denom": "umeme",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MEME",
"coingeckoId": "meme-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/meme/images/meme.svg",
@@ -7047,6 +7414,7 @@
"kind": "native",
"denom": "utick",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TICK",
"coingeckoId": "microtick",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/microtick/images/tick.svg",
@@ -7085,6 +7453,7 @@
"kind": "native",
"denom": "uwhale",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WHALE",
"coingeckoId": "white-whale",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/white-whale.svg",
@@ -7094,6 +7463,7 @@
"kind": "native",
"denom": "factory/migaloo1436kxs0w2es6xlqpp9rd35e3d0cjnw4sv8j3a7483sgks29jqwgshqdky4/ampWHALE",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampWHALE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/ampwhale.svg",
@@ -7103,6 +7473,7 @@
"kind": "native",
"denom": "factory/migaloo1mf6ptkssddfmxvhdx0ech0k03ktp6kf9yk59renau2gvht3nq2gqdhts4u/boneWhale",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bWHALE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/bWHALE.svg",
@@ -7112,6 +7483,7 @@
"kind": "native",
"denom": "factory/migaloo18a9m9stu3dyvewwcq9qmp85euxqcvln5mefync/fable",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FABLE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/fable.svg",
@@ -7121,6 +7493,7 @@
"kind": "native",
"denom": "factory/migaloo1eqntnl6tzcj9h86psg4y4h6hh05g2h9nj8e09l/urac",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RAC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/rac.svg",
@@ -7130,6 +7503,7 @@
"kind": "native",
"denom": "factory/migaloo1erul6xyq0gk6ws98ncj7lnq9l4jn4gnnu9we73gdz78yyl2lr7qqrvcgup/ash",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ASH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/ash.svg",
@@ -7139,6 +7513,7 @@
"kind": "native",
"denom": "cw20:migaloo10nucfm2zqgzqmy7y7ls398t58pjt9cwjsvpy88y2nvamtl34rgmqt5em2v",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mUSDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/mUSDC.svg",
@@ -7148,6 +7523,7 @@
"kind": "native",
"denom": "factory/migaloo1etlu2h30tjvv8rfa4fwdc43c92f6ul5w9acxzk/uguppy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GUPPY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/guppy.png",
@@ -7157,6 +7533,7 @@
"kind": "native",
"denom": "factory/migaloo1t862qdu9mj5hr3j727247acypym3ej47axu22rrapm4tqlcpuseqltxwq5/ophir",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OPHIR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/ophir.png",
@@ -7195,6 +7572,7 @@
"kind": "native",
"denom": "uwhale",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WHALE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/migaloo/images/white-whale.svg",
@@ -7233,6 +7611,7 @@
"kind": "native",
"denom": "umis",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mises/images/mises.png",
@@ -7271,6 +7650,7 @@
"kind": "native",
"denom": "utia",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TIA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/celestiatestnet3/images/celestia.svg",
@@ -7308,6 +7688,7 @@
"kind": "native",
"denom": "umun",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MUN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mun/images/mun.svg",
@@ -7346,6 +7727,7 @@
"kind": "native",
"denom": "aMYT",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "MYT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mythos/images/mythos.svg",
@@ -7384,6 +7766,7 @@
"kind": "native",
"denom": "untrn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NTRN",
"coingeckoId": "neutron-3",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/ntrn.svg",
@@ -7393,6 +7776,7 @@
"kind": "native",
"denom": "factory/neutron14henrqx9y328fjrdvz6l6d92r0t7g5hk86q5nd/uastropepe",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ASTROPEPE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/astropepe.png",
@@ -7402,6 +7786,7 @@
"kind": "native",
"denom": "factory/neutron1ug740qrkquxzrk2hh29qrlx3sktkfml3je7juusc2te7xmvsscns0n2wry/wstETH",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "wstETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/wsteth.svg",
@@ -7411,6 +7796,7 @@
"kind": "native",
"denom": "factory/neutron1p8d89wvxyjcnawmgw72klknr3lg9gwwl6ypxda/newt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NEWT",
"coingeckoId": "newt",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/newt.png",
@@ -7420,6 +7806,7 @@
"kind": "native",
"denom": "factory/neutron1tklm6cvr2wxg8k65t8gh5ewslnzdfd5fsk0w3f/corgi",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CORGI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/babycorgi.png",
@@ -7429,6 +7816,7 @@
"kind": "native",
"denom": "factory/neutron170v88vrtnedesyfytuku257cggxc79rd7lwt7q/ucircus",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CIRCUS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/circus.png",
@@ -7438,6 +7826,7 @@
"kind": "native",
"denom": "factory/neutron108x7vp9zv22d6wxrs9as8dshd3pd5vsga463yd/JIMMY",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JIMMY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/jimmy.png",
@@ -7447,6 +7836,7 @@
"kind": "native",
"denom": "factory/neutron143wp6g8paqasnuuey6zyapucknwy9rhnld8hkr/bad",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BAD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/bad.png",
@@ -7456,6 +7846,7 @@
"kind": "native",
"denom": "neutron1fjzg7fmv770hsvahqm0nwnu6grs3rjnd2wa6fvm9unv6vedkzekqpw44qj",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/bitcosmos.png",
@@ -7465,6 +7856,7 @@
"kind": "native",
"denom": "neutron12h09p8hq5y4xpsmcuxxzsn9juef4f6jvekp8yefc6xnlwm6uumnsdk29wf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WTF",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/WTF.png",
@@ -7474,6 +7866,7 @@
"kind": "native",
"denom": "factory/neutron1t5qrjtyryh8gzt800qr5vylhh2f8cmx4wmz9mc/ugoddard",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GODRD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/goddardntrn.png",
@@ -7483,6 +7876,7 @@
"kind": "native",
"denom": "factory/neutron154gg0wtm2v4h9ur8xg32ep64e8ef0g5twlsgvfeajqwghdryvyqsqhgk8e/APOLLO",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "APOLLO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/apollo.svg",
@@ -7492,6 +7886,7 @@
"kind": "native",
"denom": "factory/neutron1ume2n42r5j0660gegrr28fzdze7aqf7r5cd9y6/newtroll",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NTRL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/newtroll.svg",
@@ -7501,6 +7896,7 @@
"kind": "native",
"denom": "factory/neutron1t24nc7whl77relnu3taxyg3p66pjyuk82png2y/uretro",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RETRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/neutron/images/retro.svg",
@@ -7539,6 +7935,7 @@
"kind": "native",
"denom": "untrn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NTRN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/neutrontestnet/images/neutron.svg",
@@ -7577,6 +7974,7 @@
"kind": "native",
"denom": "unibi",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NIBI",
"coingeckoId": "nibi",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nibiru/images/nibiru.svg",
@@ -7615,6 +8013,7 @@
"kind": "native",
"denom": "ustake",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STAKE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/stake.svg",
@@ -7624,6 +8023,7 @@
"kind": "native",
"denom": "ufrienzies",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FRNZ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/frnz.svg",
@@ -7633,6 +8033,7 @@
"kind": "native",
"denom": "uusdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "usd-coin",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/USDCoin.svg",
@@ -7671,6 +8072,7 @@
"kind": "native",
"denom": "ustake",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STAKE",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -7680,6 +8082,7 @@
"kind": "native",
"denom": "ulove",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOVE",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -7689,6 +8092,7 @@
"kind": "native",
"denom": "uusdc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -7698,6 +8102,7 @@
"kind": "native",
"denom": "uusdlr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDLR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/nobletestnet/images/usdlr.svg",
@@ -7735,6 +8140,7 @@
"kind": "native",
"denom": "unois",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NOIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nois/images/nois.svg",
@@ -7773,6 +8179,7 @@
"kind": "native",
"denom": "unois",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NOIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nois/images/nois.svg",
@@ -7811,6 +8218,7 @@
"kind": "native",
"denom": "unls",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NLS",
"coingeckoId": "nolus",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nolus/images/nolus.svg",
@@ -7849,6 +8257,7 @@
"kind": "native",
"denom": "unls",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NLS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/nolustestnet/images/nolus.svg",
@@ -7887,6 +8296,7 @@
"kind": "native",
"denom": "unom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nomic/images/nom.svg",
@@ -7896,6 +8306,7 @@
"kind": "native",
"denom": "usat",
"decimals": 14,
+ "variant": "cosmos",
"displayName": "nBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nomic/images/nbtc.svg",
@@ -7934,6 +8345,7 @@
"kind": "native",
"denom": "unyx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NYX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nyx/images/nyx.png",
@@ -7943,6 +8355,7 @@
"kind": "native",
"denom": "unym",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NYM",
"coingeckoId": "nym",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/nyx/images/nym.png",
@@ -7981,6 +8394,7 @@
"kind": "native",
"denom": "uocta",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OCTA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/octa/images/octa.svg",
@@ -8019,6 +8433,7 @@
"kind": "native",
"denom": "loki",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ODIN",
"coingeckoId": "odin-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/odin/images/odin.svg",
@@ -8028,6 +8443,7 @@
"kind": "native",
"denom": "mGeo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GEO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/odin/images/geo.svg",
@@ -8037,6 +8453,7 @@
"kind": "native",
"denom": "mO9W",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "O9W",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/odin/images/o9w.svg",
@@ -8075,6 +8492,7 @@
"kind": "native",
"denom": "wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "OKT",
"coingeckoId": "oec-token",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/okexchain/images/okc.png",
@@ -8113,6 +8531,7 @@
"kind": "native",
"denom": "uknow",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KNOW",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/okp4testnet/images/okp4.png",
@@ -8151,6 +8570,7 @@
"kind": "native",
"denom": "uflix",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FLIX",
"coingeckoId": "omniflix-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/omniflixhub/images/flix.svg",
@@ -8189,6 +8609,7 @@
"kind": "native",
"denom": "anom",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "NOM",
"coingeckoId": "onomy-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/onomy/images/nom.svg",
@@ -8227,6 +8648,7 @@
"kind": "native",
"denom": "orai",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ORAI",
"coingeckoId": "oraichain-token",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/oraichain/images/orai-white.svg",
@@ -8270,6 +8692,7 @@
"denom": "uosmo",
"displayName": "OSMO",
"decimals": 6,
+ "variant": "cosmos",
"coingeckoId": "osmosis",
"icon": "osmosis-circle.svg",
"kind": "native",
@@ -8346,6 +8769,7 @@
"denom": "uosmo",
"displayName": "OSMO",
"decimals": 6,
+ "variant": "cosmos",
"coingeckoId": "osmosis",
"icon": "osmosis-circle.svg",
"kind": "native",
@@ -8406,6 +8830,7 @@
"kind": "native",
"denom": "uosmo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OSMO",
"coingeckoId": "osmosis",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/osmo.svg",
@@ -8415,6 +8840,7 @@
"kind": "native",
"denom": "uion",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ION",
"coingeckoId": "ion",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/ion.svg",
@@ -8453,6 +8879,7 @@
"kind": "native",
"denom": "upasg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PASG",
"coingeckoId": "passage",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/passage/images/pasg.png",
@@ -8491,6 +8918,7 @@
"kind": "native",
"denom": "upasg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PASG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/passage/images/pasg.png",
@@ -8529,6 +8957,7 @@
"kind": "native",
"denom": "uxprt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XPRT",
"coingeckoId": "persistence",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/xprt.svg",
@@ -8538,6 +8967,7 @@
"kind": "native",
"denom": "stk/uatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkATOM",
"coingeckoId": "stkatom",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkatom.svg",
@@ -8547,6 +8977,7 @@
"kind": "native",
"denom": "stk/uosmo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkOSMO",
"coingeckoId": "pstake-staked-osmo",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkosmo.svg",
@@ -8585,6 +9016,7 @@
"kind": "native",
"denom": "uxprt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XPRT",
"coingeckoId": "persistence",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/xprt.svg",
@@ -8594,6 +9026,7 @@
"kind": "native",
"denom": "stk/uatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkatom.svg",
@@ -8631,6 +9064,7 @@
"kind": "native",
"denom": "uxprt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XPRT",
"coingeckoId": "persistence",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/xprt.svg",
@@ -8640,6 +9074,7 @@
"kind": "native",
"denom": "stk/uatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkatom.svg",
@@ -8649,6 +9084,7 @@
"kind": "native",
"denom": "stk/uosmo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkOSMO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkosmo.svg",
@@ -8658,6 +9094,7 @@
"kind": "native",
"denom": "stk/adv4tnt",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "stkDV4TNT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/persistence/images/stkdv4tnt.svg",
@@ -8695,6 +9132,7 @@
"kind": "native",
"denom": "aplanq",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "PLQ",
"coingeckoId": "planq",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/planq/images/planq.svg",
@@ -8733,6 +9171,7 @@
"kind": "native",
"denom": "apoint",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "POINT",
"coingeckoId": "point-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/point/images/point-logo.svg",
@@ -8773,6 +9212,7 @@
"denom": "0x0000000000000000000000000000000000000000",
"displayName": "MATIC",
"decimals": 18,
+ "variant": "ethereum",
"coingeckoId": "matic",
"icon": "polygon.svg",
"kind": "native",
@@ -8815,6 +9255,7 @@
"denom": "0x0000000000000000000000000000000000000000",
"displayName": "MATIC",
"decimals": 18,
+ "variant": "ethereum",
"coingeckoId": "matic",
"icon": "polygon.svg",
"kind": "native",
@@ -8853,6 +9294,7 @@
"kind": "native",
"denom": "nhash",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "HASH",
"coingeckoId": "provenance-blockchain",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/provenance/images/prov.svg",
@@ -8891,6 +9333,7 @@
"kind": "native",
"denom": "upryzm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PRYZM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/pryzmtestnet/images/pryzm.svg",
@@ -8929,6 +9372,7 @@
"kind": "native",
"denom": "bsc0x29a63F4B209C29B4DC47f06FFA896F32667DAD2C",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "PURSE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/pundix/images/purse-token-logo.svg",
@@ -8967,6 +9411,7 @@
"kind": "native",
"denom": "uqsr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QSR",
"coingeckoId": "quasar-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quasar/images/quasar.png",
@@ -9005,6 +9450,7 @@
"kind": "native",
"denom": "uqsr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QSR",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -9014,6 +9460,7 @@
"kind": "native",
"denom": "uay",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AYY",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -9023,6 +9470,7 @@
"kind": "native",
"denom": "oro",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ORO",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -9061,6 +9509,7 @@
"kind": "native",
"denom": "uqck",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QCK",
"coingeckoId": "quicksilver",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qck.png",
@@ -9070,6 +9519,7 @@
"kind": "native",
"denom": "uqstars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qSTARS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qstars.svg",
@@ -9079,6 +9529,7 @@
"kind": "native",
"denom": "uqatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qatom.svg",
@@ -9088,6 +9539,7 @@
"kind": "native",
"denom": "uqregen",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qREGEN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qregen.svg",
@@ -9097,6 +9549,7 @@
"kind": "native",
"denom": "uqosmo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qOSMO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qosmo.svg",
@@ -9106,6 +9559,7 @@
"kind": "native",
"denom": "uqsomm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "qSOMM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qsomm.svg",
@@ -9144,6 +9598,7 @@
"kind": "native",
"denom": "uqck",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QCK",
"coingeckoId": "quicksilver",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/quicksilver/images/qck.png",
@@ -9182,6 +9637,7 @@
"kind": "native",
"denom": "uqwoyn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QWOYN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/qwoyn/images/qwoyn.png",
@@ -9220,6 +9676,7 @@
"kind": "native",
"denom": "uqwoyn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "QWOYN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/qwoyntestnet/images/qwoyn.png",
@@ -9258,6 +9715,7 @@
"kind": "native",
"denom": "ario",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "RIO",
"coingeckoId": "realio-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/realio/images/rio.svg",
@@ -9267,6 +9725,7 @@
"kind": "native",
"denom": "arst",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "RST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/realio/images/rst.png",
@@ -9305,6 +9764,7 @@
"kind": "native",
"denom": "arebus",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "REBUS",
"coingeckoId": "rebus",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/rebus/images/rebus.svg",
@@ -9343,6 +9803,7 @@
"kind": "native",
"denom": "uregen",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "REGEN",
"coingeckoId": "regen",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/regen/images/regen.svg",
@@ -9352,6 +9813,7 @@
"kind": "native",
"denom": "eco.uC.NCT",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NCT",
"coingeckoId": "toucan-protocol-nature-carbon-tonne",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/regen/images/nct.svg",
@@ -9390,6 +9852,7 @@
"kind": "native",
"denom": "uatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.svg",
@@ -9427,6 +9890,7 @@
"kind": "native",
"denom": "uatolo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ATOLO",
"coingeckoId": "rizon",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/rizon/images/atolo.svg",
@@ -9469,7 +9933,8 @@
"displayName": "SAGA",
"coingeckoId": "saga-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/saga/images/saga.svg",
- "color": "TODO"
+ "color": "TODO",
+ "variant": "cosmos"
}
],
"features": [],
@@ -9504,6 +9969,7 @@
"kind": "native",
"denom": "utsaga",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TSAGA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/saga/images/saga.svg",
@@ -9545,7 +10011,8 @@
"displayName": "TSAGA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/saga/images/saga.svg",
- "color": "TODO"
+ "color": "TODO",
+ "variant": "cosmos"
}
],
"features": [],
@@ -9580,6 +10047,7 @@
"kind": "native",
"denom": "uakt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AKT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/akash/images/akt.svg",
@@ -9618,6 +10086,7 @@
"kind": "native",
"denom": "uscrt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SCRT",
"coingeckoId": "secret",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/scrt.svg",
@@ -9627,6 +10096,7 @@
"kind": "native",
"denom": "cw20:secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "SIENNA",
"coingeckoId": "sienna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/sienna.svg",
@@ -9636,6 +10106,7 @@
"kind": "native",
"denom": "cw20:secret1qfql357amn448duf5gvp9gr48sxx9tsnhupu3d",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SHD(old)",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/shdold.svg",
@@ -9645,6 +10116,7 @@
"kind": "native",
"denom": "cw20:secret153wu605vvp934xhd4k9dtd640zsep5jkesstdm",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SHD",
"coingeckoId": "shade-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/shd.svg",
@@ -9654,6 +10126,7 @@
"kind": "native",
"denom": "cw20:secret1fl449muk5yq8dlad7a22nje4p5d2pnsgymhjfd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SILK",
"coingeckoId": "silk-bcec1136-561c-4706-a42c-8b67d0d7f7d2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/silk.svg",
@@ -9663,6 +10136,7 @@
"kind": "native",
"denom": "cw20:secret1k6u0cy4feepm6pehnz804zmwakuwdapm69tuc4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stkd-SCRT",
"coingeckoId": "stkd-scrt",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/stkd-scrt.svg",
@@ -9672,6 +10146,7 @@
"kind": "native",
"denom": "cw20:secret1yxcexylwyxlq58umhgsjgstgcg2a0ytfy4d9lt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BUTT",
"coingeckoId": "buttcoin-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/butt.svg",
@@ -9681,6 +10156,7 @@
"kind": "native",
"denom": "cw20:secret12rcvz0umvk875kd6a803txhtlu7y0pnd73kcej",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ALTER",
"coingeckoId": "alter",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/alter.svg",
@@ -9690,6 +10166,7 @@
"kind": "native",
"denom": "cw20:secret1s09x2xvfd2lp2skgzm29w2xtena7s8fq98v852",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AMBER",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/amber.svg",
@@ -9699,6 +10176,7 @@
"kind": "native",
"denom": "cw20:secret197dvnt9yjxwn8sjdlx05f7zuk27lsdxtfnwxse",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SHILL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/shill.svg",
@@ -9737,6 +10215,7 @@
"kind": "native",
"denom": "uscrt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SCRT",
"coingeckoId": "secret",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/scrt.svg",
@@ -9774,6 +10253,7 @@
"kind": "native",
"denom": "uscrt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SCRT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/secretnetwork/images/scrt.svg",
@@ -9811,6 +10291,7 @@
"kind": "native",
"denom": "usei",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEI",
"coingeckoId": "sei-network",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sei/images/sei.svg",
@@ -9820,6 +10301,7 @@
"kind": "native",
"denom": "factory/sei1thgp6wamxwqt7rthfkeehktmq0ujh5kspluw6w/OIN",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OIN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sei/images/oin.png",
@@ -9829,6 +10311,7 @@
"kind": "native",
"denom": "factory/sei1x2fgaaqecvk8kwuqkjqcj27clw5p5g99uawdzy9sc4rku8avumcq3cky4k/ampSEI",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampSEI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sei/images/ampsei.svg",
@@ -9838,6 +10321,7 @@
"kind": "native",
"denom": "factory/sei1fl8pg59wfsgw2wp4aruk38zqccfnc2g8ptrm24/popeye",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "POPEYE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sei/images/popeye.png",
@@ -9847,6 +10331,7 @@
"kind": "native",
"denom": "factory/sei1ta5rkr6y2qlkj7px8w2cvear7m2822q4f4ea0m/sensei",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SENSEI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sei/images/SenseiDog.png",
@@ -9885,6 +10370,7 @@
"kind": "native",
"denom": "usei",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/seitestnet/images/sei.png",
@@ -9923,6 +10409,7 @@
"kind": "native",
"denom": "usei",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/seidevnet3/images/sei.png",
@@ -9960,6 +10447,7 @@
"kind": "native",
"denom": "udvpn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DVPN",
"coingeckoId": "sentinel",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sentinel/images/dvpn.svg",
@@ -9998,6 +10486,7 @@
"kind": "native",
"denom": "usge",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SGE",
"coingeckoId": "six-sigma",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sge/images/sge.svg",
@@ -10036,6 +10525,7 @@
"kind": "native",
"denom": "usge",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SGE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sgetestnet/images/sge.png",
@@ -10074,6 +10564,7 @@
"kind": "native",
"denom": "nshr",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "SHR",
"coingeckoId": "shareledger",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/shareledger/images/token.svg",
@@ -10112,6 +10603,7 @@
"kind": "native",
"denom": "uctk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CTK",
"coingeckoId": "certik",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/shentu/images/ctk.svg",
@@ -10150,6 +10642,7 @@
"kind": "native",
"denom": "rowan",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ROWAN",
"coingeckoId": "sifchain",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sifchain/images/rowan.svg",
@@ -10188,6 +10681,7 @@
"kind": "native",
"denom": "usix",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "six",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/sixtestnet/images/six.png",
@@ -10225,6 +10719,7 @@
"kind": "native",
"denom": "usix",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SIX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/six/images/six.png",
@@ -10262,6 +10757,7 @@
"kind": "native",
"denom": "usomm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SOMM",
"coingeckoId": "sommelier",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/sommelier/images/somm.svg",
@@ -10300,6 +10796,7 @@
"kind": "native",
"denom": "usource",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SOURCE",
"coingeckoId": "source",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/source/images/source.svg",
@@ -10338,6 +10835,7 @@
"kind": "native",
"denom": "usource",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SOURCE",
"coingeckoId": "source-protocol",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/sourcetestnet/images/source.svg",
@@ -10375,6 +10873,7 @@
"kind": "native",
"denom": "ufis",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FIS",
"coingeckoId": "stafi",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stafihub/images/fis.svg",
@@ -10384,6 +10883,7 @@
"kind": "native",
"denom": "uratom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "rATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stafihub/images/ratom.svg",
@@ -10393,6 +10893,7 @@
"kind": "native",
"denom": "uriris",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "rIRIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stafihub/images/riris.svg",
@@ -10402,6 +10903,7 @@
"kind": "native",
"denom": "urhuahua",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "rHUAHUA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stafihub/images/rhuahua.svg",
@@ -10411,6 +10913,7 @@
"kind": "native",
"denom": "urswth",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "rSWTH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stafihub/images/rswth.svg",
@@ -10449,6 +10952,7 @@
"kind": "native",
"denom": "ustars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STARS",
"coingeckoId": "stargaze",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/stars.svg",
@@ -10458,6 +10962,7 @@
"kind": "native",
"denom": "factory/stars16da2uus9zrsy83h23ur42v3lglg5rmyrpqnju4/dust",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STRDST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/dust.svg",
@@ -10467,6 +10972,7 @@
"kind": "native",
"denom": "factory/stars16da2uus9zrsy83h23ur42v3lglg5rmyrpqnju4/mGAZE",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GAZE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/gaze.svg",
@@ -10476,6 +10982,7 @@
"kind": "native",
"denom": "factory/stars16da2uus9zrsy83h23ur42v3lglg5rmyrpqnju4/uBRNCH",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BRNCH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/brnch.svg",
@@ -10485,6 +10992,7 @@
"kind": "native",
"denom": "factory/stars16da2uus9zrsy83h23ur42v3lglg5rmyrpqnju4/uOHH",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "OHH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/ohh.svg",
@@ -10494,6 +11002,7 @@
"kind": "native",
"denom": "factory/stars1xx5976njvxpl9n4v8huvff6cudhx7yuu8e7rt4/usneaky",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SNEAKY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/sneaky.svg",
@@ -10532,6 +11041,7 @@
"kind": "native",
"denom": "ustars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STARS",
"coingeckoId": "stargaze",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stargaze/images/stars.png",
@@ -10569,6 +11079,7 @@
"kind": "native",
"denom": "uiov",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IOV",
"coingeckoId": "starname",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/starname/images/iov.svg",
@@ -10607,6 +11118,7 @@
"kind": "native",
"denom": "ustate",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STATE",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -10644,6 +11156,7 @@
"kind": "native",
"denom": "wei",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "STOS",
"coingeckoId": "stratos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stratos/images/stratos.svg",
@@ -10682,6 +11195,7 @@
"kind": "native",
"denom": "ustrd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STRD",
"coingeckoId": "stride",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/strd.svg",
@@ -10691,6 +11205,7 @@
"kind": "native",
"denom": "stuatom",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stATOM",
"coingeckoId": "stride-staked-atom",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/statom.svg",
@@ -10700,6 +11215,7 @@
"kind": "native",
"denom": "stustars",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stSTARS",
"coingeckoId": "stride-staked-stars",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/ststars.svg",
@@ -10709,6 +11225,7 @@
"kind": "native",
"denom": "stuosmo",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stOSMO",
"coingeckoId": "stride-staked-osmo",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stosmo.svg",
@@ -10718,6 +11235,7 @@
"kind": "native",
"denom": "stujuno",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stJUNO",
"coingeckoId": "stride-staked-juno",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stjuno.svg",
@@ -10727,6 +11245,7 @@
"kind": "native",
"denom": "stuluna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stLUNA",
"coingeckoId": "stride-staked-luna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stluna.svg",
@@ -10736,6 +11255,7 @@
"kind": "native",
"denom": "stinj",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "stINJ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stinj.svg",
@@ -10745,6 +11265,7 @@
"kind": "native",
"denom": "staevmos",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "stEVMOS",
"coingeckoId": "stride-staked-evmos",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stevmos.svg",
@@ -10754,6 +11275,7 @@
"kind": "native",
"denom": "stuumee",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stUMEE",
"coingeckoId": "stride-staked-umee",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stumee.svg",
@@ -10763,6 +11285,7 @@
"kind": "native",
"denom": "stucmdx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stCMDX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stcmdx.svg",
@@ -10772,6 +11295,7 @@
"kind": "native",
"denom": "stusomm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stSOMM",
"coingeckoId": "stride-staked-sommelier",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/stsomm.svg",
@@ -10810,6 +11334,7 @@
"kind": "native",
"denom": "ustrd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STRD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/stride/images/strd.svg",
@@ -10847,6 +11372,7 @@
"kind": "native",
"denom": "utprl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TPRL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/temporaltestnet/images/temporal.png",
@@ -10884,6 +11410,7 @@
"kind": "native",
"denom": "atenet",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "TENET",
"coingeckoId": "tenet-1b000f7b-59cb-4e06-89ce-d62b32d362b9",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/tenet/images/tenet.svg",
@@ -10942,6 +11469,7 @@
{
"denom": "utori",
"displayName": "TORI",
+ "variant": "cosmos",
"decimals": 6,
"coingeckoId": "teritori",
"icon": "teritori-circle.svg",
@@ -11030,6 +11558,7 @@
{
"denom": "utori",
"displayName": "TORI",
+ "variant": "cosmos",
"decimals": 6,
"coingeckoId": "teritori",
"icon": "icons/networks/teritori-circle.svg",
@@ -11120,6 +11649,7 @@
{
"denom": "utori",
"displayName": "TORI",
+ "variant": "cosmos",
"decimals": 6,
"coingeckoId": "teritori",
"icon": "teritori-circle.svg",
@@ -11198,6 +11728,7 @@
"kind": "native",
"denom": "uterpx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TERPX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terpnetwork/images/terp.png",
@@ -11207,6 +11738,7 @@
"kind": "native",
"denom": "uthiolx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "THIOLX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terpnetwork/images/thiol.png",
@@ -11244,6 +11776,7 @@
"kind": "native",
"denom": "uluna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUNA",
"coingeckoId": "terra-luna-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/luna.svg",
@@ -11253,6 +11786,7 @@
"kind": "native",
"denom": "cw20:terra1nsuqsk6kh58ulczatwev87ttq2z6r3pusulg9r24mfj2fvtzd4uq3exn26",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ASTRO",
"coingeckoId": "astroport-fi",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/astro.png",
@@ -11262,6 +11796,7 @@
"kind": "native",
"denom": "cw20:terra1spkm49wd9dqkranhrks4cupecl3rtgeqqljq3qrvrrts2ev2gw6sy5vz3k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DINHEIROS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/Dinheiros.png",
@@ -11271,6 +11806,7 @@
"kind": "native",
"denom": "cw20:terra1sdglum2dt4f3fmq7jrt2phf2tegmnudc7qqqqujkpqcm9ujuxxkqakv5u8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "REIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/Reis.png",
@@ -11280,6 +11816,7 @@
"kind": "native",
"denom": "cw20:terra1qj5hs3e86qn4vm9dvtgtlkdp550r0rayk9wpay44mfw3gn3tr8nq5jw3dg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ESCUDOS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/Escudos.png",
@@ -11289,6 +11826,7 @@
"kind": "native",
"denom": "cw20:terra1cmf8ytutcwrjrv08zskj9phuh46a3w3nkjax7en4hxezsrdr58lqvzy05q",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ALEM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/Alem.png",
@@ -11298,6 +11836,7 @@
"kind": "native",
"denom": "cw20:terra1ecgazyd0waaj3g7l9cmy5gulhxkps2gmxu9ghducvuypjq68mq2s5lvsct",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampLUNA",
"coingeckoId": "eris-amplified-luna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/ampluna.svg",
@@ -11307,6 +11846,7 @@
"kind": "native",
"denom": "cw20:terra1lxx40s29qvkrcj8fsa3yzyehy7w50umdvvnls2r830rys6lu2zns63eelv",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ROAR",
"coingeckoId": "lion-dao",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/roar.png",
@@ -11316,6 +11856,7 @@
"kind": "native",
"denom": "cw20:terra1ynvsz80w9xmhdxucv96gkwpxlwvjgsq75xh2f3pf825c4wfmkfxskq6pqv",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GEM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/gem.png",
@@ -11325,6 +11866,7 @@
"kind": "native",
"denom": "cw20:terra1lalvk0r6nhruel7fvzdppk3tup3mh5j4d4eadrqzfhle4zrf52as58hh9t",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CUB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/cub.png",
@@ -11334,6 +11876,7 @@
"kind": "native",
"denom": "cw20:terra1gwrz9xzhqsygyr5asrgyq3pu0ewpn00mv2zenu86yvx2nlwpe8lqppv584",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BLUE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/blue.png",
@@ -11343,6 +11886,7 @@
"kind": "native",
"denom": "cw20:terra10se906awphtccf4vd83m0ulpmpt9v4msuakmpy0pwvmtxmup3kdq25rayn",
"decimals": 10,
+ "variant": "cosmos",
"displayName": "xxx",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/xxx3.png",
@@ -11352,6 +11896,7 @@
"kind": "native",
"denom": "cw20:terra17aj4ty4sz4yhgm08na8drc0v03v2jwr3waxcqrwhajj729zhl7zqnpc0ml",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bLUNA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/boneluna.png",
@@ -11361,6 +11906,7 @@
"kind": "native",
"denom": "cw20:terra1xp9hrhthzddnl7j5du83gqqr4wmdjm5t0guzg9jp6jwrtpukwfjsjgy4f3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SAYVE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/sayve.svg",
@@ -11370,6 +11916,7 @@
"kind": "native",
"denom": "factory/terra1j35ta0llaxcf55auv2cjqau5a7aee6g8fz7md7my7005cvh23jfsaw83dy/ampWHALEt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampWHALEt",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/ampwhalet.svg",
@@ -11379,6 +11926,7 @@
"kind": "native",
"denom": "factory/terra10j3zrymfrkta2pxe0gklc79gu06tqyuy8c3kh6tqdsrrprsjqkrqzfl4df/boneWHALEt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "boneWHALEt",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/bonewhalet.svg",
@@ -11388,6 +11936,7 @@
"kind": "native",
"denom": "factory/terra1vklefn7n6cchn0u962w3gaszr4vf52wjvd4y95t2sydwpmpdtszsqvk9wy/ampROAR",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ampROAR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/amproar.png",
@@ -11397,6 +11946,7 @@
"kind": "native",
"denom": "cw20:terra1e0efrrrj8d55pflme3dmtyuj7klzcef5cfmz6r2jyqz77kk2jz3qa6drg3",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "NICO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/nicodao.png",
@@ -11406,6 +11956,7 @@
"kind": "native",
"denom": "cw20:terra1rc6ssp5rym7a0hg29xpj4cc9e67tl56kg5jyzgl9qrhfxxc2ugvsnrkala",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEAS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/SEAS.png",
@@ -11415,6 +11966,7 @@
"kind": "native",
"denom": "cw20:terra18vp5s0r7keezm35hdxsgw8zgfnyn8wejdkk893ag2kqncgpqxhjqwjpc0v",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BITZ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/BITZ.png",
@@ -11424,6 +11976,7 @@
"kind": "native",
"denom": "cw20:terra13s5pxw5j2p4ssvzwvxd8l7h30vke8vjgtng75vqgv6p9vddfk3hskfka0l",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SEUL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/seul.png",
@@ -11433,6 +11986,7 @@
"kind": "native",
"denom": "cw20:terra1q328gl40az3cf9x67cgudn8e8w2az9vsmhtkwsgdu7a43rhy5caqc82yr5",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "xSEUL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/xseul.png",
@@ -11442,6 +11996,7 @@
"kind": "native",
"denom": "cw20:terra1c77xqv746m7ghxayrge79dxr4kcezev8g6cnrfled4f3n4ufj0vs5gz28s",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ITO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/I.png",
@@ -11451,6 +12006,7 @@
"kind": "native",
"denom": "cw20:terra1aa7stl3fytvave9xtcexgv0kne4k7ks068dcljkrfj37hy8q270sjadav8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ARMANI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/armani.png",
@@ -11460,6 +12016,7 @@
"kind": "native",
"denom": "cw20:terra1cl273523kmr2uwjhhznq54je69mted2u3ljffm8kp2ap4z3drdksftwqun",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DROGO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/drogo.png",
@@ -11469,6 +12026,7 @@
"kind": "native",
"denom": "cw20:terra1w8xk6rtu40st6lvl3yv7ynw5urm2n686u9cchvrzltmnktzwdesqcwy0nu",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ADO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/ADO.png",
@@ -11507,6 +12065,7 @@
"kind": "native",
"denom": "uluna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUNA",
"coingeckoId": "terra-luna-2",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra2/images/luna.svg",
@@ -11544,6 +12103,7 @@
"kind": "native",
"denom": "uluna",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUNC",
"coingeckoId": "terra-luna",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/luna.svg",
@@ -11553,6 +12113,7 @@
"kind": "native",
"denom": "uusd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USTC",
"coingeckoId": "terrausd",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ust.svg",
@@ -11562,6 +12123,7 @@
"kind": "native",
"denom": "ukrw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KRTC",
"coingeckoId": "terrakrw",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/krt.svg",
@@ -11571,6 +12133,7 @@
"kind": "native",
"denom": "cw20:terra1php5m8a6qd68z02t3zpw4jv2pj4vgw4wz0t8mz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WHALE",
"coingeckoId": "white-whale",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/whale.png",
@@ -11580,6 +12143,7 @@
"kind": "native",
"denom": "cw20:terra1kc87mu460fwkqte29rquh4hc20m54fxwtsx7gp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bluna.png",
@@ -11589,6 +12153,7 @@
"kind": "native",
"denom": "cw20:terra1dzhzukyezv0etz22ud940z7adyv7xgcjkahuun",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/beth.png",
@@ -11598,6 +12163,7 @@
"kind": "native",
"denom": "cw20:terra1hzh9vpxhsk8253se0vv5jj6etdvxu3nv8z07zu",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "aUST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/aust.png",
@@ -11607,6 +12173,7 @@
"kind": "native",
"denom": "cw20:terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ANC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/anc.png",
@@ -11616,6 +12183,7 @@
"kind": "native",
"denom": "cw20:terra15gwkyepfc6xgca5t5zefzwy42uts8l2m4g40k6",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MIR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mir.png",
@@ -11625,6 +12193,7 @@
"kind": "native",
"denom": "cw20:terra1vxtwu4ehgzz77mnfwrntyrmgl64qjs75mpwqaz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mAAPL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/maapl.png",
@@ -11634,6 +12203,7 @@
"kind": "native",
"denom": "cw20:terra1g4x2pzmkc9z3mseewxf758rllg08z3797xly0n",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mABNB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mabnb.png",
@@ -11643,6 +12213,7 @@
"kind": "native",
"denom": "cw20:terra1qelfthdanju7wavc5tq0k5r0rhsyzyyrsn09qy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mAMC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mamc.png",
@@ -11652,6 +12223,7 @@
"kind": "native",
"denom": "cw20:terra18ej5nsuu867fkx4tuy2aglpvqjrkcrjjslap3z",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mAMD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mamd.png",
@@ -11661,6 +12233,7 @@
"kind": "native",
"denom": "cw20:terra165nd2qmrtszehcfrntlplzern7zl4ahtlhd5t2",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mAMZN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mamzn.png",
@@ -11670,6 +12243,7 @@
"kind": "native",
"denom": "cw20:terra1qqfx5jph0rsmkur2zgzyqnfucra45rtjae5vh6",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mARKK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/markk.png",
@@ -11679,6 +12253,7 @@
"kind": "native",
"denom": "cw20:terra1w7zgkcyt7y4zpct9dw8mw362ywvdlydnum2awa",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mBABA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mbaba.png",
@@ -11688,6 +12263,7 @@
"kind": "native",
"denom": "cw20:terra1rhhvx8nzfrx5fufkuft06q5marfkucdqwq5sjw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mbtc.png",
@@ -11697,6 +12273,7 @@
"kind": "native",
"denom": "cw20:terra18wayjpyq28gd970qzgjfmsjj7dmgdk039duhph",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mCOIN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mcoin.png",
@@ -11706,6 +12283,7 @@
"kind": "native",
"denom": "cw20:terra149755r3y0rve30e209awkhn5cxgkn5c8ju9pm5",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mDIS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mdis.png",
@@ -11715,6 +12293,7 @@
"kind": "native",
"denom": "cw20:terra19ya4jpvjvvtggepvmmj6ftmwly3p7way0tt08r",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mDOT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mdot.png",
@@ -11724,6 +12303,7 @@
"kind": "native",
"denom": "cw20:terra1dk3g53js3034x4v5c3vavhj2738une880yu6kx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/meth.png",
@@ -11733,6 +12313,7 @@
"kind": "native",
"denom": "cw20:terra1mqsjugsugfprn3cvgxsrr8akkvdxv2pzc74us7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mFB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mfb.png",
@@ -11742,6 +12323,7 @@
"kind": "native",
"denom": "cw20:terra1l5lrxtwd98ylfy09fn866au6dp76gu8ywnudls",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mGLXY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mglxy.png",
@@ -11751,6 +12333,7 @@
"kind": "native",
"denom": "cw20:terra1m6j6j9gw728n82k78s0j9kq8l5p6ne0xcc820p",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mGME",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mgme.png",
@@ -11760,6 +12343,7 @@
"kind": "native",
"denom": "cw20:terra1h8arz2k547uvmpxctuwush3jzc8fun4s96qgwt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mGOOGL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mgoogl.png",
@@ -11769,6 +12353,7 @@
"kind": "native",
"denom": "cw20:terra137drsu8gce5thf6jr5mxlfghw36rpljt3zj73v",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mGS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mgs.png",
@@ -11778,6 +12363,7 @@
"kind": "native",
"denom": "cw20:terra18yqdfzfhnguerz9du5mnvxsh5kxlknqhcxzjfr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mHOOD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mhood.png",
@@ -11787,6 +12373,7 @@
"kind": "native",
"denom": "cw20:terra10h7ry7apm55h4ez502dqdv9gr53juu85nkd4aq",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mIAU",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/miau.png",
@@ -11796,6 +12383,7 @@
"kind": "native",
"denom": "cw20:terra15hp9pr8y4qsvqvxf3m4xeptlk7l8h60634gqec",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mIAU",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/miau.png",
@@ -11805,6 +12393,7 @@
"kind": "native",
"denom": "cw20:terra1ptdxmj3xmmljzx02nr4auwfuelmj0cnkh8egs2",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mJNJ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mjnj.png",
@@ -11814,6 +12403,7 @@
"kind": "native",
"denom": "cw20:terra1qsnj5gvq8rgs7yws8x5u02gwd5wvtu4tks0hjm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mKO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mko.png",
@@ -11823,6 +12413,7 @@
"kind": "native",
"denom": "cw20:terra1227ppwxxj3jxz8cfgq00jgnxqcny7ryenvkwj6",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mMSFT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mmsft.png",
@@ -11832,6 +12423,7 @@
"kind": "native",
"denom": "cw20:terra1jsxngqasf2zynj5kyh0tgq9mj3zksa5gk35j4k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mNFLX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mnflx.png",
@@ -11841,6 +12433,7 @@
"kind": "native",
"denom": "cw20:terra1dj2cj02zak0nvwy3uj9r9dhhxhdwxnw6psse6p",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mNIO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mnio.png",
@@ -11850,6 +12443,7 @@
"kind": "native",
"denom": "cw20:terra17ana8hvzea0q7w367dm0dw48sxwql39qekpt7g",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mNKE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mnke.png",
@@ -11859,6 +12453,7 @@
"kind": "native",
"denom": "cw20:terra1drsjzvzej4h4qlehcfwclxg4w5l3h5tuvd3jd8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mNVDA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mnvda.png",
@@ -11868,6 +12463,7 @@
"kind": "native",
"denom": "cw20:terra1rh2907984nudl7vh56qjdtvv7947z4dujj92sx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mPYPL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mpypl.png",
@@ -11877,6 +12473,7 @@
"kind": "native",
"denom": "cw20:terra1csk6tc7pdmpr782w527hwhez6gfv632tyf72cp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mQQQ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mqqq.png",
@@ -11886,6 +12483,7 @@
"kind": "native",
"denom": "cw20:terra1246zy658dfgtausf0c4a6ly8sc2e285q4kxqga",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mSBUX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/msbux.png",
@@ -11895,6 +12493,7 @@
"kind": "native",
"denom": "cw20:terra1kscs6uhrqwy6rx5kuw5lwpuqvm3t6j2d6uf2lp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mSLV",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mslv.png",
@@ -11904,6 +12503,7 @@
"kind": "native",
"denom": "cw20:terra1aa00lpfexyycedfg5k2p60l9djcmw0ue5l8fhc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mSPY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mspy.png",
@@ -11913,6 +12513,7 @@
"kind": "native",
"denom": "cw20:terra1u43zu5amjlsgty5j64445fr9yglhm53m576ugh",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mSQ",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/msq.png",
@@ -11922,6 +12523,7 @@
"kind": "native",
"denom": "cw20:terra14y5affaarufk3uscy2vr6pe6w6zqf2wpjzn5sh",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mTSLA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mtsla.png",
@@ -11931,6 +12533,7 @@
"kind": "native",
"denom": "cw20:terra1cc3enj9qgchlrj34cnzhwuclc4vl2z3jl7tkqg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mTWTR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mtwtr.png",
@@ -11940,6 +12543,7 @@
"kind": "native",
"denom": "cw20:terra1lvmx8fsagy70tv0fhmfzdw9h6s3sy4prz38ugf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mUSO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/muso.png",
@@ -11949,6 +12553,7 @@
"kind": "native",
"denom": "cw20:terra19cmt6vzvhnnnfsmccaaxzy2uaj06zjktu6yzjx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mVIXY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mvixy.png",
@@ -11958,6 +12563,7 @@
"kind": "native",
"denom": "cw20:terra1zp3a6q6q4953cz376906g5qfmxnlg77hx3te45",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "mVIXY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mvixy.png",
@@ -11967,6 +12573,7 @@
"kind": "native",
"denom": "cw20:terra1ez46kxtulsdv07538fh5ra5xj8l68mu8eg24vr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOTA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/lota.png",
@@ -11976,6 +12583,7 @@
"kind": "native",
"denom": "cw20:terra17jnhankdfl8vyzj6vejt7ag8uz0cjc9crkl2h7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DPH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/dph.png",
@@ -11985,6 +12593,7 @@
"kind": "native",
"denom": "cw20:terra1kcthelkax4j9x8d3ny6sdag0qmxxynl3qtcrpy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MINE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mine.png",
@@ -11994,6 +12603,7 @@
"kind": "native",
"denom": "cw20:terra1zsaswh926ey8qa5x4vj93kzzlfnef0pstuca0y",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bPsiDP-24m",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bpsidp-24m.png",
@@ -12003,6 +12613,7 @@
"kind": "native",
"denom": "cw20:terra1s5eczhe0h0jutf46re52x5z4r03c8hupacxmdr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SPEC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/spec.png",
@@ -12012,6 +12623,7 @@
"kind": "native",
"denom": "cw20:terra1nef5jf6c7js9x6gkntlehgywvjlpytm7pcgkn4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOOP",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/loop.png",
@@ -12021,6 +12633,7 @@
"kind": "native",
"denom": "cw20:terra1jx4lmmke2srcvpjeereetc9hgegp4g5j0p9r2q",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOOPR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/loopr.png",
@@ -12030,6 +12643,7 @@
"kind": "native",
"denom": "cw20:terra13xujxcrc9dqft4p9a8ls0w3j0xnzm6y2uvve8n",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/stt.png",
@@ -12039,6 +12653,7 @@
"kind": "native",
"denom": "cw20:terra19djkaepjjswucys4npd5ltaxgsntl7jf0xz7w6",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TWD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/twd.png",
@@ -12048,6 +12663,7 @@
"kind": "native",
"denom": "cw20:terra1kvjscdgwuvwc6uzm4rqfjl6nlmuhj28tequlnc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XTRA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xtra.png",
@@ -12057,6 +12673,7 @@
"kind": "native",
"denom": "cw20:terra1vtr50tw0pgqpes34zqu60n554p9x4950wk8f63",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MIAW",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/miaw.png",
@@ -12066,6 +12683,7 @@
"kind": "native",
"denom": "cw20:terra12897djskt9rge8dtmm86w654g7kzckkd698608",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "Psi",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/psi.png",
@@ -12075,6 +12693,7 @@
"kind": "native",
"denom": "cw20:terra10f2mt82kjnkxqj2gepgwl637u2w4ue2z5nhz5j",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "nLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/nluna.svg",
@@ -12084,6 +12703,7 @@
"kind": "native",
"denom": "cw20:terra178v546c407pdnx5rer3hu8s2c0fc924k74ymnn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "nETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/neth.svg",
@@ -12093,6 +12713,7 @@
"kind": "native",
"denom": "cw20:terra1u553zk43jd4rwzc53qrdrq4jc2p8rextyq09dj",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "cnLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cnluna.svg",
@@ -12102,6 +12723,7 @@
"kind": "native",
"denom": "cw20:terra1nagqpmyw55yjphea4rhntlfv87ugmeaj8ym756",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "cnETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cneth.svg",
@@ -12111,6 +12733,7 @@
"kind": "native",
"denom": "cw20:terra13k62n0285wj8ug0ngcgpf7dgnkzqeu279tz636",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "nAVAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/navax.svg",
@@ -12120,6 +12743,7 @@
"kind": "native",
"denom": "cw20:terra1jtdc6zpf95tvh9peuaxwp3v0yqszcnwl8j5ade",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "nATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/natom.svg",
@@ -12129,6 +12753,7 @@
"kind": "native",
"denom": "cw20:terra1dy9kmlm4anr92e42mrkjwzyvfqwz66un00rwr5",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "VKR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/vkr.png",
@@ -12138,6 +12763,7 @@
"kind": "native",
"denom": "cw20:terra1mddcdx0ujx89f38gu7zspk2r2ffdl5enyz2u03",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "ORION",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/orion.png",
@@ -12147,6 +12773,7 @@
"kind": "native",
"denom": "cw20:terra1r5506ckw5tfr3z52jwlek8vg9sn3yflrqrzfsc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TLAND",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tland.png",
@@ -12156,6 +12783,7 @@
"kind": "native",
"denom": "cw20:terra1w0p5zre38ecdy3ez8efd5h9fvgum5s206xknrg",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "vUST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/vust.png",
@@ -12165,6 +12793,7 @@
"kind": "native",
"denom": "cw20:terra14tl83xcwqjy0ken9peu4pjjuu755lrry2uy25r",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "ETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/eth.png",
@@ -12174,6 +12803,7 @@
"kind": "native",
"denom": "cw20:terra1aa7upykmmqqc63l924l5qfap8mrmx5rfdm0v55",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "WBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wbtc.png",
@@ -12183,6 +12813,7 @@
"kind": "native",
"denom": "cw20:terra190tqwgqx7s8qrknz6kckct7v607cu068gfujpk",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SOL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sol.png",
@@ -12192,6 +12823,7 @@
"kind": "native",
"denom": "cw20:terra1dfasranqm4uyaz72r960umxy0w8t6zewqlnkuq",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "MATICet",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/maticet.png",
@@ -12201,6 +12833,7 @@
"kind": "native",
"denom": "cw20:terra1cetg5wruw2wsdjp7j46rj44xdel00z006e9yg8",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "BNB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bnb.png",
@@ -12210,6 +12843,7 @@
"kind": "native",
"denom": "cw20:terra1xvqlpjl2dxyel9qrp6qvtrg04xe3jh9cyxc6av",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "CAKE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cake.png",
@@ -12219,6 +12853,7 @@
"kind": "native",
"denom": "cw20:terra12dfv3f0e6m22z6cnhfn3nxk2en3z3zeqy6ctym",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "LINK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/link.png",
@@ -12228,6 +12863,7 @@
"kind": "native",
"denom": "cw20:terra1csvuzlf92nyemu6tv25h0l79etpe8hz3h5vn4a",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SUSHI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sushi.png",
@@ -12237,6 +12873,7 @@
"kind": "native",
"denom": "cw20:terra1wyxkuy5jq545fn7xfn3enpvs5zg9f9dghf6gxf",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "UNI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/uni.png",
@@ -12246,6 +12883,7 @@
"kind": "native",
"denom": "cw20:terra1ce06wkrdm4vl6t0hvc0g86rsy27pu8yadg3dva",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDTet",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdtet.png",
@@ -12255,6 +12893,7 @@
"kind": "native",
"denom": "cw20:terra1pepwcav40nvj3kh60qqgrk8k07ydmc00xyat06",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDCet",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdcet.png",
@@ -12264,6 +12903,7 @@
"kind": "native",
"denom": "cw20:terra1xfsdgcemqwxp4hhnyk4rle6wr22sseq7j07dnn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KUJI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/kuji.png",
@@ -12273,6 +12913,7 @@
"kind": "native",
"denom": "cw20:terra188w26t95tf4dz77raftme8p75rggatxjxfeknw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "sKUJI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/skuji.png",
@@ -12282,6 +12923,7 @@
"kind": "native",
"denom": "cw20:terra133chr09wu8sakfte5v7vd8qzq9vghtkv4tn0ur",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "wstETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wsteth.png",
@@ -12291,6 +12933,7 @@
"kind": "native",
"denom": "cw20:terra1t9ul45l7m6jw6sxgvnp8e5hj8xzkjsg82g84ap",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "wstSOL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wstsol.png",
@@ -12300,6 +12943,7 @@
"kind": "native",
"denom": "cw20:terra1c3xd5s2j3ejx2d94tvcjfkrdeu6rmz48ghzznj",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "wsbSOL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wsbsol.svg",
@@ -12309,6 +12953,7 @@
"kind": "native",
"denom": "cw20:terra1jxypgnfa07j6w92wazzyskhreq2ey2a5crgt6z",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "LDO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ldo.png",
@@ -12318,6 +12963,7 @@
"kind": "native",
"denom": "cw20:terra1u5szg038ur9kzuular3cae8hq6q5rk5u27tuvz",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "webETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/webeth.svg",
@@ -12327,6 +12973,7 @@
"kind": "native",
"denom": "cw20:terra1yg3j2s986nyp5z7r2lvt0hx3r0lnd7kwvwwtsc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "stLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/stluna.png",
@@ -12336,6 +12983,7 @@
"kind": "native",
"denom": "cw20:terra169edevav3pdrtjcx35j6pvzuv54aevewar4nlh",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "XDEFI",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12345,6 +12993,7 @@
"kind": "native",
"denom": "cw20:terra193c42lfwmlkasvcw22l9qqzc5q2dx208tkd7wl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BTL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/btl.png",
@@ -12354,6 +13003,7 @@
"kind": "native",
"denom": "cw20:terra17y9qkl8dfkeg4py7n0g5407emqnemc3yqk5rup",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LunaX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/lunax.png",
@@ -12363,6 +13013,7 @@
"kind": "native",
"denom": "cw20:terra1m3tdguf59xq3pa2twk5fjte5g6szj5y9x5npy7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUNI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/luni.png",
@@ -12372,6 +13023,7 @@
"kind": "native",
"denom": "cw20:terra13awdgcx40tz5uygkgm79dytez3x87rpg4uhnvu",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PLY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ply.png",
@@ -12381,6 +13033,7 @@
"kind": "native",
"denom": "cw20:terra1u2k0nkenw0p25ljsr4ksh7rxm65y466vkdewwj",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TFLOKI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tfloki.png",
@@ -12390,6 +13043,7 @@
"kind": "native",
"denom": "cw20:terra1a8k3jyv3wf6k3zngza5h6srrxcckdf7zv90p6u",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TFTIC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tftic.png",
@@ -12399,6 +13053,7 @@
"kind": "native",
"denom": "cw20:terra1xt9fgu7965kgvunnjts9zkprd8986kcc444q86",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TFTICII",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tfticii.png",
@@ -12408,6 +13063,7 @@
"kind": "native",
"denom": "cw20:terra1vte2xv7dr8sfnrnwdf9arcyprqgr0hty5ads28",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TFTICIII",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tfticiii.png",
@@ -12417,6 +13073,7 @@
"kind": "native",
"denom": "cw20:terra1hmxxq0y8h79f3228vs0czc4uz5jdgjt0appp26",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MOON",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/moon.png",
@@ -12426,6 +13083,7 @@
"kind": "native",
"denom": "cw20:terra1xj49zyqrwpv5k928jwfpfy2ha668nwdgkwlrg3",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ASTRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/astro.png",
@@ -12435,6 +13093,7 @@
"kind": "native",
"denom": "cw20:terra14lpnyzc9z4g3ugr4lhm8s4nle0tq8vcltkhzh7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "xASTRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xastro.png",
@@ -12444,6 +13103,7 @@
"kind": "native",
"denom": "cw20:terra1w8kvd6cqpsthupsk4l0clwnmek4l3zr7c84kwq",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HALO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/halo.png",
@@ -12453,6 +13113,7 @@
"kind": "native",
"denom": "cw20:terra1kdfsdm3c4reun9j3m4mk3nmyw4a4ns7mj24q3j",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PUG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/pug.png",
@@ -12462,6 +13123,7 @@
"kind": "native",
"denom": "cw20:terra1hnezwjqlhzawcrfysczcxs6xqxu2jawn729kkf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ORNE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/orne.png",
@@ -12471,6 +13133,7 @@
"kind": "native",
"denom": "cw20:terra14vz4v8adanzph278xyeggll4tfww7teh0xtw2y",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TNS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tns.png",
@@ -12480,6 +13143,7 @@
"kind": "native",
"denom": "cw20:terra1td743l5k5cmfy7tqq202g7vkmdvq35q48u2jfm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XRUNE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xrune.png",
@@ -12489,6 +13153,7 @@
"kind": "native",
"denom": "cw20:terra1366wmr8t8rrkh6mag8fagqxntmf2qe4kyte784",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "aLOT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/alot.png",
@@ -12498,6 +13163,7 @@
"kind": "native",
"denom": "cw20:terra1z09gnzufuflz6ckd9k0u456l9dnpgsynu0yyhe",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SITY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sity.svg",
@@ -12507,6 +13173,7 @@
"kind": "native",
"denom": "cw20:terra13zx49nk8wjavedjzu8xkk95r3t0ta43c9ptul7",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GLOW",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/glow.png",
@@ -12516,6 +13183,7 @@
"kind": "native",
"denom": "cw20:terra100yeqvww74h4yaejj6h733thgcafdaukjtw397",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "APOLLO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/apollo.png",
@@ -12525,6 +13193,7 @@
"kind": "native",
"denom": "cw20:terra1a7ye2splpfzyenu0yrdu8t83uzgusx2malkc7u",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ABR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/abr.svg",
@@ -12534,6 +13203,7 @@
"kind": "native",
"denom": "cw20:terra1y3d5qexmyac0fg53pfglh2pjk0664ymfvcq9mc",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "whGTPS",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12543,6 +13213,7 @@
"kind": "native",
"denom": "cw20:terra1dh9478k2qvqhqeajhn75a2a7dsnf74y5ukregw",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PRISM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/prism.png",
@@ -12552,6 +13223,7 @@
"kind": "native",
"denom": "cw20:terra1l0y8yg0s86x299nqw0p6fhh7ngex3r4phtjeuq",
"decimals": 2,
+ "variant": "cosmos",
"displayName": "SDOLLAR",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12561,6 +13233,7 @@
"kind": "native",
"denom": "cw20:terra1ku5e0dhutxhuxudsmsn5647wwcz6ndr3rsh90k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "whSAIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/whsail.png",
@@ -12570,6 +13243,7 @@
"kind": "native",
"denom": "cw20:terra1rl0cpwgtwl4utnaynugevdje37fnmsea7rv4uu",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "whgSAIL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/whgsail.png",
@@ -12579,6 +13253,7 @@
"kind": "native",
"denom": "cw20:terra1042wzrwg2uk6jqxjm34ysqquyr9esdgm5qyswz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "xPRISM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xprism.png",
@@ -12588,6 +13263,7 @@
"kind": "native",
"denom": "cw20:terra13fs83g5atgjwuh7c5ydzh6n7gecel6xyhhy2t5",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "CDE",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12597,6 +13273,7 @@
"kind": "native",
"denom": "cw20:terra1rl20t79ffsrqfa29rke48tj05gj9jxumm92vg8",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CTX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ctx.png",
@@ -12606,6 +13283,7 @@
"kind": "native",
"denom": "cw20:terra13zaagrrrxj47qjwczsczujlvnnntde7fdt0mau",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "cLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cluna.png",
@@ -12615,6 +13293,7 @@
"kind": "native",
"denom": "cw20:terra1tlgelulz9pdkhls6uglfn5lmxarx7f2gxtdzh2",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "pLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/pluna.png",
@@ -12624,6 +13303,7 @@
"kind": "native",
"denom": "cw20:terra17wkadg0tah554r35x6wvff0y5s7ve8npcjfuhz",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "yLuna",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/yluna.png",
@@ -12633,6 +13313,7 @@
"kind": "native",
"denom": "cw20:terra1cl7whtrqmz5ldr553q69qahck8xvk80fm33qjx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ATLO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/atlo.png",
@@ -12642,6 +13323,7 @@
"kind": "native",
"denom": "cw20:terra1vchw83qt25j89zqwdpmdzj722sqxthnckqzxxp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LOCAL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/local.png",
@@ -12651,6 +13333,7 @@
"kind": "native",
"denom": "cw20:terra15k5r9r8dl8r7xlr29pry8a9w7sghehcnv5mgp6",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUV",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/luv.png",
@@ -12660,6 +13343,7 @@
"kind": "native",
"denom": "cw20:terra1f62tqesptvmhtzr8sudru00gsdtdz24srgm7wp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ROBO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/robo.png",
@@ -12669,6 +13353,7 @@
"kind": "native",
"denom": "cw20:terra1vwz7t30q76s7xx6qgtxdqnu6vpr3ak3vw62ygk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LUART",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/luart.png",
@@ -12678,6 +13363,7 @@
"kind": "native",
"denom": "cw20:terra12hgwnpupflfpuual532wgrxu2gjp0tcagzgx4n",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MARS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mars.svg",
@@ -12687,6 +13373,7 @@
"kind": "native",
"denom": "cw20:terra1a04v570f9cxp49mk06vjsm8axsswndpwwt67k4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XMARS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xmars.svg",
@@ -12696,6 +13383,7 @@
"kind": "native",
"denom": "cw20:terra1vpws4hmpmpsqwnz3gljn8zj42rv7rkpc5atgt4",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "DFIAT",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12705,6 +13393,7 @@
"kind": "native",
"denom": "cw20:terra1hppnw4jppmrzzga4yvd8s87y3dwkhe27xwwl5d",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CERES",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ceres.svg",
@@ -12714,6 +13403,7 @@
"kind": "native",
"denom": "cw20:terra1z3e2e4jpk4n0xzzwlkgcfvc95pc5ldq0xcny58",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "wasAVAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wasavax.svg",
@@ -12723,6 +13413,7 @@
"kind": "native",
"denom": "cw20:terra1zd6let0zg0xjn2sestagxv4ax24a4ml6j40qdr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MINT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mint.svg",
@@ -12732,6 +13423,7 @@
"kind": "native",
"denom": "cw20:terra1ustvnmngueq0p4jd7gfnutgvdc6ujpsjhsjd02",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sd.png",
@@ -12741,6 +13433,7 @@
"kind": "native",
"denom": "cw20:terra1ln2z938phz0nc2wepxpzfkwp6ezn9yrz9zv9ep",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "xSD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/xsd.png",
@@ -12750,6 +13443,7 @@
"kind": "native",
"denom": "cw20:terra1uux6gwd6pzr0gfzrru5kne55cxex9d0700c72r",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "PAXG",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/paxg.png",
@@ -12759,6 +13453,7 @@
"kind": "native",
"denom": "cw20:terra1efjugpjc50d8sha7lr8s48cr7wmsthz94eevcl",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "whDAO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/whdao.png",
@@ -12768,6 +13463,7 @@
"kind": "native",
"denom": "cw20:terra1su6g4t4vwx7y0uh3ksancyaurj4l6w9pfs40qt",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "LINK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/link.png",
@@ -12777,6 +13473,7 @@
"kind": "native",
"denom": "cw20:terra14v9wrjs55qsn9lkvylsqela3w2ytwxzkycqzcr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SAYVE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sayve.png",
@@ -12786,6 +13483,7 @@
"kind": "native",
"denom": "cw20:terra1z55rhw0ut70jxdmpvge98mvj0rkwcz74q77z0u",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GUIDES",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12795,6 +13493,7 @@
"kind": "native",
"denom": "cw20:terra1mt2ytlrxhvd5c4d4fshxxs3zcus3fkdmuv4mk2",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "BRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bro.svg",
@@ -12804,6 +13503,7 @@
"kind": "native",
"denom": "cw20:terra1qryq5wreecx2wd3cdtzz94syr4z0a92l60asds",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bBRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bbro.svg",
@@ -12813,6 +13513,7 @@
"kind": "native",
"denom": "cw20:terra15zvyhmv6gwddht7kt4q6w5nasn4tcpgzcdfmgr",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "GTPS",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12822,6 +13523,7 @@
"kind": "native",
"denom": "cw20:terra15pkdjxv2ewjzn9x665y26pfz2h6ymak4d4e8se",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "GFI",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12831,6 +13533,7 @@
"kind": "native",
"denom": "cw20:terra1fyjsxx73jrufw8ufgtuswa773dvdkny92k70wa",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "ULC",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -12840,6 +13543,7 @@
"kind": "native",
"denom": "cw20:terra1689ys6p6gfu0q6xrjqkzfn80sdyhurjqn0jfdl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sst.png",
@@ -12849,6 +13553,7 @@
"kind": "native",
"denom": "cw20:terra1rg8f993m9834afwazersesgx7jjxv4p87q9wvc",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "ATLAS",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/atlas.png",
@@ -12858,6 +13563,7 @@
"kind": "native",
"denom": "cw20:terra1nc6flp57m5hsr6y5y8aexzszy43ksr0drdr8rp",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "AUDIO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/audio.png",
@@ -12867,6 +13573,7 @@
"kind": "native",
"denom": "cw20:terra1hj8de24c3yqvcsv9r8chr03fzwsak3hgd8gv3m",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "AVAX",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/avax.png",
@@ -12876,6 +13583,7 @@
"kind": "native",
"denom": "cw20:terra1apxgj5agkkfdm2tprwvykug0qtahxvfmugnhx2",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "BAT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/bat.png",
@@ -12885,6 +13593,7 @@
"kind": "native",
"denom": "cw20:terra1skjr69exm6v8zellgjpaa2emhwutrk5a6dz7dd",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "BUSDbs",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/busdbs.png",
@@ -12894,6 +13603,7 @@
"kind": "native",
"denom": "cw20:terra1zmclyfepfmqvfqflu8r3lv6f75trmg05z7xq95",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "DAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/dai.png",
@@ -12903,6 +13613,7 @@
"kind": "native",
"denom": "cw20:terra1dtqlfecglk47yplfrtwjzyagkgcqqngd5lgjp8",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "MATICpo",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/maticpo.png",
@@ -12912,6 +13623,7 @@
"kind": "native",
"denom": "cw20:terra15a9dr3a2a2lj5fclrw35xxg9yuxg0d908wpf2y",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "MIMet",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mimet.png",
@@ -12921,6 +13633,7 @@
"kind": "native",
"denom": "cw20:terra1ht5sepn28z999jx33sdduuxm9acthad507jg9q",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RAY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/ray.png",
@@ -12930,6 +13643,7 @@
"kind": "native",
"denom": "cw20:terra17h82zsq6q8x5tsgm5ugcx4gytw3axguvzt4pkc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SBR",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sbr.png",
@@ -12939,6 +13653,7 @@
"kind": "native",
"denom": "cw20:terra1huku2lecfjhq9d00k5a8dh73gw7dwe6vvuf2dd",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SHIB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/shib.png",
@@ -12948,6 +13663,7 @@
"kind": "native",
"denom": "cw20:terra1dkam9wd5yvaswv4yq3n2aqd4wm5j8n82qc0c7c",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SRMso",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/srmso.png",
@@ -12957,6 +13673,7 @@
"kind": "native",
"denom": "cw20:terra1pvel56a2hs93yd429pzv9zp5aptcjg5ulhkz7w",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDCav",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdcav.png",
@@ -12966,6 +13683,7 @@
"kind": "native",
"denom": "cw20:terra1yljlrxvkar0c6ujpvf8g57m5rpcwl7r032zyvu",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "USDCbs",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdcbs.png",
@@ -12975,6 +13693,7 @@
"kind": "native",
"denom": "cw20:terra1kkyyh7vganlpkj0gkc2rfmhy858ma4rtwywe3x",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDCpo",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdcpo.png",
@@ -12984,6 +13703,7 @@
"kind": "native",
"denom": "cw20:terra1e6mq63y64zcxz8xyu5van4tgkhemj3r86yvgu4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDCso",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdcso.png",
@@ -12993,6 +13713,7 @@
"kind": "native",
"denom": "cw20:terra1eqvq3thjhye7anv6f6mhxpjhyvww8zjvqcdgjx",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDTav",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdtav.png",
@@ -13002,6 +13723,7 @@
"kind": "native",
"denom": "cw20:terra1vlqeghv5mt5udh96kt5zxlh2wkh8q4kewkr0dd",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "USDTbs",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdtbs.png",
@@ -13011,6 +13733,7 @@
"kind": "native",
"denom": "cw20:terra1hd9n65snaluvf7en0p4hqzse9eqecejz2k8rl5",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDTso",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/usdtso.png",
@@ -13020,6 +13743,7 @@
"kind": "native",
"denom": "cw20:terra1fpfn2kkr8mv390wx4dtpfk3vkjx9ch3thvykl3",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "gOHM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/gohm.png",
@@ -13029,6 +13753,7 @@
"kind": "native",
"denom": "cw20:terra1qvlpf2v0zmru3gtex40sqq02wxp39x3cjh359y",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "mSOL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/msol.png",
@@ -13038,6 +13763,7 @@
"kind": "native",
"denom": "cw20:terra1w7ywr6waxtjuvn5svk5wqydqpjj0q9ps7qct4d",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "stETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/steth.png",
@@ -13047,6 +13773,7 @@
"kind": "native",
"denom": "cw20:terra1srp2u95kxps35nvan88gn96nfqhukqya2d0ffc",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LCT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/lct.png",
@@ -13056,6 +13783,7 @@
"kind": "native",
"denom": "cw20:terra18zqcnl83z98tf6lly37gghm7238k7lh79u4z9a",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "bATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/batom.svg",
@@ -13065,6 +13793,7 @@
"kind": "native",
"denom": "cw20:terra128pe5jpempxu0nws5lw28se9zknhsr78626cpn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "webATOM",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/webatom.svg",
@@ -13074,6 +13803,7 @@
"kind": "native",
"denom": "cw20:terra1laczhlpxlgmrwr9un9ds74qxd2fj4754nf82dn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WCOIN",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/wcoin.svg",
@@ -13083,6 +13813,7 @@
"kind": "native",
"denom": "cw20:terra1thhm2u93m2stytzynhsxh5h3jrtg540x4punqy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "LCTfancard",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/lctfancard.png",
@@ -13092,6 +13823,7 @@
"kind": "native",
"denom": "cw20:terra1yeyr6taynkwdl85ppaggr3zr8txhf66cny2ang",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "KNTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/kntc.svg",
@@ -13101,6 +13833,7 @@
"kind": "native",
"denom": "cw20:terra1g53pyke8jtmt4lwvk4yl0xaqc4u0qlsl8dz3ex",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "kUST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/kust.svg",
@@ -13110,6 +13843,7 @@
"kind": "native",
"denom": "cw20:terra1rl4zyexjphwgx6v3ytyljkkc4mrje2pyznaclv",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "STEAK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/steak.svg",
@@ -13119,6 +13853,7 @@
"kind": "native",
"denom": "cw20:terra1jkkt5638cd5pur0u5jnr2juw0v6hz5d6z8xu8m",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CST",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cst.png",
@@ -13128,6 +13863,7 @@
"kind": "native",
"denom": "cw20:terra1kz7qszu7p4dg9lts7m9m7lpuarsnan47jh3fam",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CSTfancard",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cstfancard.png",
@@ -13137,6 +13873,7 @@
"kind": "native",
"denom": "cw20:terra1amz5c45l34n7w8m5a3z7rd7u0k037x4nnsemwj",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "NWLD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/nwld.png",
@@ -13146,6 +13883,7 @@
"kind": "native",
"denom": "cw20:terra1cdc6nlsx0l6jmt3nnx7gxjggf902wge3n2z76k",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "FURY",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/fury.png",
@@ -13155,6 +13893,7 @@
"kind": "native",
"denom": "cw20:terra17n223dxpkypc5c48la7aqjvverczg82ga3cr93",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RCT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/rct.svg",
@@ -13164,6 +13903,7 @@
"kind": "native",
"denom": "cw20:terra14vw4sfqwe7jw8ppcc7u44vq7hy9qa2nlstnxmu",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "VITC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/vitc.png",
@@ -13173,6 +13913,7 @@
"kind": "native",
"denom": "cw20:terra1948uvsah8aw40dhsa9mhl3htq8lraj0smlh77g",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sb.png",
@@ -13182,6 +13923,7 @@
"kind": "native",
"denom": "cw20:terra1rz964297kvt86rteajhtp4hsffhcum0ye8eljh",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TOAD",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/toad.svg",
@@ -13191,6 +13933,7 @@
"kind": "native",
"denom": "cw20:terra1yhlhrea3rgyx2xdnsswsfakn28qa8z7yp5gmhd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "orionASTRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/orionastro.png",
@@ -13200,6 +13943,7 @@
"kind": "native",
"denom": "cw20:terra1j4hwavavmtsafa6zr0npalfz3tk9gf3p4787mp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "RETRO",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/retro.png",
@@ -13209,6 +13953,7 @@
"kind": "native",
"denom": "cw20:terra16wggm67a34msdxasg2vergm2pt289y7930wv7d",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TND",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tnd.png",
@@ -13218,6 +13963,7 @@
"kind": "native",
"denom": "cw20:terra1n9k2he20h5vpyn4mgv7pg4pzvw2n3wc4a86v3g",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "sTND",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/stnd.svg",
@@ -13227,6 +13973,7 @@
"kind": "native",
"denom": "cw20:terra1ezz5xply2v3xdyv32gy5tcd7zq4k235q4xtzwe",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "NWT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/nwt.png",
@@ -13236,6 +13983,7 @@
"kind": "native",
"denom": "uaud",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "AUTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/aut.svg",
@@ -13245,6 +13993,7 @@
"kind": "native",
"denom": "ucad",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CATC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cat.svg",
@@ -13254,6 +14003,7 @@
"kind": "native",
"denom": "uchf",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CHTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cht.svg",
@@ -13263,6 +14013,7 @@
"kind": "native",
"denom": "ucny",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "CNTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/cnt.svg",
@@ -13272,6 +14023,7 @@
"kind": "native",
"denom": "udkk",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "DKTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/dkt.svg",
@@ -13281,6 +14033,7 @@
"kind": "native",
"denom": "ueur",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "EUTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/eut.svg",
@@ -13290,6 +14043,7 @@
"kind": "native",
"denom": "ugbp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/gbt.svg",
@@ -13299,6 +14053,7 @@
"kind": "native",
"denom": "uhkd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "HKTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/hkt.svg",
@@ -13308,6 +14063,7 @@
"kind": "native",
"denom": "uidr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "IDTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/idt.svg",
@@ -13317,6 +14073,7 @@
"kind": "native",
"denom": "uinr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "INTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/int.svg",
@@ -13326,6 +14083,7 @@
"kind": "native",
"denom": "ujpy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "JPTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/jpt.svg",
@@ -13335,6 +14093,7 @@
"kind": "native",
"denom": "umnt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MNTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/mnt.svg",
@@ -13344,6 +14103,7 @@
"kind": "native",
"denom": "umyr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "MYTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/myt.svg",
@@ -13353,6 +14113,7 @@
"kind": "native",
"denom": "unok",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NOTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/not.svg",
@@ -13362,6 +14123,7 @@
"kind": "native",
"denom": "uphp",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PHTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/pht.svg",
@@ -13371,6 +14133,7 @@
"kind": "native",
"denom": "usdr",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SDTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sdt.svg",
@@ -13380,6 +14143,7 @@
"kind": "native",
"denom": "usek",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SETC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/set.svg",
@@ -13389,6 +14153,7 @@
"kind": "native",
"denom": "usgd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "SGTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/sgt.svg",
@@ -13398,6 +14163,7 @@
"kind": "native",
"denom": "uthb",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "THTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/tht.svg",
@@ -13407,6 +14173,7 @@
"kind": "native",
"denom": "utwd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TWTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/twt.svg",
@@ -13416,6 +14183,7 @@
"kind": "native",
"denom": "cw20:terra1mpq5zkkm39nmjrjg9raknpfrfmcfwv0nh0whvn",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "NEB",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/neb.png",
@@ -13425,6 +14193,7 @@
"kind": "native",
"denom": "cw20:terra1g6fm3yu79gv0rc8067n2nnfpf0vks6n0wpzaf4u7w48tdrmj98zsy7uu00",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TRIT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/terra/images/trit.png",
@@ -13463,6 +14232,7 @@
"kind": "native",
"denom": "utgd",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TGD",
"coingeckoId": "tgrade",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/tgrade/images/tgrade-symbol-gradient.svg",
@@ -13528,6 +14298,7 @@
"kind": "native",
"denom": "uulas",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "ULAS",
"coingeckoId": "ulas",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/ulastestnet/images/logo.png",
@@ -13565,6 +14336,7 @@
"kind": "native",
"denom": "uumee",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "UMEE",
"coingeckoId": "umee",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/umee/images/umee.svg",
@@ -13603,6 +14375,7 @@
"kind": "native",
"denom": "nund",
"decimals": 9,
+ "variant": "cosmos",
"displayName": "FUND",
"coingeckoId": "unification",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/unification/images/fund.svg",
@@ -13641,6 +14414,7 @@
"kind": "native",
"denom": "muno",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "UNION",
"coingeckoId": "unionlabs",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/union/images/union.png",
@@ -13679,6 +14453,7 @@
"kind": "native",
"denom": "uguu",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "GUU",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/ununifi/images/ununifi.svg",
@@ -13717,6 +14492,7 @@
"kind": "native",
"denom": "auptick",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "UPTICK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/uptick/images/uptick.svg",
@@ -13755,6 +14531,7 @@
"kind": "native",
"denom": "auptick",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "UPTICK",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/upticktestnet/images/uptick.png",
@@ -13792,6 +14569,7 @@
"kind": "native",
"denom": "uvdl",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "VDL",
"coingeckoId": "vidulum",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/vidulum/images/vdl.svg",
@@ -13830,6 +14608,7 @@
"kind": "native",
"denom": "avce",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "VCE",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/vincechaintestnet/images/vince.png",
@@ -13868,6 +14647,7 @@
"kind": "native",
"denom": "utest",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "TEST",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -13877,6 +14657,7 @@
"kind": "native",
"denom": "uworm",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "WORM",
"coingeckoId": "not-found",
"icon": "not-found",
@@ -13886,6 +14667,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/46YEtoSN1AcwgGSRoWruoS6bnVh8XpMp5aQTpKohCJYh",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SUI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/sui/images/sui.svg",
@@ -13895,6 +14677,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/5BWqpR48Lubd55szM5i62zK7TFkddckhbT48yy6mNbDp",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "WETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/eth-white.svg",
@@ -13904,6 +14687,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/5TSQTEhJ5Q6r1YqCmCxTRSPiV2pGx5rZUQf6g2XH4e1b",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "wstETH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/wsteth.svg",
@@ -13913,6 +14697,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/5wS2fGojbL9RhGEAeQBdkHPUAciYDxjDTMYvdf9aDn2r",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "APT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/aptos/images/aptos.svg",
@@ -13922,6 +14707,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/8iuAc6DSeLvi2JDUtwJxLytsZT8R19itXebZsNReLLNi",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDT",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.svg",
@@ -13931,6 +14717,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/8sYgCzLRJC3J7qPn2bNbx6PiGcarhyx8rBhVaNnfvHCA",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "SOL",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/solana/images/sol.svg",
@@ -13940,6 +14727,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/95mnwzvJZJ3fKz77xfGN2nR5to9pZmH8YNvaxgLgw5AR",
"decimals": 5,
+ "variant": "cosmos",
"displayName": "Bonk",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/solana/images/bonk.png",
@@ -13949,6 +14737,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/BGkuAcga2WArUghF8L6kt6uCAhAzrxmn1QcbQqi5r5bd",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "WBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/wbtc.svg",
@@ -13958,6 +14747,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/BhqTYfQogyt7jX7cx7x8uHEQP1x9fdtdBZtK4Swghgpw",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "tBTC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/tbtc.svg",
@@ -13967,6 +14757,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/EKiMEqDnPKokFGcSXDvGMk6Gt1BJ6BC7BDZzTmEpWLH1",
"decimals": 8,
+ "variant": "cosmos",
"displayName": "DAI",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/dai.svg",
@@ -13976,6 +14767,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/GGh9Ufn1SeDGrhzEkMyRKt5568VbbxZK2yvWNsd6PbXt",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "USDC",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -13985,6 +14777,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/5ZLmAZpcbaP4EGyihSmpfwryzDr84h51tboV392BCjW4",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "avalanche.USDC.wh",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdc.svg",
@@ -13994,6 +14787,7 @@
"kind": "native",
"denom": "factory/wormhole14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les00fpjx/B8ohBnfisop27exk2gtNABJyYjLwQA7ogrp5uNzvZCoy",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "PYTH",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/solana/images/pyth.svg",
@@ -14032,6 +14826,7 @@
"kind": "native",
"denom": "uxion",
"decimals": 6,
+ "variant": "cosmos",
"displayName": "XION",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/xion/images/burnt-round.png",
@@ -14070,6 +14865,7 @@
"kind": "native",
"denom": "axpla",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "XPLA",
"coingeckoId": "xpla",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/xpla/images/xpla.svg",
@@ -14108,6 +14904,7 @@
"kind": "native",
"denom": "azeta",
"decimals": 18,
+ "variant": "cosmos",
"displayName": "tZETA",
"coingeckoId": "not-found",
"icon": "https://raw.githubusercontent.com/cosmos/chain-registry/master/testnets/zetachaintestnet/images/zetachaintestnet.svg",
diff --git a/package.json b/package.json
index e12cfd01ea..602ff8f505 100644
--- a/package.json
+++ b/package.json
@@ -11,9 +11,10 @@
"build:web": "expo export -p web",
"lint": "npx tsx packages/scripts/paralint",
"lint-fix": "eslint --cache --ext .js,.jsx,.ts,.tsx . --fix",
- "unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport=\"packages/api;packages/contracts-clients;packages/evm-contracts-clients;packages/screens/RiotGame/RiotGameBridgeScreen.tsx;packages/components/socialFeed/RichText/inline-toolbar;app.config.js;weshd;./App.tsx;packages/modules/FileSystem/index.ts;.*\\.web|.electron|.native|.d.ts\"",
+ "unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport=\"packages/api;packages/contracts-clients;packages/evm-contracts-clients;packages/screens/RiotGame/RiotGameBridgeScreen.tsx;packages/components/socialFeed/RichText/inline-toolbar;app.config.js;weshd;./App.tsx;./cypress.config.ts;packages/modules/FileSystem/index.ts;.*\\.web|.electron|.native|.d.ts\"",
"validate-networks": "tsx packages/scripts/validateNetworks.ts",
- "postinstall": "patch-package"
+ "postinstall": "patch-package",
+ "install-gno": "tsx packages/scripts/install-gno"
},
"engines": {
"node": "v18.1.0"
@@ -25,11 +26,12 @@
"@chain-registry/utils": "1.18.0",
"@cosmjs/amino": "0.32.2",
"@cosmjs/cosmwasm-stargate": "0.32.2",
- "@cosmjs/encoding": "^0.32.2",
- "@cosmjs/math": "^0.32.2",
+ "@cosmjs/crypto": "0.32.2",
+ "@cosmjs/encoding": "0.32.2",
+ "@cosmjs/math": "0.32.2",
"@cosmjs/proto-signing": "0.32.2",
"@cosmjs/stargate": "0.32.2",
- "@cosmjs/tendermint-rpc": "^0.32.2",
+ "@cosmjs/tendermint-rpc": "0.32.2",
"@cosmology/core": "2.0.1",
"@dotlottie/react-player": "^1.6.5",
"@draft-js-plugins/anchor": "^4.2.0",
@@ -44,6 +46,8 @@
"@expo-google-fonts/exo": "^0.2.2",
"@expo/metro-runtime": "~3.1.3",
"@gnolang/gno-js-client": "^1.3.0",
+ "@gnolang/tm2-js-client": "^1.2.1",
+ "@hookform/resolvers": "^3.6.0",
"@improbable-eng/grpc-web": "^0.15.0",
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
"@improbable-eng/grpc-web-react-native-transport": "^0.15.0",
@@ -59,6 +63,7 @@
"@react-native-clipboard/clipboard": "^1.13.2",
"@react-native-community/slider": "4.4.2",
"@react-native-masked-view/masked-view": "0.3.0",
+ "@react-native-picker/picker": "2.6.1",
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/drawer": "^6.6.6",
"@react-navigation/native": "^6.0.11",
@@ -128,6 +133,7 @@
"react-native-gesture-handler": "~2.14.0",
"react-native-get-random-values": "~1.8.0",
"react-native-heroicons": "^3.2.0",
+ "react-native-hoverable": "^0.2.0",
"react-native-image-picker": "^7.1.0",
"react-native-keyboard-aware-scrollview": "^2.1.0",
"react-native-leaflet-view": "^0.1.2",
@@ -139,6 +145,7 @@
"react-native-qrcode-svg": "^6.2.0",
"react-native-reanimated": "^3.6.2",
"react-native-reanimated-carousel": "4.0.0-alpha.9",
+ "react-native-reanimated-table": "^0.0.2",
"react-native-redash": "^18.0.0",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
@@ -162,7 +169,8 @@
"victory-native": "^36.6.8",
"waveform-data": "^4.3.0",
"yaml": "^2.3.4",
- "zod": "^3.22.4"
+ "zod": "^3.22.4",
+ "zustand": "^4.4.7"
},
"devDependencies": {
"@axelar-network/axelarjs-types": "^0.33.0",
@@ -175,6 +183,7 @@
"@babel/plugin-transform-shorthand-properties": "^7.23.3",
"@babel/plugin-transform-template-literals": "^7.23.3",
"@cosmwasm/ts-codegen": "^0.35.7",
+ "@faker-js/faker": "^8.4.1",
"@types/draft-convert": "^2.1.4",
"@types/draft-js": "^0.11.9",
"@types/html-to-draftjs": "^1.4.0",
@@ -187,6 +196,7 @@
"babel-plugin-react-inline-svg-unique-id": "^1.3.1",
"cors-anywhere": "^0.4.4",
"cross-env": "^7.0.3",
+ "cypress": "^13.9.0",
"depcheck": "^1.4.7",
"dotenv": "^16.3.1",
"electron": "^27.1.2",
diff --git a/packages/components/FlexRow.tsx b/packages/components/FlexRow.tsx
index 9fb0adfcfd..1891c6612c 100644
--- a/packages/components/FlexRow.tsx
+++ b/packages/components/FlexRow.tsx
@@ -16,7 +16,7 @@ type Direction =
| "column-reverse"
| undefined;
-const FlexRow: React.FC = ({
+export const FlexRow: React.FC = ({
breakpoint,
width = "100%",
alignItems = "center",
diff --git a/packages/components/ProgressLine.tsx b/packages/components/ProgressLine.tsx
index 87f2d77027..6bad62b582 100644
--- a/packages/components/ProgressLine.tsx
+++ b/packages/components/ProgressLine.tsx
@@ -1,22 +1,23 @@
import { LinearGradient } from "expo-linear-gradient";
-import React from "react";
-import { View, ViewStyle } from "react-native";
+import { FC, memo } from "react";
+import { StyleProp, View, ViewStyle } from "react-native";
import { neutral33 } from "../utils/style/colors";
-const DEFAULT_WIDTH = 200;
-
-interface ProgressLineProps {
- percent: number;
- width?: number;
- style?: ViewStyle;
-}
-
-export const ProgressLine: React.FC = ({
- percent,
- width = DEFAULT_WIDTH,
- style,
-}) => {
+/**
+ * @param gain - The gain of the progress line. Must be between 0 and 1 inclusive.
+ * @param style - The style of the container View.
+ */
+export const ProgressLine: FC<{
+ gain: number;
+ style?: StyleProp;
+}> = memo(({ gain, style }) => {
+ if (gain < 0) {
+ gain = 0;
+ }
+ if (gain > 1) {
+ gain = 1;
+ }
return (
= ({
height: 4,
borderRadius: 4,
backgroundColor: neutral33,
- width,
+ flexGrow: 1,
position: "relative",
},
style,
@@ -36,7 +37,7 @@ export const ProgressLine: React.FC = ({
locations={[0, 0.5, 1]}
colors={["#5433FF", "#20BDFF", "#A5FECB"]}
style={{
- width: (percent / 100) * width,
+ width: `${gain * 100}%`,
height: 4,
position: "absolute",
top: 0,
@@ -46,4 +47,4 @@ export const ProgressLine: React.FC = ({
/>
);
-};
+});
diff --git a/packages/components/Search/SearchBarInput.tsx b/packages/components/Search/SearchBarInput.tsx
index f49f613ea8..d6d1d8f465 100644
--- a/packages/components/Search/SearchBarInput.tsx
+++ b/packages/components/Search/SearchBarInput.tsx
@@ -1,5 +1,5 @@
import React, { useRef } from "react";
-import { StyleProp, TextInput, StyleSheet } from "react-native";
+import { StyleProp, TextInput, StyleSheet, ViewStyle } from "react-native";
import { useSelector } from "react-redux";
import searchSVG from "../../../assets/icons/search.svg";
@@ -32,8 +32,19 @@ export const SearchBarInput: React.FC<{
text: string;
onChangeText: (text: string) => void;
onInteraction?: () => void;
+ placeholder?: string;
style?: StyleProp;
-}> = ({ onInteraction, text, onChangeText, style }) => {
+ inputStyle?: StyleProp;
+ noBrokenCorners?: boolean;
+}> = ({
+ onInteraction,
+ text,
+ onChangeText,
+ style,
+ placeholder,
+ inputStyle,
+ noBrokenCorners = false,
+}) => {
const ref = useRef(null);
const fullWidth = StyleSheet.flatten(style)?.width === "100%";
return (
@@ -52,6 +63,7 @@ export const SearchBarInput: React.FC<{
>
{
);
};
-const SearchResultsSection: React.FC<{
+export const SearchResultsSection: React.FC<{
title: string;
style: StyleProp;
isFirstSection?: boolean;
diff --git a/packages/components/TopMenu/TopMenuAccount.tsx b/packages/components/TopMenu/TopMenuAccount.tsx
index bf0398a5fa..0ddf6f9d1c 100644
--- a/packages/components/TopMenu/TopMenuAccount.tsx
+++ b/packages/components/TopMenu/TopMenuAccount.tsx
@@ -1,4 +1,4 @@
-import { TextStyle, ViewStyle } from "react-native";
+import { TextStyle, View, ViewStyle } from "react-native";
import chevronRightSVG from "../../../assets/icons/chevron-right.svg";
import useSelectedWallet from "../../hooks/useSelectedWallet";
@@ -10,17 +10,16 @@ import FlexCol from "../FlexCol";
import FlexRow from "../FlexRow";
import { OmniLink } from "../OmniLink";
import { SVG } from "../SVG";
-import { UserNameInline } from "../UserNameInline";
+import { UsernameWithAvatar } from "../user/UsernameWithAvatar";
export const TopMenuAccount: React.FC = () => {
const selectedWallet = useSelectedWallet();
return (
-
+
+
+
diff --git a/packages/components/TopMenu/WalletView.tsx b/packages/components/TopMenu/WalletView.tsx
index e3af59400b..bef60539a3 100644
--- a/packages/components/TopMenu/WalletView.tsx
+++ b/packages/components/TopMenu/WalletView.tsx
@@ -22,6 +22,7 @@ export const WalletView: React.FC<{
{tinyAddress(userInfo?.metadata?.tokenId || wallet?.address || "", 16)}
diff --git a/packages/components/UserNameInline.tsx b/packages/components/UserNameInline.tsx
deleted file mode 100644
index 7b8888cdd2..0000000000
--- a/packages/components/UserNameInline.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from "react";
-import { StyleProp, TextStyle } from "react-native";
-
-import { BrandText } from "./BrandText";
-import FlexRow from "./FlexRow";
-import { OmniLink } from "./OmniLink";
-import { UserAvatarWithFrame } from "./images/AvatarWithFrame";
-import { useNSUserInfo } from "../hooks/useNSUserInfo";
-import { parseUserId } from "../networks";
-import { fontSemibold14 } from "../utils/style/fonts";
-import { layout } from "../utils/style/layout";
-import { tinyAddress } from "../utils/text";
-
-type PlayerNameProps = {
- userId: string | undefined;
- multisignWalletAddres?: string | null;
- style?: StyleProp;
-};
-
-export const UserNameInline: React.FC = ({
- userId,
- style,
-}) => {
- const [, userAddress] = parseUserId(userId);
- const userInfo = useNSUserInfo(userId);
- const name =
- userInfo?.metadata?.tokenId || tinyAddress(userAddress, 30) || "";
-
- return (
-
-
-
-
- {name}
-
-
-
- );
-};
diff --git a/packages/components/WalletProviderIcon.tsx b/packages/components/WalletProviderIcon.tsx
index 69899e06a3..b48dba7a7f 100644
--- a/packages/components/WalletProviderIcon.tsx
+++ b/packages/components/WalletProviderIcon.tsx
@@ -6,6 +6,7 @@ import adenaSVG from "../../assets/icons/adena.svg";
import keplrSVG from "../../assets/icons/keplr.svg";
import leapSVG from "../../assets/icons/leap-cosmos-logo.svg";
import metamaskSVG from "../../assets/icons/metamask.svg";
+import warningSVG from "../../assets/icons/warning.svg";
import { WalletProvider } from "../utils/walletProvider";
export const WalletProviderIcon: React.FC<{
@@ -21,6 +22,8 @@ export const WalletProviderIcon: React.FC<{
return ;
case WalletProvider.Adena:
return ;
+ case WalletProvider.Gnotest:
+ return ;
default:
return ;
}
diff --git a/packages/components/buttons/IconButton.tsx b/packages/components/buttons/IconButton.tsx
index e900b86c77..84c1b232d4 100644
--- a/packages/components/buttons/IconButton.tsx
+++ b/packages/components/buttons/IconButton.tsx
@@ -55,6 +55,7 @@ export const IconButton: React.FC<{
borderRadius: borderRadiusButton(size),
backgroundColor,
paddingHorizontal: 20,
+ alignItems: "center",
},
]}
>
diff --git a/packages/components/buttons/PrimaryButton.tsx b/packages/components/buttons/PrimaryButton.tsx
index 276751b903..a3132cb882 100644
--- a/packages/components/buttons/PrimaryButton.tsx
+++ b/packages/components/buttons/PrimaryButton.tsx
@@ -35,6 +35,7 @@ export const PrimaryButton: React.FC<{
RightComponent?: React.FC;
color?: string;
isLoading?: boolean;
+ testID?: string;
}> = ({
// If no width, the buttons will fit the content including paddingHorizontal 20
width,
@@ -51,6 +52,7 @@ export const PrimaryButton: React.FC<{
iconColor,
color = primaryColor,
isLoading: isLoadingProp,
+ testID,
}) => {
const [isLocalLoading, setIsLocalLoading] = useState(false);
const [hovered, setHovered] = useState(false);
@@ -89,6 +91,7 @@ export const PrimaryButton: React.FC<{
onHoverOut={() => {
setHovered(false);
}}
+ testID={testID}
>
;
+ style?: StyleProp;
loading?: boolean;
disabled?: boolean;
iconSVG?: React.FC;
outline?: boolean;
+ testID?: string | undefined;
}
export const SimpleButton: React.FC = ({
@@ -38,27 +39,33 @@ export const SimpleButton: React.FC = ({
style,
iconSVG = null,
outline = false,
+ testID,
}) => {
let padH: number;
let padV: number;
+ let radius: number;
switch (size) {
case "XL":
padH = layout.spacing_x3;
padV = layout.spacing_x2_5;
+ radius = layout.spacing_x1_5;
break;
case "SM":
padH = layout.spacing_x2;
padV = layout.spacing_x1_5;
+ radius = layout.spacing_x0_75;
break;
case "XS":
padH = layout.spacing_x1_5;
padV = layout.spacing_x0_5;
+ radius = layout.spacing_x0_5;
break;
case "M":
default:
padH = layout.spacing_x2_5;
padV = layout.spacing_x2;
+ radius = layout.spacing_x1;
break;
}
@@ -67,15 +74,20 @@ export const SimpleButton: React.FC = ({
disabled={disabled}
style={[containerStyle, (loading || disabled) && { opacity: 0.6 }]}
onPress={() => !loading && onPress?.()}
+ testID={testID}
>
= ({
);
};
-
-// FIXME: remove StyleSheet.create
-// eslint-disable-next-line no-restricted-syntax
-const styles = StyleSheet.create({
- btnStyle: {
- alignSelf: "center",
- borderRadius: layout.spacing_x1_5,
- ...(fontSemibold14 as object),
- },
-});
diff --git a/packages/components/buttons/SocialButton.tsx b/packages/components/buttons/SocialButton.tsx
index 4e0931729a..23ca47e682 100644
--- a/packages/components/buttons/SocialButton.tsx
+++ b/packages/components/buttons/SocialButton.tsx
@@ -1,12 +1,18 @@
import React from "react";
-import { ViewStyle, StyleProp, TouchableOpacity } from "react-native";
+import {
+ ViewStyle,
+ StyleProp,
+ TouchableOpacity,
+ View,
+ Pressable,
+ ColorValue,
+} from "react-native";
import { SvgProps } from "react-native-svg";
-import { BrandText } from "../BrandText";
-import { SVG } from "../SVG";
-import { Box } from "../boxes/Box";
-
-import { neutral22, neutral33, withAlpha } from "@/utils/style/colors";
+import { BrandText } from "@/components/BrandText";
+import { SVG } from "@/components/SVG";
+import { Box } from "@/components/boxes/Box";
+import { withAlpha, neutral22, neutral33 } from "@/utils/style/colors";
import { fontMedium14 } from "@/utils/style/fonts";
export const iconSize = 32;
@@ -14,12 +20,78 @@ export const iconPadding = 12;
export const outerPadding = 6;
export const innerGap = 8;
+const IconWithText: React.FC<{
+ text?: string;
+ iconSvg: React.FC;
+ textColor?: ColorValue;
+ iconColor?: ColorValue;
+}> = ({ text, iconSvg, textColor, iconColor }) => {
+ return (
+
+
+
+
+ {!!text && (
+
+ {text}
+
+ )}
+
+ );
+};
+
+export const IconWithTextButton: React.FC<{
+ text?: string;
+ iconSvg: React.FC;
+ textColor?: ColorValue;
+ onPress?: () => void;
+ style?: StyleProp;
+}> = ({ text, iconSvg, style, onPress, textColor }) => {
+ const [hovered, setHovered] = React.useState(false);
+ return (
+ setHovered(true)}
+ onHoverOut={() => setHovered(false)}
+ >
+
+
+ );
+};
+
export const SocialButton: React.FC<{
text?: string;
iconSvg: React.FC;
+ textColor?: ColorValue;
+ iconColor?: ColorValue;
onPress?: () => void;
style?: StyleProp;
-}> = ({ text, onPress, iconSvg, style }) => {
+}> = ({ text, onPress, iconSvg, style, textColor, iconColor }) => {
return (
-
-
-
- {!!text && (
-
- {text}
-
- )}
+
);
diff --git a/packages/components/connectWallet/ConnectAdenaButton.tsx b/packages/components/connectWallet/ConnectAdenaButton.tsx
index 153ad7f12c..d02ff246c8 100644
--- a/packages/components/connectWallet/ConnectAdenaButton.tsx
+++ b/packages/components/connectWallet/ConnectAdenaButton.tsx
@@ -31,6 +31,7 @@ export const ConnectAdenaButton: React.FC<{
const address = account.data.address;
const chainId = account.data.chainId;
const network = getGnoNetworkFromChainId(chainId);
+
if (!network) {
throw new Error(`Unsupported chainId ${chainId}`);
}
diff --git a/packages/components/hub/AssetRatioByChain.tsx b/packages/components/hub/AssetRatioByChain.tsx
index 8b353ec18d..d64033a46e 100644
--- a/packages/components/hub/AssetRatioByChain.tsx
+++ b/packages/components/hub/AssetRatioByChain.tsx
@@ -43,8 +43,10 @@ const ListItem: React.FC = ({ title, icon, percent }) => {
{title}
{
description="Get funds to develop, contribute and build new feature for Communities"
info="Apply here"
iconSVG={labsSVG}
- onPress={() => Linking.openURL("https://teritori.com/grants")}
+ onPress={() => Linking.openURL("https://teritori.com/projects")}
/>
diff --git a/packages/components/images/RoundedGradientImage.tsx b/packages/components/images/RoundedGradientImage.tsx
index 25ff66fe1b..1c55d0d964 100644
--- a/packages/components/images/RoundedGradientImage.tsx
+++ b/packages/components/images/RoundedGradientImage.tsx
@@ -4,12 +4,16 @@ import { View, ViewStyle, StyleProp } from "react-native";
import { OptimizedImage } from "../OptimizedImage";
-type RoundedGradientImageSize = "M" | "XS" | "XXS";
+type RoundedGradientImageSize = "L" | "M" | "S" | "XS" | "XXS";
const dimension = (size: RoundedGradientImageSize) => {
switch (size) {
+ case "L":
+ return 236;
case "M":
return 140;
+ case "S":
+ return 56;
case "XS":
return 32;
case "XXS":
@@ -18,8 +22,12 @@ const dimension = (size: RoundedGradientImageSize) => {
};
const imageDimension = (size: RoundedGradientImageSize) => {
switch (size) {
+ case "L":
+ return dimension(size) - 4;
case "M":
return dimension(size) - 4;
+ case "S":
+ return dimension(size) - 2;
case "XS":
return dimension(size) - 2;
case "XXS":
@@ -32,7 +40,8 @@ export const RoundedGradientImage: React.FC<{
fallbackURI?: string | null | undefined;
size?: RoundedGradientImageSize;
style?: StyleProp;
-}> = ({ sourceURI, fallbackURI, size = "M", style }) => {
+ square?: boolean;
+}> = ({ sourceURI, fallbackURI, size = "M", style, square = false }) => {
return (
@@ -75,7 +88,7 @@ export const RoundedGradientImage: React.FC<{
position: "absolute",
width: dimension(size),
height: dimension(size),
- borderRadius: 999,
+ borderRadius: square ? 12 : 999,
}}
colors={["#01B7C5", "#782C96"]}
/>
diff --git a/packages/components/inputs/SelectInput.tsx b/packages/components/inputs/SelectInput.tsx
index 3644d7039f..0c5c374577 100644
--- a/packages/components/inputs/SelectInput.tsx
+++ b/packages/components/inputs/SelectInput.tsx
@@ -52,6 +52,7 @@ type Props = {
allowSearchValue?: boolean;
name?: string;
isLoading?: boolean;
+ testID?: string;
renderItem?: ({
onPressItem,
item,
@@ -75,6 +76,7 @@ export const SelectInput: React.FC = ({
name,
isLoading,
renderItem,
+ testID,
}) => {
const [openMenu, setOpenMenu] = useState(false);
const [hovered, setHovered] = useState(false);
@@ -131,6 +133,7 @@ export const SelectInput: React.FC = ({
if (!disabled || selectableData.length) setOpenMenu((value) => !value);
}}
disabled={disabled || !selectableData.length}
+ testID={testID}
>
{label && (
<>
diff --git a/packages/components/inputs/TextInputCustom.tsx b/packages/components/inputs/TextInputCustom.tsx
index ef95e3184e..6c8f29a1e6 100644
--- a/packages/components/inputs/TextInputCustom.tsx
+++ b/packages/components/inputs/TextInputCustom.tsx
@@ -264,6 +264,8 @@ export const TextInputCustom = ({
boxMainContainerStyle,
noBrokenCorners && styles.noCropBorderBg,
hovered && { borderColor: secondaryColor },
+ height !== undefined &&
+ height <= styles.mainContainer.minHeight && { minHeight: height },
]}
width={width}
fullWidth={!width}
diff --git a/packages/components/layout/GridList.tsx b/packages/components/layout/GridList.tsx
index 4c4d2cda4d..61257e6715 100644
--- a/packages/components/layout/GridList.tsx
+++ b/packages/components/layout/GridList.tsx
@@ -16,6 +16,12 @@ type GridListType = React.FC<{
gap?: number;
noFixedHeight?: boolean;
onEndReached?: ComponentProps>["onEndReached"];
+ ListHeaderComponent?: ComponentProps<
+ typeof FlatList
+ >["ListHeaderComponent"];
+ ListFooterComponent?: ComponentProps<
+ typeof FlatList
+ >["ListFooterComponent"];
}>;
type ItemWrapper =
@@ -36,6 +42,8 @@ export function GridList({
noFixedHeight,
keyExtractor,
renderItem,
+ ListHeaderComponent,
+ ListFooterComponent,
}: ComponentProps>): ReturnType> {
const { height } = useMaxResolution({ isLarge: true });
const [containerWidth, setContainerWidth] = useState(0);
@@ -90,6 +98,7 @@ export function GridList({
>
onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
contentContainerStyle={!noFixedHeight && { height }}
+ ListHeaderComponent={ListHeaderComponent}
columnWrapperStyle={
elemsPerRow < 2
? undefined
@@ -109,6 +118,7 @@ export function GridList({
size={Math.min(height, containerWidth) / 3}
/>
}
+ ListFooterComponent={ListFooterComponent}
renderItem={renderItemWithFixedWidth}
/>
);
diff --git a/packages/components/loaders/AnimatedLoader.tsx b/packages/components/loaders/AnimatedLoader.tsx
index 452d91599b..545fc9ddb5 100644
--- a/packages/components/loaders/AnimatedLoader.tsx
+++ b/packages/components/loaders/AnimatedLoader.tsx
@@ -5,7 +5,8 @@ import { StyleProp, View, ViewStyle } from "react-native";
export const AnimatedLoader: React.FC<{
size?: number;
style?: StyleProp;
-}> = memo(({ size: sizeProp, style }) => {
+ testID?: string | undefined;
+}> = memo(({ size: sizeProp, style, testID }) => {
const size = sizeProp || 80;
return (
diff --git a/packages/components/loaders/LoaderFullScreen.tsx b/packages/components/loaders/LoaderFullScreen.tsx
index 2c1df5f34b..4cf5dc51bb 100644
--- a/packages/components/loaders/LoaderFullScreen.tsx
+++ b/packages/components/loaders/LoaderFullScreen.tsx
@@ -17,7 +17,7 @@ export const LoaderFullScreen: React.FC<{ visible: boolean }> = ({
zIndex: 10,
}}
>
-
+
);
diff --git a/packages/components/modals/ConnectWalletModal.tsx b/packages/components/modals/ConnectWalletModal.tsx
index fd48cc2721..c32cde9703 100644
--- a/packages/components/modals/ConnectWalletModal.tsx
+++ b/packages/components/modals/ConnectWalletModal.tsx
@@ -19,6 +19,8 @@ import { ConnectWalletButton } from "../connectWallet/components/ConnectWalletBu
import { SeparatorGradient } from "../separators/SeparatorGradient";
import { SpacerColumn } from "../spacer";
+import { ConnectGnotestButton } from "@/context/WalletsProvider/gnotest";
+
export const ConnectWalletModal: FC<{
forceNetworkFeature?: NetworkFeature;
label?: string;
@@ -109,6 +111,7 @@ export const ConnectWalletModal: FC<{
visible={isDisclaimerVisible}
onClose={toggleDisclaimer}
/>
+
);
};
diff --git a/packages/components/navigation/getNormalModeScreens.tsx b/packages/components/navigation/getNormalModeScreens.tsx
index 20bcff6e4d..5b134f0389 100644
--- a/packages/components/navigation/getNormalModeScreens.tsx
+++ b/packages/components/navigation/getNormalModeScreens.tsx
@@ -39,6 +39,13 @@ import { MultisigWalletDashboardScreen } from "@/screens/Multisig/MultisigWallet
import { MyCollectionScreen } from "@/screens/MyCollection/MyCollectionScreen";
import { OrganizationDeployerScreen } from "@/screens/Organizations/OrganizationDeployerScreen";
import { OrganizationsScreen } from "@/screens/Organizations/OrganizationsScreen";
+import { ProjectsCompleteMilestoneScreen } from "@/screens/Projects/CompleteMilestoneScreen";
+import { ProjectsConflictSolvingScreen } from "@/screens/Projects/ProjectsConflictSolvingScreen";
+import { ProjectsDetailScreen } from "@/screens/Projects/ProjectsDetailScreen";
+import { ProjectsMakeRequestScreen } from "@/screens/Projects/ProjectsMakeRequestScreen";
+import { ProjectsManagerScreen } from "@/screens/Projects/ProjectsManagerScreen";
+import { ProjectsPaymentScreen } from "@/screens/Projects/ProjectsPaymentScreen";
+import { ProjectsScreen } from "@/screens/Projects/ProjectsScreen";
import { ReadyLaunchpadApplicationsScreen } from "@/screens/ReadyLaunchpadApplications/ReadyLaunchpadApplicationsScreen";
import { RiotGameBreedingScreen } from "@/screens/RiotGame/RiotGameBreedingScreen";
import { RiotGameEnrollScreen } from "@/screens/RiotGame/RiotGameEnrollScreen";
@@ -318,6 +325,67 @@ export const getNormalModeScreens = ({ appMode }: { appMode: AppMode }) => {
}}
/>
+ {/* ==== Projects program */}
+ null, title: screenTitle("Projects Program") }}
+ />
+
+ null,
+ title: screenTitle("Projects Program Detail"),
+ }}
+ />
+
+ null,
+ title: screenTitle("Projects Program Manager"),
+ }}
+ />
+
+ null,
+ title: screenTitle("Projects Program Payment"),
+ }}
+ />
+
+ null,
+ title: screenTitle("Projects Milestone"),
+ }}
+ />
+
+ null,
+ title: screenTitle("Projects Program Make Request"),
+ }}
+ />
+
+ null,
+ title: screenTitle("Project Conflict Solving"),
+ }}
+ />
+
{/* ==== Teritori Name Service*/}
= ({ userId, addrLen = 30 }) => {
+ const [, userAddress] = parseUserId(userId);
+ const userInfo = useNSUserInfo(userId);
+
+ if (!userId) {
+ return (
+
+ None
+
+ );
+ }
+
+ const name =
+ userInfo?.metadata?.tokenId || tinyAddress(userAddress, addrLen) || "";
+
+ return (
+
+
+
+ {name}
+
+
+ );
+};
diff --git a/packages/context/SidebarProvider.tsx b/packages/context/SidebarProvider.tsx
index 72e56176c6..5f99f59074 100644
--- a/packages/context/SidebarProvider.tsx
+++ b/packages/context/SidebarProvider.tsx
@@ -15,12 +15,14 @@ import {
import { useAppDispatch } from "../store/store";
import { SIDEBAR_LIST } from "../utils/sidebar";
+import { useDeveloperMode } from "@/hooks/useDeveloperMode";
import { getValuesFromId, SEPARATOR } from "@/utils/dapp-store";
export const useSidebar = () => {
const isSidebarExpanded = useSelector(selectSidebarExpanded);
const selectedApps = useSelector(selectCheckedApps);
const availableApps = useSelector(selectAvailableApps);
+ const [developerMode] = useDeveloperMode();
const dispatch = useAppDispatch();
// on mobile sidebar is not expanded on load
const isMobile = useIsMobile();
@@ -51,31 +53,46 @@ export const useSidebar = () => {
[key: string]: any;
};
- selectedApps.map((element) => {
- const { appId, groupKey } = getValuesFromId(element);
- if (!availableApps[groupKey]) {
- return;
- }
- const option = availableApps[groupKey].options[appId];
- if (option === undefined) {
- return;
- }
+ selectedApps
+ .filter((element) => {
+ const { appId, groupKey } = getValuesFromId(element);
+ if (!availableApps[groupKey]) {
+ return false;
+ }
+ const option = availableApps[groupKey].options[appId];
+ if (option === undefined) {
+ return false;
+ }
+ if (option.devOnly && !developerMode) {
+ return false;
+ }
+ return true;
+ })
+ .map((element) => {
+ const { appId, groupKey } = getValuesFromId(element);
+ if (!availableApps[groupKey]) {
+ return;
+ }
+ const option = availableApps[groupKey].options[appId];
+ if (option === undefined) {
+ return;
+ }
- dynamicAppsSelection[element] = SIDEBAR_LIST[option.id]
- ? SIDEBAR_LIST[option.id]
- : {
- id: option.id,
- title: option.title,
- route: option.route,
- url: option.url,
- icon: option.icon,
- };
- });
+ dynamicAppsSelection[element] = SIDEBAR_LIST[option.id]
+ ? SIDEBAR_LIST[option.id]
+ : {
+ id: option.id,
+ title: option.title,
+ route: option.route,
+ url: option.url,
+ icon: option.icon,
+ };
+ });
dynamicAppsSelection["dappstore"] = SIDEBAR_LIST["DAppsStore"];
return dynamicAppsSelection;
- }, [availableApps, selectedApps]);
+ }, [availableApps, selectedApps, developerMode]);
const toggleSidebar = () => {
dispatch(setSidebarExpanded(!isSidebarExpanded));
diff --git a/packages/context/WalletsProvider/WalletsProvider.tsx b/packages/context/WalletsProvider/WalletsProvider.tsx
index 119e7e3833..5ad2410978 100644
--- a/packages/context/WalletsProvider/WalletsProvider.tsx
+++ b/packages/context/WalletsProvider/WalletsProvider.tsx
@@ -1,6 +1,7 @@
import React, { createContext, ReactNode, useContext, useMemo } from "react";
import { useAdena } from "./adena";
+import { useGnotest } from "./gnotest";
import { useKeplr } from "./keplr";
import { useLeap } from "./leap";
import { useMetamask } from "./metamask";
@@ -33,6 +34,7 @@ export const WalletsProvider: React.FC<{ children: ReactNode }> = React.memo(
const [hasLeap, leapIsReady, leapWallets] = useLeap();
const [hasMetamask, metamaskIsReady, metamaskWallets] = useMetamask();
const [hasAdena, adenaIsReady, adenaWallets] = useAdena();
+ const [hasGnotest, , gnotestWallets] = useGnotest();
const selectedNativeWallet = useSelectedNativeWallet();
const hasNative = !!selectedNativeWallet;
@@ -137,25 +139,34 @@ export const WalletsProvider: React.FC<{ children: ReactNode }> = React.memo(
}
}
+ if (hasGnotest) {
+ walletProviders.push(WalletProvider.Gnotest);
+ if (gnotestWallets?.[0]?.connected) {
+ wallets.push(gnotestWallets[0]);
+ }
+ }
+
return {
wallets,
walletProviders,
ready: keplrIsReady && metamaskIsReady && adenaIsReady && leapIsReady,
};
}, [
+ adenaIsReady,
+ adenaWallets,
+ gnotestWallets,
+ hasAdena,
+ hasGnotest,
hasKeplr,
hasLeap,
hasMetamask,
- hasAdena,
hasNative,
keplrIsReady,
- metamaskIsReady,
- adenaIsReady,
- leapIsReady,
keplrWallets,
+ leapIsReady,
leapWallets,
+ metamaskIsReady,
metamaskWallets,
- adenaWallets,
selectedNativeWallet,
]);
diff --git a/packages/context/WalletsProvider/gnotest/index.tsx b/packages/context/WalletsProvider/gnotest/index.tsx
new file mode 100644
index 0000000000..c09e82dec7
--- /dev/null
+++ b/packages/context/WalletsProvider/gnotest/index.tsx
@@ -0,0 +1,309 @@
+import {
+ GnoJSONRPCProvider,
+ GnoWallet,
+ MsgSend,
+ decodeTxMessages,
+} from "@gnolang/gno-js-client";
+import { TxFee, TransactionEndpoint, Tx } from "@gnolang/tm2-js-client";
+import Long from "long";
+import React from "react";
+import { Pressable } from "react-native";
+import { create } from "zustand";
+
+import { Wallet } from "../wallet";
+
+import { getUserId } from "@/networks";
+import { gnoDevNetwork } from "@/networks/gno-dev";
+import { setSelectedWalletId } from "@/store/slices/settings";
+import { useAppDispatch } from "@/store/store";
+import { RequestDocontractMessage } from "@/utils/gno";
+import { WalletProvider } from "@/utils/walletProvider";
+
+type UseGnotestResult = [true, boolean, Wallet[]] | [false, boolean, undefined];
+
+interface GnotestState {
+ connected: boolean;
+ wallet: GnoWallet | null;
+ address: string | null;
+ accounts: Account[];
+ connect: () => void;
+}
+
+interface Account {
+ wallet: GnoWallet;
+ address: string;
+}
+
+const network = gnoDevNetwork;
+
+interface UserMetadata {
+ imageURI: string;
+ displayName: string;
+ bio: string;
+}
+
+interface TestUser {
+ name: string;
+ mnemonic: string;
+ nsName: string;
+ extra: UserMetadata;
+}
+
+const faucetMnemo =
+ "chimney entire define lesson scale embark copy bird rough govern surprise soda sand evidence decline crisp clinic merry slice balance typical creek lumber hollow";
+
+const testUsers: TestUser[] = [
+ {
+ name: "alice",
+ nsName: "alicetests",
+ mnemonic:
+ "clog eager dumb mango sibling crime soldier climb switch either lock festival raven please badge weasel misery host grant make half assume strategy buzz",
+ extra: {
+ imageURI:
+ "ipfs://bafybeignxvdw76wqsokthgyp4d3jrvbdiikqwo4vbff6rwb5ivj7fb3aoi",
+ displayName: "Alice",
+ bio: "Seasoned marketing strategist with a knack for digital campaigns and brand building. With a background in content creation and SEO, has helped numerous startups grow their online presence and engage with their target audience effectively. Outside of work, is an avid reader, enjoys playing guitar, and is a dedicated coffee enthusiast. Reach out for insights on marketing trends and effective brand strategies.",
+ },
+ },
+ {
+ name: "bob",
+ nsName: "bobtests",
+ mnemonic:
+ "vault garment mosquito legend merit level flavor width correct amazing window skill title dwarf another journey cube junior chat ivory toilet area pool brick",
+ extra: {
+ imageURI:
+ "ipfs://bafkreifvzfnitqu6yq2t4dp37oeaqvitepuutrox332kcs5jncl7uxo6sy",
+ displayName: "Bob",
+ bio: "Passionate software developer with over 10 years of experience in web and mobile application development. Specializes in JavaScript, React, and Node.js, and loves creating seamless user experiences. When not coding, enjoys hiking, photography, and volunteering at local animal shelters. Connect to discuss innovative tech solutions and collaborative projects.",
+ },
+ },
+ {
+ name: "dredd",
+ nsName: "dreddtests",
+ mnemonic:
+ "nice daughter demise elevator gate manage observe real outer awkward profit sheriff total boat collect voice speed board pilot rifle nephew grid permit frozen",
+ extra: {
+ imageURI:
+ "ipfs://bafkreiahgkmcppkvxhkus7baqnflrcrff2pkjboi4t4eebt3dq6ui66foi",
+ displayName: "Dredd",
+ bio: "Cybersecurity expert with a focus on network security and ethical hacking. With over 15 years in the field, has a proven track record of safeguarding organizations from cyber threats and vulnerabilities. Also a frequent speaker at industry conferences and enjoys writing articles on the latest in cybersecurity. In free time, practices martial arts and enjoys building custom PCs. Connect for advice on protecting digital assets and staying ahead of cyber threats.",
+ },
+ },
+];
+
+const useGnotestStore = create((set, get) => ({
+ connected: false,
+ accounts: [],
+ wallet: null,
+ address: null,
+ connect: async () => {
+ const state = get();
+ if (state.connected) {
+ return;
+ }
+
+ const provider = new GnoJSONRPCProvider(network.endpoint);
+
+ const faucetWallet = await GnoWallet.fromMnemonic(faucetMnemo);
+ faucetWallet.connect(provider);
+ const faucerAddr = await faucetWallet.getAddress();
+
+ // fund users
+ const msgs = await Promise.all(
+ testUsers.map(async (testUser) => {
+ const wallet = await GnoWallet.fromMnemonic(testUser.mnemonic);
+ wallet.connect(provider);
+ // fund user
+ const msg: MsgSend = {
+ from_address: faucerAddr,
+ to_address: await wallet.getAddress(),
+ amount: "200000000000ugnot",
+ };
+ return msg;
+ }),
+ );
+ const tx: Tx = {
+ messages: msgs.map((msg) => ({
+ typeUrl: "/bank.MsgSend",
+ value: MsgSend.encode(msg).finish(),
+ })),
+ fee: {
+ gasFee: "1ugnot",
+ gasWanted: Long.fromNumber(1000000),
+ },
+ memo: "",
+ signatures: [],
+ };
+ const signed = await faucetWallet.signTransaction(tx, decodeTxMessages);
+ await faucetWallet.sendTransaction(
+ signed,
+ TransactionEndpoint.BROADCAST_TX_COMMIT,
+ );
+
+ const accounts = await Promise.all(
+ testUsers.map(async (testUser) => {
+ const wallet = await GnoWallet.fromMnemonic(testUser.mnemonic);
+ wallet.connect(provider);
+ const addr = await wallet.getAddress();
+
+ // try register user
+ try {
+ const nsRealm = network.nameServiceContractAddress;
+ const send = new Map();
+ send.set("ugnot", 200000000);
+ wallet.callMethod(
+ nsRealm,
+ "Register",
+ ["", testUser.nsName, JSON.stringify(testUser.extra)],
+ TransactionEndpoint.BROADCAST_TX_COMMIT,
+ send,
+ {
+ gasWanted: Long.fromNumber(10000000),
+ gasFee: "1ugnot",
+ },
+ );
+ } catch (e) {
+ console.warn("Failed to register user", testUser, e);
+ }
+
+ return {
+ wallet,
+ address: addr,
+ };
+ }),
+ );
+ set((state) => ({
+ ...state,
+ connected: true,
+ accounts,
+ wallet: accounts[0].wallet,
+ address: accounts[0].address,
+ }));
+ },
+}));
+
+const setupAdenaMock = () => {
+ (window as any).adena = {
+ SetTestUser: async (name: string) => {
+ const testUser = testUsers.find((u) => u.name === name);
+ if (!testUser) {
+ throw new Error("Test user not found: " + name);
+ }
+ const newAddr = await (
+ await GnoWallet.fromMnemonic(testUser.mnemonic)
+ ).getAddress();
+ const state = useGnotestStore.getState();
+ const account = state.accounts.find((a) => a.address === newAddr);
+ if (!account) {
+ throw new Error("Account not found: " + newAddr);
+ }
+ useGnotestStore.setState({
+ wallet: account.wallet,
+ address: account.address,
+ });
+ return getUserId(network.id, account.address);
+ },
+ GetAccount: async () => {
+ const state = useGnotestStore.getState();
+ return {
+ data: {
+ address: state.address,
+ chainId: network.chainId,
+ },
+ };
+ },
+ DoContract: async (req: RequestDocontractMessage) => {
+ try {
+ const state = useGnotestStore.getState();
+ if (!state.wallet) {
+ throw new Error("Wallet not connected");
+ }
+ const msg = req.messages[0];
+ if (msg.type !== "/vm.m_call") {
+ throw new Error("Unsupported message type: " + msg.type);
+ }
+ const txFee: TxFee = {
+ gasWanted: Long.fromNumber(req.gasWanted),
+ gasFee: req.gasFee.toString() + "ugnot",
+ };
+ let sendMap;
+ if (msg.value.send) {
+ sendMap = new Map();
+ const end = msg.value.send.length - "ugnot".length;
+ const sendAmount = (msg.value.send as string).substring(0, end);
+ console.log("docontract sendAmount", sendAmount);
+ sendMap.set("ugnot", +sendAmount);
+ }
+ const res = await state.wallet.callMethod(
+ msg.value.pkg_path,
+ msg.value.func,
+ msg.value.args,
+ TransactionEndpoint.BROADCAST_TX_COMMIT,
+ sendMap,
+ txFee,
+ );
+ return {
+ status: "success",
+ data: {
+ hash: res.hash,
+ height: res.height,
+ },
+ };
+ } catch (e) {
+ console.error("docontract error", e);
+ const errMsg = e instanceof Error ? e.message : `${e}`;
+ return {
+ status: "failure",
+ message: errMsg,
+ data: {
+ error: e,
+ },
+ };
+ }
+ },
+ };
+};
+
+export const useGnotest: () => UseGnotestResult = () => {
+ const { wallet, address } = useGnotestStore();
+ const wallets: Wallet[] = [];
+ if (wallet && address) {
+ wallets.push({
+ address,
+ provider: WalletProvider.Gnotest,
+ networkKind: network.kind,
+ networkId: network.id,
+ userId: getUserId(network.id, address),
+ connected: true,
+ id: `gnotest`,
+ });
+ }
+ return [true, true, wallets];
+};
+
+export const ConnectGnotestButton: React.FC<{
+ onDone?: () => void;
+}> = ({ onDone }) => {
+ const { connect } = useGnotestStore();
+ const dispatch = useAppDispatch();
+ return (
+ {
+ setupAdenaMock();
+ connect();
+ dispatch(setSelectedWalletId("gnotest"));
+ onDone?.();
+ }}
+ testID="connect-gnotest-wallet"
+ />
+ );
+};
+
+const TestHiddenButton: React.FC<{
+ testID: string | undefined;
+ onPress: () => void;
+}> = ({ testID, onPress }) => {
+ return (
+
+ );
+};
diff --git a/packages/hooks/useNSNameInfo.ts b/packages/hooks/useNSNameInfo.ts
index 8b5c1ec0ae..4e53905d07 100644
--- a/packages/hooks/useNSNameInfo.ts
+++ b/packages/hooks/useNSNameInfo.ts
@@ -64,6 +64,7 @@ export const useNSNameInfo = (
if (!address) {
return null;
}
+ // TODO: use profile realm
const res: NftInfoResponse = {
extension: {},
};
@@ -111,7 +112,7 @@ const gnoGetAddressByUsername = async (
try {
const res = await provider.evaluateExpression(
network.nameServiceContractAddress,
- `GetUserByName(${JSON.stringify(name)}).address`,
+ `GetUserByName(${JSON.stringify(name)}).Address`,
);
const address = extractGnoString(res);
return address;
diff --git a/packages/networks/cosmos-hub-theta/currencies.ts b/packages/networks/cosmos-hub-theta/currencies.ts
index 44f9c60612..c16f288398 100644
--- a/packages/networks/cosmos-hub-theta/currencies.ts
+++ b/packages/networks/cosmos-hub-theta/currencies.ts
@@ -6,6 +6,7 @@ export const cosmosHubThetaCurrencies: CurrencyInfo[] = [
denom: "uatom",
displayName: "ATOM",
decimals: 6,
+ variant: "cosmos",
coingeckoId: "cosmos",
icon: "cosmos-hub-circle.svg",
kind: "native",
diff --git a/packages/networks/cosmos-hub/currencies.ts b/packages/networks/cosmos-hub/currencies.ts
index 592f1d04ed..9fc336ed21 100644
--- a/packages/networks/cosmos-hub/currencies.ts
+++ b/packages/networks/cosmos-hub/currencies.ts
@@ -6,6 +6,7 @@ export const cosmosHubCurrencies: CurrencyInfo[] = [
denom: "uatom",
displayName: "ATOM",
decimals: 6,
+ variant: "cosmos",
coingeckoId: "cosmos",
icon: "cosmos-hub-circle.svg",
kind: "native",
diff --git a/packages/networks/cosmos-registry.ts b/packages/networks/cosmos-registry.ts
index 918dc84e99..63180bdf09 100644
--- a/packages/networks/cosmos-registry.ts
+++ b/packages/networks/cosmos-registry.ts
@@ -54,6 +54,7 @@ export const networksFromCosmosRegistry = (): CosmosNetworkInfo[] => {
decimals:
asset.denom_units.find((du) => du.denom === asset.display)
?.exponent || 6,
+ variant: "cosmos",
displayName: asset.symbol,
coingeckoId: asset.coingecko_id || "not-found",
icon:
diff --git a/packages/networks/ethereum-goerli/currencies.ts b/packages/networks/ethereum-goerli/currencies.ts
index 2f1072d9d6..4f3c6b3636 100644
--- a/packages/networks/ethereum-goerli/currencies.ts
+++ b/packages/networks/ethereum-goerli/currencies.ts
@@ -6,6 +6,7 @@ export const ethereumGoerliCurrencies: CurrencyInfo[] = [
denom: "0x0000000000000000000000000000000000000000", // native currency: wei
displayName: "GoerliETH",
decimals: 18,
+ variant: "ethereum",
coingeckoId: "ethereum",
icon: "ethereum-circle.svg",
kind: "native",
diff --git a/packages/networks/ethereum/currencies.ts b/packages/networks/ethereum/currencies.ts
index 46989a1966..be77c1116f 100644
--- a/packages/networks/ethereum/currencies.ts
+++ b/packages/networks/ethereum/currencies.ts
@@ -6,6 +6,7 @@ export const ethereumCurrencies: CurrencyInfo[] = [
denom: "0x0000000000000000000000000000000000000000", // native currency: wei
displayName: "ETH",
decimals: 18,
+ variant: "ethereum",
coingeckoId: "ethereum",
icon: "ethereum-circle.svg",
kind: "native",
diff --git a/packages/networks/features.ts b/packages/networks/features.ts
index 7e718ba128..5be05ca8d0 100644
--- a/packages/networks/features.ts
+++ b/packages/networks/features.ts
@@ -13,6 +13,7 @@ export enum NetworkFeature {
RiotP2E = "RiotP2E",
NFTBridge = "NFTBridge",
CosmWasmPremiumFeed = "CosmWasmPremiumFeed",
+ GnoProjectManager = "GnoProjectManager",
NFTMarketplaceLeaderboard = "NFTMarketplaceLeaderboard",
CosmWasmNFTsBurner = "CosmWasmNFTsBurner",
}
@@ -43,12 +44,26 @@ type CosmWasmSocialFeed = {
feedContractAddress: string;
};
+// Gno Project Manager
+
+const zodGnoProjectManager = z.object({
+ type: z.literal(NetworkFeature.GnoProjectManager),
+ projectsManagerPkgPath: z.string(),
+ paymentsDenom: z.string(),
+});
+
+type GnoProjectManager = z.infer;
+
+// Registry
+
export const allFeatureObjects = [
zodCosmWasmPremiumFeed,
zodCosmWasmNFTsBurner,
+ zodGnoProjectManager,
];
export type NetworkFeatureObject =
| CosmWasmPremiumFeed
| CosmWasmSocialFeed
- | CosmWasmNFTsBurner;
+ | CosmWasmNFTsBurner
+ | GnoProjectManager;
diff --git a/packages/networks/gno-dev/currencies.ts b/packages/networks/gno-dev/currencies.ts
index baa0c8ce2e..1f1fb4bf11 100644
--- a/packages/networks/gno-dev/currencies.ts
+++ b/packages/networks/gno-dev/currencies.ts
@@ -6,6 +6,17 @@ export const gnoCurrencies: CurrencyInfo[] = [
denom: "ugnot",
displayName: "GNOT",
decimals: 6,
+ variant: "gno",
+ coingeckoId: "gno",
+ icon: "gno.svg",
+ kind: "native",
+ color: currencyGNOcolor,
+ },
+ {
+ denom: "gno.land/r/demo/tori20",
+ displayName: "TORI",
+ decimals: 6,
+ variant: "grc20",
coingeckoId: "gno",
icon: "gno.svg",
kind: "native",
diff --git a/packages/networks/gno-dev/index.ts b/packages/networks/gno-dev/index.ts
index 0f1b3dd3f0..3af1938c6e 100644
--- a/packages/networks/gno-dev/index.ts
+++ b/packages/networks/gno-dev/index.ts
@@ -10,28 +10,38 @@ export const gnoDevNetwork: GnoNetworkInfo = {
NetworkFeature.Organizations,
NetworkFeature.SocialFeed,
NetworkFeature.UPP,
+ NetworkFeature.GnoProjectManager,
+ ],
+ featureObjects: [
+ {
+ type: NetworkFeature.GnoProjectManager,
+ projectsManagerPkgPath: "gno.land/r/teritori/projects_manager",
+ paymentsDenom: "ugnot",
+ },
],
currencies: gnoCurrencies,
stakeCurrency: "ugnot",
idPrefix: "gnodev",
chainId: "dev",
- endpoint: "http://127.0.0.1:36657/http://127.0.0.1:26657",
+ endpoint: "http://127.0.0.1:26657",
txExplorer: "https://gnoscan.io/transactions/details?txhash=$hash",
accountExplorer: "https://gnoscan.io/accounts/$address",
contractExplorer: "https://gnoscan.io/realms/details?path=$address",
testnet: true,
- backendEndpoint: "http://localhost:9090",
+ // backendEndpoint: "http://localhost:9090",
+ backendEndpoint: "https://dapp-backend.testnet.teritori.com",
vaultContractAddress: "",
- daoRegistryPkgPath: "gno.land/r/demo/teritori/dao_registry",
- socialFeedsPkgPath: "gno.land/r/demo/teritori/social_feeds",
- socialFeedsDAOPkgPath: "gno.land/r/demo/teritori/social_feeds_dao",
+ daoRegistryPkgPath: "gno.land/r/teritori/dao_registry",
+ socialFeedsPkgPath: "gno.land/r/teritori/social_feeds",
+ socialFeedsDAOPkgPath: "gno.land/r/teritori/social_feeds_dao",
nameServiceContractAddress: "gno.land/r/demo/users",
- modboardsPkgPath: "gno.land/r/demo/teritori/modboards",
- groupsPkgPath: "gno.land/r/demo/teritori/groups",
- votingGroupPkgPath: "gno.land/p/demo/teritori/dao_voting_group",
- daoProposalSinglePkgPath: "gno.land/p/demo/teritori/dao_proposal_single",
- daoInterfacesPkgPath: "gno.land/p/demo/teritori/dao_interfaces",
- daoCorePkgPath: "gno.land/p/demo/teritori/dao_core",
+ modboardsPkgPath: "gno.land/r/teritori/modboards",
+ groupsPkgPath: "gno.land/r/teritori/groups",
+ votingGroupPkgPath: "gno.land/p/teritori/dao_voting_group",
+ daoProposalSinglePkgPath: "gno.land/p/teritori/dao_proposal_single",
+
+ daoInterfacesPkgPath: "gno.land/p/teritori/dao_interfaces",
+ daoCorePkgPath: "gno.land/p/teritori/dao_core",
nameServiceDefaultImage:
"ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
gnowebURL: "http://127.0.0.1:8888",
diff --git a/packages/networks/gno-portal/currencies.ts b/packages/networks/gno-portal/currencies.ts
index baa0c8ce2e..b1beeaf715 100644
--- a/packages/networks/gno-portal/currencies.ts
+++ b/packages/networks/gno-portal/currencies.ts
@@ -10,5 +10,6 @@ export const gnoCurrencies: CurrencyInfo[] = [
icon: "gno.svg",
kind: "native",
color: currencyGNOcolor,
+ variant: "gno",
},
];
diff --git a/packages/networks/gno-portal/index.ts b/packages/networks/gno-portal/index.ts
index bacdd1158e..ac76c7d796 100644
--- a/packages/networks/gno-portal/index.ts
+++ b/packages/networks/gno-portal/index.ts
@@ -26,13 +26,13 @@ export const gnoPortalNetwork: GnoNetworkInfo = {
nameServiceContractAddress: "gno.land/r/demo/users",
nameServiceDefaultImage:
"ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
- daoRegistryPkgPath: "gno.land/r/demo/teritori/dao_registry",
- socialFeedsPkgPath: "gno.land/r/demo/teritori/social_feeds",
- socialFeedsDAOPkgPath: "gno.land/r/demo/teritori/social_feeds_dao",
- // modboardsPkgPath: "gno.land/r/demo/teritori/modboards_v4",
- groupsPkgPath: "gno.land/r/demo/teritori/groups",
- votingGroupPkgPath: "gno.land/p/demo/teritori/dao_voting_group",
- daoProposalSinglePkgPath: "gno.land/p/demo/teritori/dao_proposal_single",
- daoInterfacesPkgPath: "gno.land/p/demo/teritori/dao_interfaces",
- daoCorePkgPath: "gno.land/p/demo/teritori/dao_core",
+ daoRegistryPkgPath: "gno.land/r/teritori/dao_registry",
+ socialFeedsPkgPath: "gno.land/r/teritori/social_feeds",
+ socialFeedsDAOPkgPath: "gno.land/r/teritori/social_feeds_dao",
+ // modboardsPkgPath: "gno.land/r/teritori/modboards_v4",
+ groupsPkgPath: "gno.land/r/teritori/groups",
+ votingGroupPkgPath: "gno.land/p/teritori/dao_voting_group",
+ daoProposalSinglePkgPath: "gno.land/p/teritori/dao_proposal_single",
+ daoInterfacesPkgPath: "gno.land/p/teritori/dao_interfaces",
+ daoCorePkgPath: "gno.land/p/teritori/dao_core",
};
diff --git a/packages/networks/gno-teritori/currencies.ts b/packages/networks/gno-teritori/currencies.ts
index baa0c8ce2e..cb3c09b8b1 100644
--- a/packages/networks/gno-teritori/currencies.ts
+++ b/packages/networks/gno-teritori/currencies.ts
@@ -6,6 +6,7 @@ export const gnoCurrencies: CurrencyInfo[] = [
denom: "ugnot",
displayName: "GNOT",
decimals: 6,
+ variant: "gno",
coingeckoId: "gno",
icon: "gno.svg",
kind: "native",
diff --git a/packages/networks/gno-teritori/index.ts b/packages/networks/gno-teritori/index.ts
index 52a0639099..65ce09d447 100644
--- a/packages/networks/gno-teritori/index.ts
+++ b/packages/networks/gno-teritori/index.ts
@@ -10,6 +10,14 @@ export const gnoTeritoriNetwork: GnoNetworkInfo = {
NetworkFeature.Organizations,
NetworkFeature.SocialFeed,
NetworkFeature.UPP,
+ NetworkFeature.GnoProjectManager,
+ ],
+ featureObjects: [
+ {
+ type: NetworkFeature.GnoProjectManager,
+ projectsManagerPkgPath: "gno.land/r/teritori/escrow",
+ paymentsDenom: "ugnot",
+ },
],
currencies: gnoCurrencies,
stakeCurrency: "ugnot",
@@ -25,15 +33,15 @@ export const gnoTeritoriNetwork: GnoNetworkInfo = {
nameServiceContractAddress: "gno.land/r/demo/users",
nameServiceDefaultImage:
"ipfs://bafkreignptjimiu7wuux6mk6uh4hb4odb6ff62ny4bvdokrhes7g67huse",
- daoRegistryPkgPath: "gno.land/r/demo/teritori/dao_registry_v4",
- socialFeedsPkgPath: "gno.land/r/demo/teritori/social_feeds_v4",
- socialFeedsDAOPkgPath: "gno.land/r/demo/teritori/social_feeds_dao_v2",
- modboardsPkgPath: "gno.land/r/demo/teritori/modboards_v4",
- groupsPkgPath: "gno.land/r/demo/teritori/groups_v4",
- votingGroupPkgPath: "gno.land/p/demo/teritori/dao_voting_group_v2",
- daoProposalSinglePkgPath: "gno.land/p/demo/teritori/dao_proposal_single_v4",
- daoInterfacesPkgPath: "gno.land/p/demo/teritori/dao_interfaces_v5",
- daoCorePkgPath: "gno.land/p/demo/teritori/dao_core_v4",
+ daoRegistryPkgPath: "gno.land/r/teritori/dao_registry_v4",
+ socialFeedsPkgPath: "gno.land/r/teritori/social_feeds_v4",
+ socialFeedsDAOPkgPath: "gno.land/r/teritori/social_feeds_dao_v2",
+ modboardsPkgPath: "gno.land/r/teritori/modboards_v4",
+ groupsPkgPath: "gno.land/r/teritori/groups_v4",
+ votingGroupPkgPath: "gno.land/p/teritori/dao_voting_group_v2",
+ daoProposalSinglePkgPath: "gno.land/p/teritori/dao_proposal_single_v4",
+ daoInterfacesPkgPath: "gno.land/p/teritori/dao_interfaces_v5",
+ daoCorePkgPath: "gno.land/p/teritori/dao_core_v4",
gnowebURL: "https://testnet.gno.teritori.com",
faucetURL: "https://testnet.gno.teritori.com:5050/?toaddr=$addr",
};
diff --git a/packages/networks/gno-test3/currencies.ts b/packages/networks/gno-test3/currencies.ts
index baa0c8ce2e..cb3c09b8b1 100644
--- a/packages/networks/gno-test3/currencies.ts
+++ b/packages/networks/gno-test3/currencies.ts
@@ -6,6 +6,7 @@ export const gnoCurrencies: CurrencyInfo[] = [
denom: "ugnot",
displayName: "GNOT",
decimals: 6,
+ variant: "gno",
coingeckoId: "gno",
icon: "gno.svg",
kind: "native",
diff --git a/packages/networks/gno-test4/currencies.ts b/packages/networks/gno-test4/currencies.ts
index baa0c8ce2e..b1beeaf715 100644
--- a/packages/networks/gno-test4/currencies.ts
+++ b/packages/networks/gno-test4/currencies.ts
@@ -10,5 +10,6 @@ export const gnoCurrencies: CurrencyInfo[] = [
icon: "gno.svg",
kind: "native",
color: currencyGNOcolor,
+ variant: "gno",
},
];
diff --git a/packages/networks/osmosis-testnet/currencies.ts b/packages/networks/osmosis-testnet/currencies.ts
index a303be43a1..1e42e542e6 100644
--- a/packages/networks/osmosis-testnet/currencies.ts
+++ b/packages/networks/osmosis-testnet/currencies.ts
@@ -6,6 +6,7 @@ export const osmosisTestnetCurrencies: CurrencyInfo[] = [
denom: "uosmo",
displayName: "OSMO",
decimals: 6,
+ variant: "cosmos",
coingeckoId: "osmosis",
icon: "osmosis-circle.svg",
kind: "native",
diff --git a/packages/networks/osmosis/currencies.ts b/packages/networks/osmosis/currencies.ts
index fb7be4d49c..531b6297fa 100644
--- a/packages/networks/osmosis/currencies.ts
+++ b/packages/networks/osmosis/currencies.ts
@@ -6,6 +6,7 @@ export const osmosisCurrencies: CurrencyInfo[] = [
denom: "uosmo",
displayName: "OSMO",
decimals: 6,
+ variant: "cosmos",
coingeckoId: "osmosis",
icon: "osmosis-circle.svg",
kind: "native",
diff --git a/packages/networks/polygon-mumbai/currencies.ts b/packages/networks/polygon-mumbai/currencies.ts
index 7fa475c69f..61eaa967e9 100644
--- a/packages/networks/polygon-mumbai/currencies.ts
+++ b/packages/networks/polygon-mumbai/currencies.ts
@@ -6,6 +6,7 @@ export const polygonMumbaiCurrencies: CurrencyInfo[] = [
denom: "0x0000000000000000000000000000000000000000", // native currency: wei
displayName: "MATIC",
decimals: 18,
+ variant: "ethereum",
coingeckoId: "matic",
icon: "polygon.svg",
kind: "native",
diff --git a/packages/networks/polygon/currencies.ts b/packages/networks/polygon/currencies.ts
index 41e99fb676..7743389439 100644
--- a/packages/networks/polygon/currencies.ts
+++ b/packages/networks/polygon/currencies.ts
@@ -6,6 +6,7 @@ export const polygonCurrencies: CurrencyInfo[] = [
denom: "0x0000000000000000000000000000000000000000", // native currency: wei
displayName: "MATIC",
decimals: 18,
+ variant: "ethereum",
coingeckoId: "matic",
icon: "polygon.svg",
kind: "native",
diff --git a/packages/networks/saga-test2/index.ts b/packages/networks/saga-test2/index.ts
index f3cdaf397a..3b25595f0a 100644
--- a/packages/networks/saga-test2/index.ts
+++ b/packages/networks/saga-test2/index.ts
@@ -15,6 +15,7 @@ export const sagaTest2: CosmosNetworkInfo = {
coingeckoId: "not-found",
icon: "https://raw.githubusercontent.com/cosmos/chain-registry/master/saga/images/saga.svg",
color: "TODO",
+ variant: "cosmos",
},
],
features: [],
diff --git a/packages/networks/saga/index.ts b/packages/networks/saga/index.ts
index 94583d3411..d17d226655 100644
--- a/packages/networks/saga/index.ts
+++ b/packages/networks/saga/index.ts
@@ -16,6 +16,7 @@ export const sagaNetwork: CosmosNetworkInfo = {
coingeckoId: "saga-2",
icon: "https://raw.githubusercontent.com/cosmos/chain-registry/master/saga/images/saga.svg",
color: "TODO",
+ variant: "cosmos",
},
],
features: [],
diff --git a/packages/networks/teritori-localnet/currencies.ts b/packages/networks/teritori-localnet/currencies.ts
index 3eddd9280c..ef6dba4cf0 100644
--- a/packages/networks/teritori-localnet/currencies.ts
+++ b/packages/networks/teritori-localnet/currencies.ts
@@ -5,6 +5,7 @@ export const teritoriLocalnetCurrencies: CurrencyInfo[] = [
{
denom: "utori",
displayName: "TORI",
+ variant: "cosmos",
decimals: 6,
coingeckoId: "teritori",
icon: "icons/networks/teritori-circle.svg",
diff --git a/packages/networks/teritori-testnet/currencies.ts b/packages/networks/teritori-testnet/currencies.ts
index 3dd718088a..493fb08133 100644
--- a/packages/networks/teritori-testnet/currencies.ts
+++ b/packages/networks/teritori-testnet/currencies.ts
@@ -5,6 +5,7 @@ export const teritoriTestnetCurrencies: CurrencyInfo[] = [
{
denom: "utori",
displayName: "TORI",
+ variant: "cosmos",
decimals: 6,
coingeckoId: "teritori",
icon: "teritori-circle.svg",
diff --git a/packages/networks/teritori/currencies.ts b/packages/networks/teritori/currencies.ts
index ce384c1635..5c1bfc44f0 100644
--- a/packages/networks/teritori/currencies.ts
+++ b/packages/networks/teritori/currencies.ts
@@ -5,6 +5,7 @@ export const teritoriCurrencies: CurrencyInfo[] = [
{
denom: "utori",
displayName: "TORI",
+ variant: "cosmos",
decimals: 6,
coingeckoId: "teritori",
icon: "teritori-circle.svg",
diff --git a/packages/networks/types.ts b/packages/networks/types.ts
index 1481d490aa..626a7357df 100644
--- a/packages/networks/types.ts
+++ b/packages/networks/types.ts
@@ -127,6 +127,7 @@ export type NetworkInfo =
export type NativeCurrencyInfo = {
kind: "native";
+ variant: "cosmos" | "ethereum" | "gno" | "grc20";
denom: string;
displayName: string;
decimals: number;
diff --git a/packages/screens/DAppStore/components/RightRail.tsx b/packages/screens/DAppStore/components/RightRail.tsx
index 0592795d34..70172fde50 100644
--- a/packages/screens/DAppStore/components/RightRail.tsx
+++ b/packages/screens/DAppStore/components/RightRail.tsx
@@ -7,6 +7,7 @@ import { DAppBox } from "./DAppBox";
import { BrandText } from "@/components/BrandText";
import { SVGorImageIcon } from "@/components/SVG/SVGorImageIcon";
import { GridList } from "@/components/layout/GridList";
+import { useDeveloperMode } from "@/hooks/useDeveloperMode";
import { selectAvailableApps } from "@/store/slices/dapps-store";
import { layout } from "@/utils/style/layout";
import { dAppType } from "@/utils/types/dapp-store";
@@ -14,6 +15,7 @@ import { dAppType } from "@/utils/types/dapp-store";
export const RightRail = ({ searchInput }: { searchInput: string }) => {
const availableApps = useSelector(selectAvailableApps);
const { width } = useWindowDimensions();
+ const [developerMode] = useDeveloperMode();
const isMobile = width < 760;
return (
{
noFixedHeight
keyExtractor={(item) => item.id}
data={Object.values(element.options).filter(
- (option: dAppType) =>
- option.title
+ (option: dAppType) => {
+ if (option.devOnly && !developerMode) {
+ return false;
+ }
+ return option.title
.toLowerCase()
- .includes(searchInput.toLowerCase()),
+ .includes(searchInput.toLowerCase());
+ },
)}
minElemWidth={300}
renderItem={({ item: option }, elemWidth) => {
diff --git a/packages/screens/DAppStore/query/getFromFile.ts b/packages/screens/DAppStore/query/getFromFile.ts
index 7b1636137d..4896bf26cb 100644
--- a/packages/screens/DAppStore/query/getFromFile.ts
+++ b/packages/screens/DAppStore/query/getFromFile.ts
@@ -14,6 +14,7 @@ import multisig from "@/assets/icons/multisig.svg";
import osmosisSVG from "@/assets/icons/networks/osmosis.svg";
import teritoriSVG from "@/assets/icons/networks/teritori.svg";
import pathwar from "@/assets/icons/pathwar.svg";
+import projectsProgramSVG from "@/assets/icons/projects-program.svg";
import otherAppsIcon from "@/assets/icons/random-goods-icon.svg";
import riot from "@/assets/icons/rioters-game.svg";
import staking from "@/assets/icons/staking.svg";
@@ -192,6 +193,17 @@ export function getAvailableApps(): dAppGroup {
selectedByDefault: true,
alwaysOn: true,
},
+ projects: {
+ id: "projects",
+ title: "Projects Program",
+ icon: projectsProgramSVG,
+ description: "Projects Program",
+ route: "Projects",
+ groupKey: "top-apps",
+ selectedByDefault: false,
+ alwaysOn: false,
+ devOnly: true,
+ },
toripunks: {
id: "toripunks",
title: "Toripunks dApp",
diff --git a/packages/screens/MarketplaceLeaderboardScreen/component/MarketplaceLeaderboardTable.tsx b/packages/screens/MarketplaceLeaderboardScreen/component/MarketplaceLeaderboardTable.tsx
index 39be10ff22..5361050e1e 100644
--- a/packages/screens/MarketplaceLeaderboardScreen/component/MarketplaceLeaderboardTable.tsx
+++ b/packages/screens/MarketplaceLeaderboardScreen/component/MarketplaceLeaderboardTable.tsx
@@ -5,7 +5,6 @@ import { FlatList, View } from "react-native";
import { screenContentMaxWidthLarge } from "../../../utils/style/layout";
import { LeaderboardEntry } from "@/api/marketplace/v1/marketplace";
-import { UserNameInline } from "@/components/UserNameInline";
import { SpacerColumn } from "@/components/spacer";
import { TableCell } from "@/components/table/TableCell";
import { TableHeader } from "@/components/table/TableHeader";
@@ -13,6 +12,7 @@ import { TableRow } from "@/components/table/TableRow";
import { TableTextCell } from "@/components/table/TableTextCell";
import { TableWrapper } from "@/components/table/TableWrapper";
import { TableColumns } from "@/components/table/utils";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
import { getMarketplaceClient } from "@/utils/backend";
const columns: TableColumns = {
@@ -125,7 +125,7 @@ const MarketplaceLeaderboardTableRow: React.FC<{
flex: columns.userId.flex,
}}
>
-
+
{
{
label: (
-
+
ninja.tori
diff --git a/packages/screens/Projects/CompleteMilestoneScreen.tsx b/packages/screens/Projects/CompleteMilestoneScreen.tsx
new file mode 100644
index 0000000000..fa0259fda9
--- /dev/null
+++ b/packages/screens/Projects/CompleteMilestoneScreen.tsx
@@ -0,0 +1,263 @@
+import React, { useState } from "react";
+import { View } from "react-native";
+import { SvgProps } from "react-native-svg";
+
+import { HeaderBackButton } from "./components/HeaderBackButton";
+import { MilestoneStatusTag } from "./components/MilestoneStatusTag";
+import { useProject } from "./hooks/useProjects";
+import { Project, ProjectMilestone } from "./types";
+import githubSVG from "../../../assets/icons/github.svg";
+import FlexRow from "../../components/FlexRow";
+import useSelectedWallet from "../../hooks/useSelectedWallet";
+
+import { BrandText } from "@/components/BrandText";
+import { ScreenContainer } from "@/components/ScreenContainer";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { PrimaryButtonOutline } from "@/components/buttons/PrimaryButtonOutline";
+import { SocialButton } from "@/components/buttons/SocialButton";
+import { RoundedGradientImage } from "@/components/images/RoundedGradientImage";
+import { TextInputCustom } from "@/components/inputs/TextInputCustom";
+import { Separator } from "@/components/separators/Separator";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { prettyPrice } from "@/utils/coins";
+import { ScreenFC, useAppNavigation } from "@/utils/navigation";
+import {
+ neutral17,
+ neutral77,
+ neutralA3,
+ neutralFF,
+ primaryColor,
+ redDefault,
+} from "@/utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold16,
+ fontSemibold20,
+ fontSemibold28,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+const CustomSocialButton: React.FC<{
+ text: string;
+ iconSvg: React.FC;
+}> = ({ text, iconSvg }) => {
+ return (
+
+ );
+};
+
+export const ProjectsCompleteMilestoneScreen: ScreenFC<
+ "ProjectsCompleteMilestone"
+> = ({ route: { params } }) => {
+ const navigation = useAppNavigation();
+
+ const networkId = useSelectedNetworkId();
+ const { projectId, milestoneId } = params;
+ const [isProcessing, setIsProcessing] = useState(false);
+ const selectedWallet = useSelectedWallet();
+
+ const { data: project } = useProject(projectId);
+ const milestone = (project?.milestones || []).find(
+ (_, idx) => idx === +milestoneId,
+ );
+
+ const [report, setReport] = useState("");
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+
+ const completeMilestone = async (
+ project: Project,
+ milestone: ProjectMilestone,
+ ) => {
+ setIsProcessing(true);
+
+ const isOk = await execEscrowMethod("CompleteMilestoneAndPay", [
+ project?.id?.toString(),
+ milestone.id.toString(),
+ ]);
+
+ setIsProcessing(true);
+
+ if (isOk) {
+ navigation.navigate("ProjectsDetail", { id: projectId });
+ }
+ };
+
+ if (!milestone || !project) return null;
+
+ return (
+ }>
+
+
+
+
+
+
+ Project
+
+
+
+ {project.metadata?.shortDescData?.name}
+
+
+
+
+
+
+
+ {/* Left Col ==========================================================*/}
+
+
+
+
+ Milestone: {milestone.title}
+
+
+
+
+
+ {milestone.desc}
+
+
+
+
+
+
+
+ Report input:
+
+
+
+
+ setReport(text)}
+ label=""
+ name="name"
+ placeholder="Enter details here..."
+ hideLabel
+ multiline
+ noBrokenCorners
+ containerStyle={{ width: "100%" }}
+ textInputStyle={{ height: 80 }}
+ />
+
+
+
+
+
+
+
+
+
+ {/* Right Col =========================================================*/}
+
+
+
+ Budget
+
+
+ {prettyPrice(networkId, milestone.amount, project.paymentDenom)}
+
+
+
+
+
+
+ Status
+
+
+
+
+
+
+
+
+ Contractor:
+
+
+
+ @{project?.contractor}
+
+
+
+
+
+
+
+
+
+
+
+
+ completeMilestone(project, milestone)}
+ fullWidth
+ disabled={isProcessing}
+ text="Complete the Milestone"
+ />
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsConflictSolvingScreen/NewConflictSection.tsx b/packages/screens/Projects/ProjectsConflictSolvingScreen/NewConflictSection.tsx
new file mode 100644
index 0000000000..a886671863
--- /dev/null
+++ b/packages/screens/Projects/ProjectsConflictSolvingScreen/NewConflictSection.tsx
@@ -0,0 +1,82 @@
+import React, { FC, useState } from "react";
+
+import { BrandText } from "@/components/BrandText";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButtonOutline } from "@/components/buttons/PrimaryButtonOutline";
+import { TextInputCustom } from "@/components/inputs/TextInputCustom";
+import { SpacerColumn } from "@/components/spacer";
+import { parseUserId } from "@/networks";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { neutral17, neutralFF, redDefault } from "@/utils/style/colors";
+import { fontSemibold28 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const NewConflictSection: FC<{
+ projectId: string | undefined;
+ userId: string | undefined;
+}> = ({ projectId, userId }) => {
+ const [initialMessage, setInitialMessage] = useState("");
+ const [network, userAddress] = parseUserId(userId);
+
+ const { execEscrowMethod } = useEscrowContract(network?.id, userAddress);
+
+ return (
+ <>
+
+ New conflict
+
+
+
+ Initial message
+
+
+
+
+ setInitialMessage(text)}
+ label=""
+ name="initialMessage"
+ placeholder="Enter details here..."
+ hideLabel
+ multiline
+ noBrokenCorners
+ containerStyle={{ width: "100%" }}
+ textInputStyle={{ height: 80 }}
+ />
+
+
+
+ {
+ const [network, userAddress] = parseUserId(userId);
+ if (!network || !userAddress) {
+ throw new Error("Invalid user id");
+ }
+ if (!projectId) {
+ throw new Error("Invalid project id");
+ }
+
+ await execEscrowMethod("RequestConflictResolution", [
+ projectId,
+ initialMessage,
+ ]);
+ }}
+ />
+
+ >
+ );
+};
diff --git a/packages/screens/Projects/ProjectsConflictSolvingScreen/OngoingConflictSection.tsx b/packages/screens/Projects/ProjectsConflictSolvingScreen/OngoingConflictSection.tsx
new file mode 100644
index 0000000000..f2df44a926
--- /dev/null
+++ b/packages/screens/Projects/ProjectsConflictSolvingScreen/OngoingConflictSection.tsx
@@ -0,0 +1,298 @@
+import { Picker } from "@react-native-picker/picker";
+import moment from "moment/moment";
+import React, { FC, useState } from "react";
+import { View } from "react-native";
+
+import { BrandText } from "@/components/BrandText";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButtonOutline } from "@/components/buttons/PrimaryButtonOutline";
+import { TextInputCustom } from "@/components/inputs/TextInputCustom";
+import { SpacerColumn } from "@/components/spacer";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { getUserId, parseUserId } from "@/networks";
+import {
+ PartyRole,
+ UserRole,
+} from "@/screens/Projects/ProjectsConflictSolvingScreen/types";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { useProject } from "@/screens/Projects/hooks/useProjects";
+import {
+ errorColor,
+ neutral17,
+ redDefault,
+ yellowDefault,
+} from "@/utils/style/colors";
+import { fontSemibold28 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const OngoingConflictSection: FC<{
+ userId: string | undefined;
+ projectId: string | undefined;
+}> = ({ userId, projectId }) => {
+ const [network, userAddress] = parseUserId(userId);
+ const [outcome, setOutcome] = useState(1);
+ const [responseMessage, setResponseMessage] = useState("");
+ const [resolutionMessage, setResolutionMessage] = useState("");
+ const { data: project } = useProject(projectId);
+ const conflicts = project?.conflicts;
+ const lastConflict = conflicts?.length
+ ? conflicts[conflicts.length - 1]
+ : null;
+
+ const { execEscrowMethod } = useEscrowContract(network?.id, userAddress);
+
+ let responderAddress;
+ if (lastConflict?.initiator === project?.contractor) {
+ responderAddress = project?.funder;
+ } else {
+ responderAddress = project?.contractor;
+ }
+
+ let userRole: UserRole;
+ if (lastConflict?.initiator === userAddress) {
+ userRole = "initiator";
+ } else if (responderAddress === userAddress) {
+ userRole = "responder";
+ } else if (project?.conflictHandler === userAddress) {
+ userRole = "resolver";
+ } else {
+ userRole = "observer";
+ }
+
+ let initiatorRole: PartyRole;
+ if (lastConflict?.initiator === project?.contractor) {
+ initiatorRole = "contractor";
+ } else {
+ initiatorRole = "funder";
+ }
+ let responderRole: PartyRole;
+ if (responderAddress === project?.contractor) {
+ responderRole = "contractor";
+ } else {
+ responderRole = "funder";
+ }
+
+ return (
+
+
+ Ongoing conflict
+
+
+
+
+ Initial message by {initiatorRole} on{" "}
+ {moment(lastConflict?.createdAt).format("MMM D, YYYY")}
+
+
+
+
+
+
+ {(userRole === "responder" || !!lastConflict?.respondedAt) && (
+ <>
+
+
+
+ Response by {responderRole} on{" "}
+ {moment(lastConflict?.respondedAt).format("MMM D, YYYY")}
+
+
+
+
+
+ {userRole === "responder" && !lastConflict?.respondedAt && (
+ <>
+
+ {
+ if (!projectId) {
+ throw new Error("Invalid project id");
+ }
+ if (!network || !userAddress) {
+ throw new Error("Invalid user id");
+ }
+
+ await execEscrowMethod("RespondToConflict", [
+ projectId,
+ responseMessage,
+ ]);
+ }}
+ />
+ >
+ )}
+ >
+ )}
+
+ {(!!lastConflict?.resolvedAt || userRole === "resolver") &&
+ !lastConflict?.respondedAt && (
+ <>
+
+
+
+ No response from {responderRole} after{" "}
+ {moment(lastConflict?.createdAt).fromNow(true)}
+
+
+
+ >
+ )}
+
+ {userRole !== "resolver" && !lastConflict?.resolvedAt && (
+ <>
+
+
+ Waiting for{!lastConflict?.respondedAt ? " response or " : " "}
+ resolution for {moment(lastConflict?.createdAt).fromNow(true)}...
+
+ >
+ )}
+
+ {(userRole === "resolver" || !!lastConflict?.resolvedAt) && (
+ <>
+
+
+ Verdict
+
+
+
+
+ {userRole === "resolver" && !lastConflict?.resolvedAt && (
+ <>
+
+
+
+ {
+ if (!projectId) {
+ throw new Error("Invalid project id");
+ }
+ if (!network || !userAddress) {
+ throw new Error("Invalid user id");
+ }
+
+ await execEscrowMethod("ResolveConflict", [
+ projectId,
+ outcome.toString(),
+ resolutionMessage,
+ ]);
+ }}
+ />
+ >
+ )}
+ >
+ )}
+
+
+ );
+};
+
+const OutcomeSelect: FC<{
+ value: number;
+ onChange: (value: number) => void;
+}> = ({ value, onChange }) => {
+ return (
+ selectedValue={value} onValueChange={onChange}>
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsConflictSolvingScreen/SettledConflictsSection.tsx b/packages/screens/Projects/ProjectsConflictSolvingScreen/SettledConflictsSection.tsx
new file mode 100644
index 0000000000..9970e8939c
--- /dev/null
+++ b/packages/screens/Projects/ProjectsConflictSolvingScreen/SettledConflictsSection.tsx
@@ -0,0 +1,204 @@
+import moment from "moment/moment";
+import React, { FC } from "react";
+import { View } from "react-native";
+
+import { BrandText } from "@/components/BrandText";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { TextInputCustom } from "@/components/inputs/TextInputCustom";
+import { SpacerColumn } from "@/components/spacer";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { getUserId, parseNetworkObjectId } from "@/networks";
+import { PartyRole } from "@/screens/Projects/ProjectsConflictSolvingScreen/types";
+import { useProject } from "@/screens/Projects/hooks/useProjects";
+import { errorColor, neutral17 } from "@/utils/style/colors";
+import { fontSemibold28 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const SettledConflictsSection: FC<{
+ projectId: string | undefined;
+}> = ({ projectId }) => {
+ const [network] = parseNetworkObjectId(projectId);
+ const networkId = network?.id;
+ const { data: project } = useProject(projectId);
+ return (
+ <>
+ Settled conflicts
+ {[...(project?.conflicts || [])]
+ .reverse()
+ .filter((c) => !!c.outcome)
+ .map((conflict, index) => {
+ let responderAddress;
+ if (conflict.initiator === project?.contractor) {
+ responderAddress = project?.funder;
+ } else {
+ responderAddress = project?.contractor;
+ }
+
+ let initiatorRole: PartyRole;
+ if (conflict.initiator === project?.contractor) {
+ initiatorRole = "contractor";
+ } else {
+ initiatorRole = "funder";
+ }
+ let responderRole: PartyRole;
+ if (responderAddress === project?.contractor) {
+ responderRole = "contractor";
+ } else {
+ responderRole = "funder";
+ }
+
+ let outcomeColor, outcomeText;
+ switch (conflict.outcome) {
+ case "RESUME_CONTRACT":
+ outcomeColor = "white";
+ outcomeText = "Project resumed";
+ break;
+ case "REFUND_FUNDER":
+ outcomeColor = errorColor;
+ outcomeText = "Funder reimbursed";
+ break;
+ case "PAY_CONTRACTOR":
+ outcomeColor = errorColor;
+ outcomeText = "Contractor paid";
+ break;
+ default:
+ outcomeColor = errorColor;
+ outcomeText = "Unknown outcome";
+ break;
+ }
+
+ return (
+ <>
+
+
+
+
+ Initial message by {initiatorRole} on{" "}
+ {moment(conflict.createdAt).format("MMM D, YYYY")}
+
+
+
+
+
+
+
+
+ {conflict.respondedAt ? (
+ <>
+
+
+ Response by {responderRole} on{" "}
+ {moment(conflict.respondedAt).format("MMM D, YYYY")}
+
+
+
+
+
+ >
+ ) : (
+ <>
+
+
+ No response from {responderRole} after{" "}
+ {moment(conflict.createdAt).fromNow(true)}
+
+
+
+ >
+ )}
+
+
+
+
+ Verdict on{" "}
+ {moment(conflict.resolvedAt).format("MMM D, YYYY")}
+
+
+
+
+
+
+
+ {outcomeText}
+
+
+ >
+ );
+ })}
+ >
+ );
+};
diff --git a/packages/screens/Projects/ProjectsConflictSolvingScreen/index.tsx b/packages/screens/Projects/ProjectsConflictSolvingScreen/index.tsx
new file mode 100644
index 0000000000..a66158d4e7
--- /dev/null
+++ b/packages/screens/Projects/ProjectsConflictSolvingScreen/index.tsx
@@ -0,0 +1,45 @@
+import React from "react";
+
+import { useProject } from "../hooks/useProjects";
+
+import { ScreenContainer } from "@/components/ScreenContainer";
+import { SpacerColumn } from "@/components/spacer";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { NewConflictSection } from "@/screens/Projects/ProjectsConflictSolvingScreen/NewConflictSection";
+import { OngoingConflictSection } from "@/screens/Projects/ProjectsConflictSolvingScreen/OngoingConflictSection";
+import { SettledConflictsSection } from "@/screens/Projects/ProjectsConflictSolvingScreen/SettledConflictsSection";
+import { ScreenFC } from "@/utils/navigation";
+
+export const ProjectsConflictSolvingScreen: ScreenFC<
+ "ProjectsConflictSolving"
+> = ({ route }) => {
+ const projectId = route.params.projectId;
+ const selectedWallet = useSelectedWallet();
+ const userId = selectedWallet?.userId;
+ const userAddress = selectedWallet?.address;
+ const { data: project } = useProject(projectId);
+ const userIsParty =
+ !!project &&
+ !!userAddress &&
+ (userAddress === project?.contractor || userAddress === project?.funder);
+ return (
+
+
+ {project?.status === "ACCEPTED" && userIsParty && (
+
+ )}
+
+ {project?.status === "CONFLICT" && (
+
+ )}
+
+ {(project?.conflicts?.length || 0) > 0 &&
+ !(
+ project?.conflicts?.length === 1 && project.status === "CONFLICT"
+ ) && }
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsConflictSolvingScreen/types.ts b/packages/screens/Projects/ProjectsConflictSolvingScreen/types.ts
new file mode 100644
index 0000000000..01443b2a37
--- /dev/null
+++ b/packages/screens/Projects/ProjectsConflictSolvingScreen/types.ts
@@ -0,0 +1,2 @@
+export type UserRole = "initiator" | "responder" | "resolver" | "observer";
+export type PartyRole = "contractor" | "funder";
diff --git a/packages/screens/Projects/ProjectsDetailScreen/MilestoneDetail.tsx b/packages/screens/Projects/ProjectsDetailScreen/MilestoneDetail.tsx
new file mode 100644
index 0000000000..ee076dca20
--- /dev/null
+++ b/packages/screens/Projects/ProjectsDetailScreen/MilestoneDetail.tsx
@@ -0,0 +1,222 @@
+import { Link } from "@react-navigation/native";
+import { useQueryClient } from "@tanstack/react-query";
+import React, { useState } from "react";
+import { TouchableOpacity, View } from "react-native";
+
+import chevronRightSVG from "@/assets/icons/chevron-right.svg";
+import closeSVG from "@/assets/icons/close.svg";
+import githubSVG from "@/assets/icons/github.svg";
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { SVG } from "@/components/SVG";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { SelectInput, SelectInputItem } from "@/components/inputs/SelectInput";
+import { Separator } from "@/components/separators/Separator";
+import { SpacerColumn } from "@/components/spacer";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { getNetworkObjectId } from "@/networks";
+import { MilestonePriorityTag } from "@/screens/Projects/components/MilestonePriorityTag";
+import { MilestoneStatusTag } from "@/screens/Projects/components/MilestoneStatusTag";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import {
+ MilestoneStatus,
+ Project,
+ ProjectMilestone,
+ zodMilestoneStatus,
+} from "@/screens/Projects/types";
+import {
+ neutral00,
+ neutral22,
+ neutral33,
+ neutralA3,
+} from "@/utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold20,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { objectKeys } from "@/utils/typescript";
+
+const STATUSES: SelectInputItem[] = [
+ { label: "Open", value: "MS_OPEN" },
+ { label: "In Progress", value: "MS_PROGRESS" },
+ { label: "Review", value: "MS_REVIEW" },
+ { label: "Completed", value: "MS_COMPLETED" },
+];
+
+export const MilestoneDetail: React.FC<{
+ project: Project;
+ milestone: ProjectMilestone;
+ editable?: boolean;
+ onClose?: (milestone: ProjectMilestone) => void;
+}> = ({ project, editable, milestone, onClose }) => {
+ const [newStatus, setNewStatus] = useState(milestone.status);
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+ const [isProcessing, setIsProcessing] = useState(false);
+ const queryClient = useQueryClient();
+
+ const changeMilestoneStatus = async (
+ project: Project,
+ milestone: ProjectMilestone,
+ ) => {
+ setIsProcessing(true);
+ try {
+ // Convert milestone status => status id
+ let statusId = 1;
+ for (const msStatus of objectKeys(zodMilestoneStatus.enum)) {
+ if (msStatus === newStatus) {
+ break;
+ }
+ statusId++;
+ }
+
+ const refetch = () =>
+ Promise.all([
+ queryClient.invalidateQueries(["projects", networkId]),
+ queryClient.invalidateQueries([
+ "project",
+ getNetworkObjectId(networkId, project.id),
+ ]),
+ ]);
+
+ if (newStatus === "MS_COMPLETED") {
+ await execEscrowMethod("CompleteMilestoneAndPay", [
+ project.id.toString(),
+ milestone.id.toString(),
+ ]);
+ await refetch();
+ return;
+ }
+
+ await execEscrowMethod("ChangeMilestoneStatus", [
+ project.id.toString(),
+ milestone.id.toString(),
+ statusId.toString(),
+ ]);
+ await refetch();
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ return (
+
+ onClose?.(milestone)}>
+
+
+
+ {milestone.title}
+
+
+
+
+
+ Status
+
+
+
+
+
+
+
+
+
+ Priority
+
+
+
+
+
+
+
+ Description
+
+
+
+
+ {milestone.desc}
+
+
+
+
+
+
+
+
+ Github link
+
+
+
+
+
+
+ {editable && (
+
+
+ Change status
+
+
+ s.value === newStatus) || STATUSES[0]
+ }
+ selectItem={(item) => setNewStatus(item.value as MilestoneStatus)}
+ boxStyle={{ height: 32 }}
+ testID="milestone-select-new-status"
+ />
+
+
+
+ changeMilestoneStatus(project, milestone)}
+ fullWidth
+ size="SM"
+ />
+
+ )}
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsDetailScreen/index.tsx b/packages/screens/Projects/ProjectsDetailScreen/index.tsx
new file mode 100644
index 0000000000..715accdfb2
--- /dev/null
+++ b/packages/screens/Projects/ProjectsDetailScreen/index.tsx
@@ -0,0 +1,74 @@
+import React, { useState } from "react";
+import { View } from "react-native";
+
+import { HeaderBackButton } from "../components/HeaderBackButton";
+import { ProjectInfo } from "../components/ProjectInfo";
+import { ProjectMilestones } from "../components/ProjectMilestones";
+import { useProject } from "../hooks/useProjects";
+
+import { ScreenContainer } from "@/components/ScreenContainer";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { MilestoneDetail } from "@/screens/Projects/ProjectsDetailScreen/MilestoneDetail";
+import { ScreenFC } from "@/utils/navigation";
+
+export const ProjectsDetailScreen: ScreenFC<"ProjectsDetail"> = ({
+ route: { params },
+}) => {
+ const selectedWallet = useSelectedWallet();
+
+ const [selectedMilestoneId, setSelectedMilestoneId] = useState(
+ null,
+ );
+
+ const { data: project } = useProject(params.id);
+
+ const selectedMilestone = project?.milestones.find(
+ (m) => m.id === selectedMilestoneId,
+ );
+
+ const onSelectMilestone = (id: string) => {
+ setSelectedMilestoneId(id);
+ };
+
+ if (!project)
+ return (
+ }
+ />
+ );
+
+ return (
+ }
+ footerChildren={<>>}
+ >
+
+
+
+
+
+
+ {/* Detail view ======================================================= */}
+ {selectedMilestone !== undefined && (
+ setSelectedMilestoneId(null)}
+ editable={
+ (project.contractor === selectedWallet?.address &&
+ selectedMilestone.status === "MS_OPEN") ||
+ (project.funder === selectedWallet?.address &&
+ selectedMilestone.status === "MS_REVIEW")
+ }
+ />
+ )}
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/ConfirmAndSign.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/ConfirmAndSign.tsx
new file mode 100644
index 0000000000..103be207f9
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/ConfirmAndSign.tsx
@@ -0,0 +1,338 @@
+import { useQueryClient } from "@tanstack/react-query";
+import React, { useMemo, useState } from "react";
+import { Image, View } from "react-native";
+
+import gnoSVG from "../../../../assets/icons/networks/gno.svg";
+import projectSuccessPaymentPNG from "../../../../assets/project-success-payment.png";
+import ModalBase from "../../../components/modals/ModalBase";
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { Tag } from "../components/Milestone";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+import {
+ MilestoneRequest,
+ ProjectShortDescData,
+ ProjectTeamAndLinkData,
+} from "../types";
+
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { SVG } from "@/components/SVG";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { SecondaryButton } from "@/components/buttons/SecondaryButton";
+import { SecondaryButtonOutline } from "@/components/buttons/SecondaryButtonOutline";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { useFeedbacks } from "@/context/FeedbacksProvider";
+import { useBalances } from "@/hooks/useBalances";
+import {
+ useSelectedNetworkId,
+ useSelectedNetworkInfo,
+} from "@/hooks/useSelectedNetwork";
+import { NetworkFeature, getNetworkFeature } from "@/networks";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { prettyPrice } from "@/utils/coins";
+import { useAppNavigation } from "@/utils/navigation";
+import {
+ neutral00,
+ neutral17,
+ neutral33,
+ neutral77,
+ neutralFF,
+} from "@/utils/style/colors";
+import {
+ fontSemibold12,
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold16,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { tinyAddress } from "@/utils/text";
+
+export const ConfirmAndSign: React.FC = () => {
+ const [isShowModal, setIsShowModal] = useState(false);
+ const [isShowConfirmModal, setIsShowConfirmModal] = useState(true);
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const navigation = useAppNavigation();
+ const {
+ projectFormData,
+ milestones,
+ teamAndLinkData: teamAndLinkFormData,
+ } = useMakeRequestState();
+ const networkId = useSelectedNetworkId();
+
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+
+ const selectedWallet = useSelectedWallet();
+ const selectedNetwork = useSelectedNetworkInfo();
+ const { balances } = useBalances(
+ selectedNetwork?.id,
+ selectedWallet?.address,
+ );
+ const bal = balances?.find((b) => b.denom === pmFeature?.paymentsDenom);
+
+ const { setToast } = useFeedbacks();
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+
+ const queryClient = useQueryClient();
+
+ const cancel = async () => {
+ setIsShowConfirmModal(false);
+ navigation.replace("Projects", { network: networkId });
+ };
+
+ const confirmAndSign = async () => {
+ try {
+ setIsProcessing(true);
+
+ if (!projectFormData.coverImg) {
+ setIsShowConfirmModal(false);
+ throw Error("Cover image file is required");
+ }
+
+ if (!pmFeature) {
+ throw Error("Project manager feature not found");
+ }
+
+ const coverImg = projectFormData.coverImg;
+
+ // other party can't accept contract after duration expired
+ const expiryDuration = 24 * 60 * 60; // 1 day in seconds
+
+ const shortDescData: ProjectShortDescData = {
+ name: projectFormData.name,
+ desc: projectFormData.description,
+ coverImg,
+ tags: projectFormData.tags || "",
+ };
+
+ const teamAndLinkData: ProjectTeamAndLinkData = {
+ websiteLink: teamAndLinkFormData.websiteLink,
+ twitterProfile: teamAndLinkFormData.twitterProfile,
+ discordLink: teamAndLinkFormData.discordLink,
+ githubLink: teamAndLinkFormData.githubLink,
+ teamDesc: teamAndLinkFormData.teamDesc,
+ };
+
+ const metadata = JSON.stringify({
+ shortDescData,
+ teamAndLinkData,
+ });
+
+ const conflictHandler = projectFormData.arbitratorAddress;
+
+ let send = "";
+ // If creator = funder then we need to send all needed fund
+ if (projectFormData.creatorKind === "funder") {
+ send = totalFunding + pmFeature.paymentsDenom;
+ }
+
+ const contractor =
+ projectFormData.creatorKind === "contractor"
+ ? projectFormData.creatorAddress
+ : "";
+ const funder =
+ projectFormData.creatorKind === "funder"
+ ? projectFormData.creatorAddress
+ : "";
+
+ const args = [
+ contractor,
+ funder,
+ pmFeature.paymentsDenom,
+ metadata,
+ expiryDuration.toString(),
+ JSON.stringify(
+ milestones.map((ms) => {
+ const req: MilestoneRequest = {
+ title: ms.title,
+ desc: ms.desc,
+ duration: ms.duration.toString(),
+ amount: ms.amount.toString(),
+ link: ms.link || "",
+ priority: ms.priority,
+ };
+ return req;
+ }),
+ ),
+ conflictHandler,
+ ];
+ console.log("executing contract creation", args);
+
+ await execEscrowMethod("CreateContractJSON", args, send, 10_000_000);
+
+ await queryClient.invalidateQueries(["projects"]);
+
+ setIsShowConfirmModal(false);
+ setIsShowModal(true);
+ } catch (e) {
+ let msg = "";
+ if (e instanceof Error) {
+ msg = e.message;
+ } else {
+ msg = `${e}`;
+ }
+ setIsShowConfirmModal(false);
+ setToast({
+ title: "Error",
+ message: msg,
+ type: "error",
+ mode: "normal",
+ });
+ throw e;
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ const totalFunding = useMemo(() => {
+ return milestones.reduce((total, m) => total + +m.amount, 0).toString();
+ }, [milestones]);
+
+ return (
+
+
+
+ You’re making the signature to validate a transaction
+
+
+
+
+
+
+
+
+
+
+
+ {selectedNetwork?.displayName}
+
+
+
+ {tinyAddress(selectedWallet?.address, 16)}
+
+
+
+ {selectedWallet?.address && }
+
+
+
+
+
+
+ Funding
+
+
+
+ {prettyPrice(networkId, totalFunding, pmFeature?.paymentsDenom)}
+
+
+
+
+
+ Balance
+
+
+
+ {prettyPrice(networkId, bal?.amount, pmFeature?.paymentsDenom)}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setIsShowModal(false)}
+ label="Successful payment"
+ visible={isShowModal}
+ width={480}
+ >
+
+
+
+
+ You have successfully created Project: {projectFormData?.name}
+
+
+
+ {
+ setIsShowModal(false);
+ navigation.navigate("Projects", { network: networkId });
+ }}
+ />
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/Footer.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/Footer.tsx
new file mode 100644
index 0000000000..da53e6ceed
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/Footer.tsx
@@ -0,0 +1,49 @@
+import React from "react";
+import { View } from "react-native";
+
+import FlexRow from "../../../components/FlexRow";
+import { PrimaryButton } from "../../../components/buttons/PrimaryButton";
+import { SecondaryButton } from "../../../components/buttons/SecondaryButton";
+import { Separator } from "../../../components/separators/Separator";
+import { layout } from "../../../utils/style/layout";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+
+const DEFAULT_WIDTH = 120;
+
+export const MakeRequestFooter: React.FC<{
+ onSubmit: () => void;
+ disableNext: boolean;
+ nextText?: string;
+ backText?: string;
+ width?: number;
+}> = (props) => {
+ const {
+ actions: { goPrevStep },
+ } = useMakeRequestState();
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/Milestones.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/Milestones.tsx
new file mode 100644
index 0000000000..abfb82a4de
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/Milestones.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import { View } from "react-native";
+
+import { MakeRequestFooter } from "./Footer";
+import { neutral17 } from "../../../utils/style/colors";
+import { layout } from "../../../utils/style/layout";
+import { MilestoneBoard } from "../components/MilestoneBoard";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+import { previewMilestoneForm } from "../types";
+
+export const Milestones: React.FC = () => {
+ const {
+ milestones,
+ projectFormData: shortDescData,
+ actions: { goNextStep, setShortDesc },
+ } = useMakeRequestState();
+
+ const goToReview = () => {
+ setShortDesc(shortDescData);
+
+ goNextStep();
+ };
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/Preview.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/Preview.tsx
new file mode 100644
index 0000000000..5d42837f47
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/Preview.tsx
@@ -0,0 +1,68 @@
+import React from "react";
+import { View } from "react-native";
+
+import { MakeRequestFooter } from "./Footer";
+import { ProjectInfo } from "../components/ProjectInfo";
+import { ProjectMilestones } from "../components/ProjectMilestones";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+import { Project, previewMilestoneForm } from "../types";
+
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+
+export const Preview: React.FC = () => {
+ const {
+ projectFormData,
+ milestones,
+ teamAndLinkData,
+ actions: { goNextStep },
+ } = useMakeRequestState();
+
+ const selectedWallet = useSelectedWallet();
+
+ // Create project object just like when it returned from server
+ const project: Project = {
+ sender: selectedWallet?.address || "",
+ metadata: {
+ shortDescData: {
+ ...projectFormData,
+ coverImg: projectFormData.coverImg,
+ tags: projectFormData.tags || "",
+ },
+ teamAndLinkData,
+ },
+ budget: "",
+ funder: selectedWallet?.address || "",
+ contractor: "",
+ status: "CREATED",
+ id: "",
+ funded: false,
+ milestones: milestones.map(previewMilestoneForm),
+ contractorCandidates: [],
+ paymentDenom: "",
+ expireAt: new Date(),
+ funderFeedback: "",
+ contractorFeedback: "",
+ pausedBy: "",
+ conflictHandler: "",
+ handlerCandidate: "",
+ handlerSuggestor: "",
+ createdAt: new Date(),
+ rejectReason: "",
+ conflicts: [],
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/ShortPresentation.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/ShortPresentation.tsx
new file mode 100644
index 0000000000..ca8bdc18a6
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/ShortPresentation.tsx
@@ -0,0 +1,248 @@
+import { zodResolver } from "@hookform/resolvers/zod";
+import React, { useEffect, useState } from "react";
+import { useForm } from "react-hook-form";
+import { View } from "react-native";
+
+import { MakeRequestFooter } from "./Footer";
+import addSVG from "../../../../assets/icons/add.svg";
+import { BrandText } from "../../../components/BrandText";
+import { PrimaryButtonOutline } from "../../../components/buttons/PrimaryButtonOutline";
+import { FileUploader } from "../../../components/fileUploader";
+import { RoundedGradientImage } from "../../../components/images/RoundedGradientImage";
+import { TextInputCustom } from "../../../components/inputs/TextInputCustom";
+import { SpacerColumn } from "../../../components/spacer";
+import { useNameSearch } from "../../../hooks/search/useNameSearch";
+import { useSelectedNetworkId } from "../../../hooks/useSelectedNetwork";
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { IMAGE_MIME_TYPES } from "../../../utils/mime";
+import { errorColor, neutral77, neutralA3 } from "../../../utils/style/colors";
+import { fontSemibold14, fontSemibold20 } from "../../../utils/style/fonts";
+import { TNSResult } from "../components/TNSResult";
+import {
+ useMakeRequestState,
+ zodProjectFormData,
+} from "../hooks/useMakeRequestHook";
+
+import { LoaderFullScreen } from "@/components/loaders/LoaderFullScreen";
+import { useIpfs } from "@/hooks/useIpfs";
+import { ButtonsGroup } from "@/screens/Projects/components/ButtonsGroup";
+
+export const ShortPresentation: React.FC = () => {
+ const {
+ actions: { goNextStep, setShortDesc },
+ projectFormData: shortDescData,
+ } = useMakeRequestState();
+ const selectedWallet = useSelectedWallet();
+ const caller = selectedWallet?.address;
+ const selectedNetworkId = useSelectedNetworkId();
+ const [searchTNSText, setSearchTNSText] = useState("");
+ const [isTNSVisible, setIsTNSVisible] = useState(false);
+ const { handleSubmit, formState, setValue, watch, setError } = useForm({
+ resolver: zodResolver(zodProjectFormData),
+ defaultValues: shortDescData,
+ });
+ const { errors } = formState;
+ const values = watch();
+ const { uploadToIPFS } = useIpfs();
+ const [isUploadingCover, setIsUploadingCover] = useState(false);
+ useEffect(() => {
+ if (!caller) {
+ // TODO: would be better to not allow this corner case, aka do something smarter when no wallet is connected
+ return;
+ }
+ setValue("creatorAddress", caller);
+ }, [setValue, caller]);
+
+ const { names } = useNameSearch({
+ networkId: selectedNetworkId,
+ input: searchTNSText,
+ limit: 12,
+ });
+
+ if (!caller) {
+ return null;
+ }
+
+ return (
+
+
+
+ Grant details
+
+
+
+
+ Information about your Grant
+
+
+
+
+
+
+ I'm *
+
+
+
+
+ {
+ if (selectedId === 0) {
+ setValue("creatorKind", "contractor");
+ } else {
+ setValue("creatorKind", "funder");
+ }
+ }}
+ />
+
+
+
+
+
+ {
+ setSearchTNSText(text);
+ setIsTNSVisible(true);
+ setValue("targetAddress", text);
+ }}
+ value={values.targetAddress}
+ error={errors.targetAddress?.message}
+ />
+
+ 0}
+ networkId={selectedNetworkId}
+ names={names}
+ onSelected={(name) => {
+ setIsTNSVisible(false);
+ setValue("targetAddress", name);
+ }}
+ />
+
+
+
+
+ setValue("name", val)}
+ value={values.name}
+ error={errors.name?.message}
+ />
+
+
+
+ setValue("description", val)}
+ value={values.description}
+ error={errors.description?.message}
+ />
+
+
+
+ setValue("arbitratorAddress", val)}
+ value={values.arbitratorAddress}
+ />
+
+
+
+
+ Cover Image *
+
+
+
+
+ {
+ setIsUploadingCover(true);
+ try {
+ if (files[0].fileType !== "image") {
+ setError("coverImg", { message: "file is not an image" });
+ return;
+ }
+ const web3URI = await uploadToIPFS(selectedWallet.userId, files[0]);
+ setValue("coverImg", web3URI);
+ } finally {
+ setIsUploadingCover(false);
+ }
+ }}
+ mimeTypes={IMAGE_MIME_TYPES}
+ >
+ {({ onPress }) => (
+
+ )}
+
+
+
+
+ {!!errors.coverImg && (
+
+ {errors.coverImg.message}
+
+ )}
+
+
+ {!!values.coverImg && (
+
+ )}
+
+
+
+
+ setValue("tags", val)}
+ value={values.tags || ""}
+ error={errors.tags?.message}
+ />
+
+ {
+ setShortDesc(submitValues);
+ goNextStep();
+ })}
+ />
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/TeamAndLinks.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/TeamAndLinks.tsx
new file mode 100644
index 0000000000..70813838fe
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/TeamAndLinks.tsx
@@ -0,0 +1,159 @@
+import { zodResolver } from "@hookform/resolvers/zod";
+import React from "react";
+import { useForm } from "react-hook-form";
+import { View } from "react-native";
+
+import { MakeRequestFooter } from "./Footer";
+import { BrandText } from "../../../components/BrandText";
+import { TextInputCustom } from "../../../components/inputs/TextInputCustom";
+import { Separator } from "../../../components/separators/Separator";
+import { SpacerColumn } from "../../../components/spacer";
+import { neutral55, neutral77, neutralA3 } from "../../../utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold20,
+} from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import {
+ useMakeRequestState,
+ zodProjectTeamAndLinkFormData,
+} from "../hooks/useMakeRequestHook";
+
+export const TeamAndLinks: React.FC = () => {
+ const {
+ actions: { goNextStep, setTeamAndLink },
+ teamAndLinkData,
+ } = useMakeRequestState();
+
+ const { handleSubmit, formState, setValue, watch } = useForm({
+ resolver: zodResolver(zodProjectTeamAndLinkFormData),
+ defaultValues: teamAndLinkData,
+ });
+
+ const { errors } = formState;
+ const values = watch();
+
+ const submit = handleSubmit((values) => {
+ setTeamAndLink(values);
+ goNextStep();
+ });
+
+ return (
+
+ Links
+
+
+
+
+ Your Grant useful links
+
+
+
+
+ setValue("websiteLink", val)}
+ value={values.websiteLink}
+ error={errors.websiteLink?.message}
+ />
+
+
+
+ setValue("twitterProfile", val)}
+ value={values.twitterProfile}
+ error={errors.twitterProfile?.message}
+ />
+
+
+
+ setValue("discordLink", val)}
+ value={values.discordLink}
+ error={errors.discordLink?.message}
+ />
+
+
+
+ setValue("githubLink", val)}
+ value={values.githubLink}
+ error={errors.githubLink?.message}
+ />
+
+
+
+ Links
+
+
+
+
+ Your Grant useful links
+
+
+
+
+
+ Describe your team: *
+
+
+
+ 1. How many core members are you? ( Working on the project daily )
+
+
+ 2. Past accomplishments or projects?
+
+
+ 3. Please add all relevant links for all your members.
+
+
+
+
+ setValue("teamDesc", val)}
+ value={values.teamDesc}
+ error={errors.teamDesc?.message}
+ />
+
+
+
+
+ Team links and attachments
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsMakeRequestScreen/index.tsx b/packages/screens/Projects/ProjectsMakeRequestScreen/index.tsx
new file mode 100644
index 0000000000..9df7b905c8
--- /dev/null
+++ b/packages/screens/Projects/ProjectsMakeRequestScreen/index.tsx
@@ -0,0 +1,45 @@
+import React from "react";
+import { View } from "react-native";
+
+import { ConfirmAndSign } from "./ConfirmAndSign";
+import { Milestones } from "./Milestones";
+import { Preview } from "./Preview";
+import { ShortPresentation } from "./ShortPresentation";
+import { TeamAndLinks } from "./TeamAndLinks";
+import { ScreenContainer } from "../../../components/ScreenContainer";
+import { SpacerColumn } from "../../../components/spacer";
+import { NetworkKind } from "../../../networks";
+import { ScreenFC } from "../../../utils/navigation";
+import { Breadcrumb } from "../components/Breadcrumb";
+import { HeaderBackButton } from "../components/HeaderBackButton";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+
+const renderStep = (stepIndice: number) => {
+ if (stepIndice === 1) return ;
+ if (stepIndice === 2) return ;
+ if (stepIndice === 3) return ;
+ if (stepIndice === 4) return ;
+ if (stepIndice === 5) return ;
+};
+
+export const ProjectsMakeRequestScreen: ScreenFC<
+ "ProjectsMakeRequest"
+> = () => {
+ const { stepIndice } = useMakeRequestState();
+
+ return (
+ }
+ >
+
+
+
+
+ {/* Main view============================================================ */}
+ {renderStep(stepIndice)}
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/ContractorCandidates.tsx b/packages/screens/Projects/ProjectsManagerScreen/ContractorCandidates.tsx
new file mode 100644
index 0000000000..9bdbea2edc
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/ContractorCandidates.tsx
@@ -0,0 +1,177 @@
+import { useQueryClient } from "@tanstack/react-query";
+import React, { useState } from "react";
+import { TouchableOpacity, View } from "react-native";
+
+import FlexRow from "../../../components/FlexRow";
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { ProjectStatusTag } from "../components/ProjectStatusTag";
+import { useProjects } from "../hooks/useProjects";
+import { Project } from "../types";
+
+import { BrandText } from "@/components/BrandText";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { RoundedGradientImage } from "@/components/images/RoundedGradientImage";
+import { TableCell } from "@/components/table/TableCell";
+import { TableHeader } from "@/components/table/TableHeader";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import {
+ getNetworkObjectId,
+ getUserId,
+ parseNetworkObjectId,
+} from "@/networks";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { useAppNavigation } from "@/utils/navigation";
+import { neutral33, neutralFF } from "@/utils/style/colors";
+import { fontSemibold13 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const ContractorCandidates: React.FC<{ networkId: string }> = ({
+ networkId,
+}) => {
+ const selectedWallet = useSelectedWallet();
+
+ const { projects } = useProjects(networkId, {
+ byCandidatesForFunder: { funder: selectedWallet?.address || "" },
+ });
+
+ return (
+
+
+ {projects.map((project) => (
+
+ ))}
+
+ );
+};
+
+const TABLE_COLS = {
+ name: {
+ label: "Project name",
+ flex: 3,
+ },
+ status: {
+ label: "Status",
+ flex: 1,
+ },
+ candidates: {
+ label: "Candidates",
+ flex: 3,
+ },
+};
+
+const ProjectRow: React.FC<{ networkId: string; project: Project }> = ({
+ networkId,
+ project,
+}) => {
+ const navigation = useAppNavigation();
+
+ if (!project.contractorCandidates.length) return null;
+
+ return (
+
+ {/* === Name === */}
+
+
+
+ {
+ if (!project.id) {
+ return;
+ }
+ navigation.navigate("ProjectsDetail", { id: project.id });
+ }}
+ >
+
+ {project.metadata?.shortDescData?.name}
+
+
+
+
+ {/* === Status === */}
+
+
+
+
+
+
+ {[
+ project.contractorCandidates,
+ // project.contractorCandidates,
+ // project.contractorCandidates,
+ ]
+ .flatMap((c) => c)
+ .map((c, idx) => (
+
+ ))}
+
+
+
+ );
+};
+
+type CandidateProps = {
+ projectId: string;
+ candidate: string;
+};
+
+const Candidate: React.FC = ({ projectId, candidate }) => {
+ const [network, localProjectId] = parseNetworkObjectId(projectId);
+ const networkId = network?.id;
+
+ const selectedWallet = useSelectedWallet();
+
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const queryClient = useQueryClient();
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+
+ const acceptCandidate = async () => {
+ setIsProcessing(true);
+ await execEscrowMethod("AcceptContractor", [localProjectId, candidate]);
+ await Promise.all([
+ queryClient.invalidateQueries(["project", projectId]),
+ queryClient.invalidateQueries(["projects", networkId]),
+ ]);
+ setIsProcessing(false);
+ };
+
+ return (
+
+
+ acceptCandidate()}
+ />
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/MilestonesUpdateManager.tsx b/packages/screens/Projects/ProjectsManagerScreen/MilestonesUpdateManager.tsx
new file mode 100644
index 0000000000..1e3cc1d9c7
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/MilestonesUpdateManager.tsx
@@ -0,0 +1,181 @@
+import React from "react";
+import { View } from "react-native";
+import { TouchableOpacity } from "react-native-gesture-handler";
+
+import githubSVG from "../../../../assets/icons/github.svg";
+import FlexRow from "../../../components/FlexRow";
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { MilestonePriorityTag } from "../components/MilestonePriorityTag";
+import { MilestoneStatusTag } from "../components/MilestoneStatusTag";
+import { useProjects } from "../hooks/useProjects";
+import { ProjectMilestone } from "../types";
+
+import { BrandText } from "@/components/BrandText";
+import { Link } from "@/components/Link";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { SocialButton } from "@/components/buttons/SocialButton";
+import { Separator } from "@/components/separators/Separator";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { getNetworkObjectId } from "@/networks";
+import { useAppNavigation } from "@/utils/navigation";
+import {
+ neutral00,
+ neutral17,
+ neutral77,
+ neutralA3,
+ neutralFF,
+} from "@/utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold16,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const MilestonesUpdateManager: React.FC = () => {
+ const navigation = useAppNavigation();
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+
+ // TODO: Support to default limit projects for now, make this more dynamic latter
+ const { projects, isLoading } = useProjects(networkId, {
+ byFunder: { funder: selectedWallet?.address || "" },
+ });
+
+ if (isLoading || !selectedWallet?.address) return null;
+
+ return (
+ <>
+ {projects.map((project) =>
+ (project.milestones || [])
+ .filter((m) => m.status === "MS_REVIEW")
+ .map((milestone: ProjectMilestone, milestoneIdx: number) => {
+ return (
+ <>
+
+ Project: {project.metadata?.shortDescData?.name}
+
+
+
+
+
+ {project.metadata?.shortDescData?.name}
+
+
+
+ {milestone.title}
+
+
+
+
+
+
+
+ Builder: @{project.contractor}
+
+
+
+ Funder: @{project.funder}
+
+
+
+
+
+
+
+ Status
+
+
+
+
+
+
+
+
+
+ Priority
+
+
+
+
+
+
+
+
+
+
+
+ {
+ if (!project.id) return;
+ navigation.navigate("ProjectsCompleteMilestone", {
+ projectId: getNetworkObjectId(networkId, project.id),
+ milestoneId: milestone.id,
+ });
+ }}
+ >
+
+ Approve
+
+
+
+
+ >
+ );
+ }),
+ )}
+ >
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/MyProjectsManager.tsx b/packages/screens/Projects/ProjectsManagerScreen/MyProjectsManager.tsx
new file mode 100644
index 0000000000..512c1a0eb3
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/MyProjectsManager.tsx
@@ -0,0 +1,190 @@
+import moment from "moment";
+import React, { useMemo, useState } from "react";
+import { TouchableOpacity, View } from "react-native";
+
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { ProjectStatusTag } from "../components/ProjectStatusTag";
+import { ProjectsStatusFilterButtons } from "../components/ProjectsStatusFilterButtons";
+import { ProjectFilter, useProjects } from "../hooks/useProjects";
+import { ContractStatusFilter, Project } from "../types";
+import { getProjectStats } from "../utils";
+
+import { BrandText } from "@/components/BrandText";
+import { ProgressLine } from "@/components/ProgressLine";
+import { RoundedGradientImage } from "@/components/images/RoundedGradientImage";
+import { SpacerColumn } from "@/components/spacer";
+import { TableCell } from "@/components/table/TableCell";
+import { TableHeader } from "@/components/table/TableHeader";
+import { TableRow } from "@/components/table/TableRow";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { getNetworkObjectId, getUserId } from "@/networks";
+import { prettyPrice } from "@/utils/coins";
+import { useAppNavigation } from "@/utils/navigation";
+import { neutralFF } from "@/utils/style/colors";
+import { fontSemibold13 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+export const MyProjectsManager: React.FC<{
+ type: ProjectType;
+}> = ({ type }) => {
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+
+ let filter: ProjectFilter;
+ switch (type) {
+ case "myInvestments": {
+ filter = { byFunder: { funder: selectedWallet?.address || "" } };
+ break;
+ }
+ case "myProjects": {
+ filter = { byContractor: { contractor: selectedWallet?.address || "" } };
+ }
+ }
+ const { projects } = useProjects(networkId, filter);
+
+ const [statusFilter, setStatusFilter] = useState("ALL");
+
+ const filteredProjects = useMemo(() => {
+ if (!selectedWallet?.address) return [];
+
+ return projects.filter(
+ (p) => statusFilter === "ALL" || p.status === statusFilter,
+ );
+ }, [projects, statusFilter, selectedWallet?.address]);
+
+ return (
+
+
+
+
+
+
+ {filteredProjects.map((project) => (
+
+ ))}
+
+ );
+};
+
+const getTableCols = (projectType: ProjectType) => {
+ return {
+ name: {
+ label: "Project name",
+ flex: 2.5,
+ },
+ status: {
+ label: "Status",
+ flex: 1,
+ },
+ manager: {
+ label: projectType === "myProjects" ? "Funder" : "Contractor",
+ flex: 2.5,
+ },
+ milestones: {
+ label: "Milestones",
+ flex: 2,
+ },
+ grant: {
+ label: "Grant",
+ flex: 2,
+ },
+ creationDate: {
+ label: "Creation date",
+ flex: 1,
+ },
+ };
+};
+
+const defaultCols = getTableCols("myProjects");
+
+type ProjectType = "myInvestments" | "myProjects";
+
+const ProjectRow: React.FC<{ project: Project; projectType: ProjectType }> = ({
+ project,
+ projectType,
+}) => {
+ const stats = getProjectStats(project);
+ const navigation = useAppNavigation();
+ const networkId = useSelectedNetworkId();
+
+ return (
+
+ {/* === Name === */}
+
+
+
+ {
+ if (!project.id) {
+ return;
+ }
+ navigation.navigate("ProjectsDetail", {
+ id: getNetworkObjectId(networkId, project.id),
+ });
+ }}
+ >
+
+ {project.metadata?.shortDescData?.name}
+
+
+
+
+ {/* === Status === */}
+
+
+
+
+ {/* === Manager === */}
+
+ {projectType === "myProjects" && (
+
+ )}
+ {projectType === "myInvestments" && (
+
+ )}
+
+
+ {/* === Milestones === */}
+
+
+ {stats.completed}/{stats.total}
+
+
+
+
+ {/* === Grant === */}
+
+
+ {prettyPrice(networkId, project.budget, project.paymentDenom)}
+
+
+
+ {/* === Creation date === */}
+
+
+ {moment(project.createdAt).format("L")}
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/Requests.tsx b/packages/screens/Projects/ProjectsManagerScreen/Requests.tsx
new file mode 100644
index 0000000000..4ad1cdb183
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/Requests.tsx
@@ -0,0 +1,342 @@
+import { Link } from "@react-navigation/native";
+import React, { useState } from "react";
+import { View } from "react-native";
+
+import githubSVG from "../../../../assets/icons/github.svg";
+import FlexRow from "../../../components/FlexRow";
+import ModalBase from "../../../components/modals/ModalBase";
+import useSelectedWallet from "../../../hooks/useSelectedWallet";
+import { ProjectStatusTag } from "../components/ProjectStatusTag";
+import { ProjectFilter, useProjects } from "../hooks/useProjects";
+import { Project } from "../types";
+
+import { BrandText } from "@/components/BrandText";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { PrimaryButtonOutline } from "@/components/buttons/PrimaryButtonOutline";
+import { SocialButton } from "@/components/buttons/SocialButton";
+import { TextInputCustom } from "@/components/inputs/TextInputCustom";
+import { Separator } from "@/components/separators/Separator";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { getUserId } from "@/networks";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { useUtils } from "@/screens/Projects/hooks/useUtils";
+import { prettyPrice } from "@/utils/coins";
+import { useAppNavigation } from "@/utils/navigation";
+import {
+ neutral17,
+ neutralA3,
+ primaryColor,
+ redDefault,
+} from "@/utils/style/colors";
+import { fontSemibold13, fontSemibold14 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+type RequestType = "requestsByBuilders" | "requestsByInvestors";
+
+const Spacing = () => {
+ return (
+
+ );
+};
+
+const RequestItem: React.FC<{
+ project: Project & { contractorCandidate?: string };
+ networkId: string;
+ walletAddress: string;
+ requestType: RequestType;
+}> = ({ project, networkId, walletAddress, requestType }) => {
+ const navigation = useAppNavigation();
+
+ const [isProcessing, setIsProcessing] = useState(false);
+ const [isShowModal, setIsShowModal] = useState(false);
+ const [rejectReason, setRejectReason] = useState("");
+ const { mustGetValue } = useUtils();
+
+ const { execEscrowMethod } = useEscrowContract(networkId, walletAddress);
+
+ const githubLink = project.metadata?.teamAndLinkData?.githubLink;
+
+ const gotoProjectDetail = (project: Project) => {
+ if (!project.id) {
+ return;
+ }
+ navigation.navigate("ProjectsDetail", { id: project.id });
+ };
+
+ const acceptContractor = async () => {
+ setIsProcessing(true);
+
+ const candidate = mustGetValue(
+ project.contractorCandidate,
+ "contractor candidate",
+ );
+
+ await execEscrowMethod("AcceptContractor", [
+ project?.id?.toString(),
+ candidate,
+ ]);
+
+ setIsProcessing(false);
+ };
+
+ const acceptContract = async (project: Project) => {
+ setIsProcessing(true);
+ await execEscrowMethod("AcceptContract", [project?.id?.toString()]);
+ setIsProcessing(false);
+ };
+
+ const rejectContract = async (project: Project, rejectReason: string) => {
+ setIsProcessing(true);
+ await execEscrowMethod("RejectContract", [
+ project?.id?.toString(),
+ rejectReason,
+ ]);
+ setIsProcessing(false);
+ };
+
+ return (
+ <>
+
+
+
+ gotoProjectDetail(project)}
+ style={fontSemibold14}
+ >
+ {project.metadata?.shortDescData?.name}
+
+
+ gotoProjectDetail(project)}
+ style={[fontSemibold14, { color: neutralA3 }]}
+ >
+ {project.metadata?.shortDescData?.desc}
+
+
+
+
+
+
+
+ Grant
+
+
+
+ {prettyPrice(networkId, project.budget, project.paymentDenom)}
+
+
+
+
+
+
+ {requestType === "requestsByBuilders" && (
+
+ )}
+ {requestType === "requestsByInvestors" && (
+
+ Investor{" "}
+
+ )}
+
+
+ {requestType === "requestsByBuilders" && project.contractor}
+ {requestType === "requestsByInvestors" && project.funder}
+
+
+
+
+
+
+
+ Milestones
+
+
+
+ {project.milestones.length}
+
+
+
+
+
+
+
+
+
+ {githubLink && (
+ <>
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ {project.status === "CREATED" && (
+ <>
+ setIsShowModal(true)}
+ />
+
+ acceptContract(project)
+ }
+ />
+ >
+ )}
+
+ {project.status === "REJECTED" && (
+
+ {project.rejectReason}
+
+ )}
+
+
+
+
+ setIsShowModal(false)}
+ label="Reason for rejection"
+ visible={isShowModal}
+ width={480}
+ >
+
+
+ rejectContract(project, rejectReason)}
+ />
+
+ >
+ );
+};
+
+export const Requests: React.FC<{
+ type: RequestType;
+}> = ({ type }) => {
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+
+ // FIXME: add new filters
+
+ let filter: ProjectFilter;
+ switch (type) {
+ case "requestsByBuilders": {
+ filter = { byFunder: { funder: selectedWallet?.address || "" } };
+ break;
+ }
+ case "requestsByInvestors": {
+ filter = { byContractor: { contractor: selectedWallet?.address || "" } };
+ }
+ }
+
+ const { projects } = useProjects(networkId, filter);
+
+ if (!selectedWallet?.address) {
+ return null;
+ }
+
+ let adjustedProjects: (Project & { contractorCandidate?: string })[] =
+ type === "requestsByBuilders"
+ ? projects.filter((p) => p.sender === p.funder)
+ : projects.filter((p) => p.sender === p.contractor);
+
+ if (type === "requestsByBuilders") {
+ // expand by contractor
+ adjustedProjects = adjustedProjects.reduce(
+ (acc, p) => {
+ if (!p.contractorCandidates) {
+ return acc;
+ }
+ const newProjects = p.contractorCandidates.map((c) => ({
+ ...p,
+ contractorCandidate: c,
+ }));
+ return [...acc, ...newProjects];
+ },
+ [] as (Project & { contractorCandidate?: string })[],
+ );
+ }
+
+ return (
+ <>
+ {adjustedProjects.map((project) => {
+ return (
+
+ );
+ })}
+ >
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/index.tsx b/packages/screens/Projects/ProjectsManagerScreen/index.tsx
new file mode 100644
index 0000000000..7b85067699
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/index.tsx
@@ -0,0 +1,99 @@
+import React, { useMemo } from "react";
+import { View } from "react-native";
+
+import { MilestonesUpdateManager } from "./MilestonesUpdateManager";
+import { MyProjectsManager } from "./MyProjectsManager";
+import { Requests } from "./Requests";
+import { TabOption, ViewKey } from "./types";
+import { HeaderBackButton } from "../components/HeaderBackButton";
+
+import { BrandText } from "@/components/BrandText";
+import { FlexRow } from "@/components/FlexRow";
+import { ScreenContainer } from "@/components/ScreenContainer";
+import { Tabs } from "@/components/tabs/Tabs";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { NetworkKind } from "@/networks";
+import { ContractorCandidates } from "@/screens/Projects/ProjectsManagerScreen/ContractorCandidates";
+import { ScreenFC, useAppNavigation } from "@/utils/navigation";
+import { neutral33 } from "@/utils/style/colors";
+import { fontSemibold14, fontSemibold28 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { arrayIncludes, objectKeys } from "@/utils/typescript";
+
+export const ProjectsManagerScreen: ScreenFC<"ProjectsManager"> = ({
+ route: { params },
+}) => {
+ const networkId = useSelectedNetworkId();
+ const navigation = useAppNavigation();
+ const viewFromParams = params.view;
+
+ const { tabOptions, managerTypes } = useMemo(() => {
+ const tabOptions: TabOption = {
+ myInvestments: {
+ name: "My investments",
+ component: ,
+ },
+ myProjects: {
+ name: "My projects",
+ component: ,
+ },
+ milestonesUpdates: {
+ name: "Reviews",
+ component: ,
+ },
+ requestsByBuilders: {
+ name: "Contractor candidates",
+ component: ,
+ },
+ requestsByInvestors: {
+ name: "Requests by investors",
+ component: ,
+ },
+ };
+ return { tabOptions, managerTypes: objectKeys(tabOptions) };
+ }, [networkId]);
+
+ const view: ViewKey = useMemo(() => {
+ return arrayIncludes(managerTypes, viewFromParams)
+ ? viewFromParams
+ : "myInvestments";
+ }, [managerTypes, viewFromParams]);
+
+ return (
+ }
+ >
+
+ {tabOptions[view].name}
+
+
+ navigation.navigate("ProjectsManager", { view: tab })
+ }
+ tabTextStyle={fontSemibold14}
+ />
+
+
+
+ {tabOptions[view].component}
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsManagerScreen/types.ts b/packages/screens/Projects/ProjectsManagerScreen/types.ts
new file mode 100644
index 0000000000..07496ffb40
--- /dev/null
+++ b/packages/screens/Projects/ProjectsManagerScreen/types.ts
@@ -0,0 +1,17 @@
+import React from "react";
+
+export type ViewKey =
+ | "myInvestments"
+ | "myProjects"
+ | "milestonesUpdates"
+ | "requestsByBuilders"
+ | "requestsByInvestors";
+
+type ViewData = {
+ name: string;
+ component: React.ReactNode;
+};
+
+export type TabOption = {
+ [key in ViewKey]: ViewData;
+};
diff --git a/packages/screens/Projects/ProjectsPaymentScreen.tsx b/packages/screens/Projects/ProjectsPaymentScreen.tsx
new file mode 100644
index 0000000000..6d73bffff8
--- /dev/null
+++ b/packages/screens/Projects/ProjectsPaymentScreen.tsx
@@ -0,0 +1,248 @@
+import moment from "moment";
+import React, { useState } from "react";
+import { View } from "react-native";
+import { SvgProps } from "react-native-svg";
+
+import { HeaderBackButton } from "./components/HeaderBackButton";
+import { Tag } from "./components/Milestone";
+import { useProject } from "./hooks/useProjects";
+import discordSVG from "../../../assets/icons/discord.svg";
+import githubSVG from "../../../assets/icons/github.svg";
+import twitterSVG from "../../../assets/icons/twitter.svg";
+import websiteSVG from "../../../assets/icons/website.svg";
+import { BrandText } from "../../components/BrandText";
+import FlexRow from "../../components/FlexRow";
+import { ScreenContainer } from "../../components/ScreenContainer";
+import { TertiaryBox } from "../../components/boxes/TertiaryBox";
+import { PrimaryButton } from "../../components/buttons/PrimaryButton";
+import { PrimaryButtonOutline } from "../../components/buttons/PrimaryButtonOutline";
+import { SocialButton } from "../../components/buttons/SocialButton";
+import { RoundedGradientImage } from "../../components/images/RoundedGradientImage";
+import { TextInputCustom } from "../../components/inputs/TextInputCustom";
+import { Separator } from "../../components/separators/Separator";
+import { SpacerColumn, SpacerRow } from "../../components/spacer";
+import { ScreenFC } from "../../utils/navigation";
+import {
+ neutral17,
+ neutral77,
+ neutralA3,
+ neutralFF,
+ primaryColor,
+ redDefault,
+} from "../../utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold20,
+ fontSemibold28,
+} from "../../utils/style/fonts";
+import { layout } from "../../utils/style/layout";
+
+const CustomSocialButton: React.FC<{
+ text: string;
+ iconSvg: React.FC;
+}> = ({ text, iconSvg }) => {
+ return (
+
+ );
+};
+
+export const ProjectsPaymentScreen: ScreenFC<"ProjectsPayment"> = ({
+ route: { params },
+}) => {
+ const { projectId, milestoneId } = params;
+
+ const { data: project } = useProject(projectId);
+ const milestone = (project?.milestones || []).find(
+ (_, idx) => idx === +milestoneId,
+ );
+
+ const [report, setReport] = useState("");
+
+ if (!milestone) return null;
+
+ return (
+ }>
+
+
+
+ {milestone.title}
+
+
+
+
+
+ {/* Left Col ==========================================================*/}
+
+
+
+ {milestone.title}
+
+
+
+
+
+ {project?.metadata?.shortDescData?.desc}
+
+
+
+
+
+
+
+
+ Tags:
+
+
+ {project?.metadata?.shortDescData?.tags?.split(",").map((tag) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+
+
+ Report input:
+
+
+
+
+ setReport(text)}
+ label=""
+ name="name"
+ placeholder="Enter details here..."
+ hideLabel
+ multiline
+ noBrokenCorners
+ containerStyle={{ width: "100%" }}
+ textInputStyle={{ height: 80 }}
+ />
+
+
+
+
+
+
+
+
+
+ {/* Right Col =========================================================*/}
+
+
+
+ Grant
+
+
+ $50K
+
+
+
+
+
+
+ Status
+
+
+
+
+
+
+
+
+ Created by:
+
+
+
+ @0x17dfsdvgsd98fsbsd9b8sd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/ProjectsScreen.tsx b/packages/screens/Projects/ProjectsScreen.tsx
new file mode 100644
index 0000000000..a7ee5af32b
--- /dev/null
+++ b/packages/screens/Projects/ProjectsScreen.tsx
@@ -0,0 +1,104 @@
+import React, { useState } from "react";
+import { View } from "react-native";
+
+import { ProjectBox } from "./components/ProjectBox";
+import { ProjectsStatusFilterButtons } from "./components/ProjectsStatusFilterButtons";
+import { useProjects } from "./hooks/useProjects";
+import { ContractStatusFilter } from "./types";
+import { BrandText } from "../../components/BrandText";
+import { FlexRow } from "../../components/FlexRow";
+import { ScreenContainer } from "../../components/ScreenContainer";
+import { SimpleButton } from "../../components/buttons/SimpleButton";
+import { Separator } from "../../components/separators/Separator";
+import { SpacerColumn, SpacerRow } from "../../components/spacer";
+import { useSelectedNetworkId } from "../../hooks/useSelectedNetwork";
+import { NetworkKind, getNetwork } from "../../networks";
+import { ScreenFC, useAppNavigation } from "../../utils/navigation";
+import { primaryColor, secondaryColor } from "../../utils/style/colors";
+import { fontSemibold20, fontSemibold28 } from "../../utils/style/fonts";
+import { layout } from "../../utils/style/layout";
+
+import { GridList } from "@/components/layout/GridList";
+import { useForceNetworkSelection } from "@/hooks/useForceNetworkSelection";
+import { joinElements } from "@/utils/react";
+
+export const ProjectsScreen: ScreenFC<"Projects"> = ({ route: { params } }) => {
+ const network = params?.network;
+ useForceNetworkSelection(network);
+ const networkId = useSelectedNetworkId();
+ const inputNetwork = getNetwork(network);
+ const { projects, fetchNextPage } = useProjects(networkId);
+
+ const navigation = useAppNavigation();
+
+ const gotoProjectsManager = () => {
+ navigation.navigate("ProjectsManager", { view: "myInvestments" });
+ };
+
+ const gotoCreateGrant = () => {
+ navigation.navigate("ProjectsMakeRequest", { step: 1 });
+ };
+
+ const [statusFilter, setStatusFilter] = useState("ALL");
+
+ const topRightElems = [
+ ,
+ ,
+ ];
+
+ return (
+ >}
+ headerChildren={Projects}
+ >
+
+
+
+ Projects
+
+ {joinElements(topRightElems, )}
+
+
+
+
+
+ >
+ }
+ ListFooterComponent={}
+ data={projects}
+ keyExtractor={(project) => project.id}
+ minElemWidth={400}
+ onEndReached={() => fetchNextPage()}
+ renderItem={({ item: project }, elemWidth) => {
+ return (
+
+ );
+ }}
+ />
+
+ );
+};
diff --git a/packages/screens/Projects/components/Breadcrumb.tsx b/packages/screens/Projects/components/Breadcrumb.tsx
new file mode 100644
index 0000000000..bb6e7ec02b
--- /dev/null
+++ b/packages/screens/Projects/components/Breadcrumb.tsx
@@ -0,0 +1,132 @@
+import React, { Fragment } from "react";
+import { StyleProp, ViewStyle } from "react-native";
+
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { TertiaryBox } from "../../../components/boxes/TertiaryBox";
+import {
+ neutral00,
+ neutral17,
+ neutral22,
+ neutral77,
+ neutralFF,
+ primaryColor,
+} from "../../../utils/style/colors";
+import { fontSemibold14, fontSemibold16 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+
+const Step: React.FC<{
+ indice: number;
+ text: string;
+ active?: boolean;
+ disabled?: boolean;
+ onPress: (step: number) => void;
+}> = ({ indice, text, active, disabled, onPress }) => {
+ return (
+
+ onPress(indice)}
+ style={[
+ fontSemibold14,
+ {
+ color: disabled ? neutral77 : neutral00,
+ backgroundColor: active
+ ? primaryColor
+ : disabled
+ ? neutral22
+ : neutralFF,
+ borderRadius: 100,
+ width: 32,
+ height: 32,
+ justifyContent: "center",
+ alignItems: "center",
+ display: "flex",
+ marginRight: layout.spacing_x2,
+ },
+ ]}
+ >
+ {indice}
+
+
+ onPress(indice)}
+ numberOfLines={1}
+ style={[
+ fontSemibold14,
+ {
+ color: active ? primaryColor : disabled ? neutral77 : neutralFF,
+ },
+ ]}
+ >
+ {text}
+
+
+ );
+};
+
+const Seperator = () => {
+ return (
+
+ {">"}
+
+ );
+};
+
+const STEPS = [
+ "Short presentation",
+ "Team and links",
+ "Milestones",
+ "Preview",
+ "Confirm and Sign",
+];
+
+export const Breadcrumb: React.FC<{
+ stepIndice?: number;
+ containerStyle?: StyleProp;
+}> = ({ stepIndice = 1, containerStyle }) => {
+ const {
+ stepIndice: currentStepIndice,
+ actions: { gotoStep },
+ } = useMakeRequestState();
+
+ // We can only goto passed steps
+ const gotoValidStep = (targetStepIndice: number) => {
+ if (targetStepIndice <= currentStepIndice) {
+ gotoStep(targetStepIndice);
+ }
+ };
+
+ return (
+
+
+ {STEPS.map((step, idx) => {
+ return (
+
+
+ {idx + 1 < STEPS.length && }
+
+ );
+ })}
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/ButtonsGroup.tsx b/packages/screens/Projects/components/ButtonsGroup.tsx
new file mode 100644
index 0000000000..2e5243f040
--- /dev/null
+++ b/packages/screens/Projects/components/ButtonsGroup.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import { View } from "react-native";
+
+import { SimpleButton } from "@/components/buttons/SimpleButton";
+import {
+ neutral00,
+ neutral33,
+ primaryColor,
+ secondaryColor,
+} from "@/utils/style/colors";
+import { layout } from "@/utils/style/layout";
+
+type ButtonsGroupType = {
+ texts: string[];
+ selectedId: number;
+ onChange?: (selectedId: number) => void;
+ size?: "XS" | "SM" | "M" | "XL";
+};
+
+export const ButtonsGroup: React.FC = ({
+ texts,
+ selectedId,
+ onChange,
+ size = "M",
+}) => {
+ return (
+
+ {texts.map((text, btnId) => {
+ return (
+ onChange?.(btnId)}
+ />
+ );
+ })}
+
+ );
+};
diff --git a/packages/screens/Projects/components/FundProjectModal.tsx b/packages/screens/Projects/components/FundProjectModal.tsx
new file mode 100644
index 0000000000..b83eddfd28
--- /dev/null
+++ b/packages/screens/Projects/components/FundProjectModal.tsx
@@ -0,0 +1,184 @@
+import { useQueryClient } from "@tanstack/react-query";
+import React, { useMemo, useState } from "react";
+import { View } from "react-native";
+
+import gnoSVG from "@/assets/icons/networks/gno.svg";
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { SVG } from "@/components/SVG";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { SecondaryButton } from "@/components/buttons/SecondaryButton";
+import ModalBase from "@/components/modals/ModalBase";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { useBalances } from "@/hooks/useBalances";
+import {
+ useSelectedNetworkId,
+ useSelectedNetworkInfo,
+} from "@/hooks/useSelectedNetwork";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import {
+ NetworkFeature,
+ getNetworkFeature,
+ getNetworkObjectId,
+} from "@/networks";
+import { Tag } from "@/screens/Projects/components/Milestone";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { Project } from "@/screens/Projects/types";
+import { prettyPrice } from "@/utils/coins";
+import { neutral17, neutral77 } from "@/utils/style/colors";
+import {
+ fontSemibold12,
+ fontSemibold13,
+ fontSemibold14,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { tinyAddress } from "@/utils/text";
+
+type FundProjectModalProps = {
+ isVisible: boolean;
+ onClose: () => void;
+ project: Project;
+};
+
+export const FundProjectModal: React.FC = ({
+ isVisible,
+ onClose,
+ project,
+}) => {
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+ const selectedNetwork = useSelectedNetworkInfo();
+
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+
+ const { balances } = useBalances(
+ selectedNetwork?.id,
+ selectedWallet?.address,
+ );
+ const bal = balances?.find((b) => b.denom === pmFeature?.paymentsDenom);
+
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+
+ const queryClient = useQueryClient();
+
+ const submitFunder = async () => {
+ setIsSubmitting(true);
+ try {
+ await execEscrowMethod(
+ "SubmitFunder",
+ [project.id?.toString()],
+ `${project.budget}${project.paymentDenom}`,
+ );
+ await Promise.all([
+ queryClient.invalidateQueries([
+ "project",
+ getNetworkObjectId(networkId, project.id),
+ ]),
+ queryClient.invalidateQueries(["projects", networkId]),
+ ]);
+ } finally {
+ onClose();
+ setIsSubmitting(false);
+ }
+ };
+
+ const fundingAmount = useMemo(() => {
+ return project.milestones
+ .map((m) => m.amount)
+ .reduce((total, amount) => total + BigInt(amount), BigInt(0))
+ .toString();
+ }, [project]);
+
+ return (
+
+
+ You’re making the signature to validate a transaction
+
+
+
+
+
+
+
+
+
+
+
+ {selectedNetwork?.displayName}
+
+
+
+ {tinyAddress(selectedWallet?.address, 16)}
+
+
+
+ {selectedWallet?.address && }
+
+
+
+
+
+
+ Funding amount
+
+
+
+ {prettyPrice(networkId, fundingAmount, pmFeature?.paymentsDenom)}
+
+
+
+
+
+ Balance
+
+
+
+ {prettyPrice(networkId, bal?.amount, pmFeature?.paymentsDenom)}
+
+
+
+
+
+ submitFunder()}
+ />
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/HeaderBackButton.tsx b/packages/screens/Projects/components/HeaderBackButton.tsx
new file mode 100644
index 0000000000..e93c778f19
--- /dev/null
+++ b/packages/screens/Projects/components/HeaderBackButton.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import { TouchableOpacity } from "react-native";
+
+import chevronLeftSVG from "../../../../assets/icons/chevron-left.svg";
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SVG } from "../../../components/SVG";
+import { SpacerRow } from "../../../components/spacer";
+import { useAppNavigation } from "../../../utils/navigation";
+import { fontSemibold20 } from "../../../utils/style/fonts";
+
+export const HeaderBackButton: React.FC = () => {
+ const navigation = useAppNavigation();
+
+ return (
+ navigation.navigate("Projects")}>
+
+
+
+ Projects Program
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/Milestone.tsx b/packages/screens/Projects/components/Milestone.tsx
new file mode 100644
index 0000000000..a6f84d0ea7
--- /dev/null
+++ b/packages/screens/Projects/components/Milestone.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { StyleProp, ViewStyle } from "react-native";
+
+import { SimpleButton } from "../../../components/buttons/SimpleButton";
+import { neutral00, neutral33, neutral77 } from "../../../utils/style/colors";
+import { fontSemibold13 } from "../../../utils/style/fonts";
+
+export const Tag: React.FC<{
+ text: string;
+ color?: string;
+ bgColor?: string;
+ size?: "XS" | "SM" | "M" | "XL";
+ borderColor?: string;
+ containerStyle?: StyleProp;
+}> = ({ text, bgColor, color, borderColor, size, containerStyle }) => {
+ if (text === "") return null;
+
+ return (
+
+ );
+};
diff --git a/packages/screens/Projects/components/MilestoneBoard.tsx b/packages/screens/Projects/components/MilestoneBoard.tsx
new file mode 100644
index 0000000000..0112a4e0df
--- /dev/null
+++ b/packages/screens/Projects/components/MilestoneBoard.tsx
@@ -0,0 +1,181 @@
+import React, { useState } from "react";
+import { StyleProp, ViewStyle } from "react-native";
+import Hoverable from "react-native-hoverable";
+import { SvgProps } from "react-native-svg";
+
+import { MilestoneForm } from "./MilestoneForm";
+import { MilestoneItem } from "./MilestoneItem";
+import { MilestoneList } from "./MilestoneList";
+import addCircleSVG from "../../../../assets/icons/add-circle.svg";
+import noMilestonesSVG from "../../../../assets/icons/no-tasks.svg";
+import projectsCompletedSVG from "../../../../assets/icons/projects-completed.svg";
+import projectsInProgressSVG from "../../../../assets/icons/projects-inProgress.svg";
+import projectsOpenSVG from "../../../../assets/icons/projects-open.svg";
+import projectsReviewSVG from "../../../../assets/icons/projects-review.svg";
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SVG } from "../../../components/SVG";
+import { SimpleButton } from "../../../components/buttons/SimpleButton";
+import { SpacerColumn, SpacerRow } from "../../../components/spacer";
+import {
+ neutral00,
+ neutral33,
+ neutral77,
+ neutralFF,
+} from "../../../utils/style/colors";
+import { fontSemibold13 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import { useMakeRequestState } from "../hooks/useMakeRequestHook";
+import {
+ ProjectMilestone,
+ MilestoneStatus,
+ MilestoneFormValues,
+} from "../types";
+
+export type Step = {
+ status: MilestoneStatus;
+ text: string;
+ iconSVG: React.FC;
+};
+
+const STEPS: Step[] = [
+ {
+ status: "MS_OPEN",
+ text: "Open (Backlog)",
+ iconSVG: projectsOpenSVG,
+ },
+ {
+ status: "MS_PROGRESS",
+ text: "In Progress",
+ iconSVG: projectsInProgressSVG,
+ },
+ {
+ status: "MS_REVIEW",
+ text: "Review",
+ iconSVG: projectsReviewSVG,
+ },
+ {
+ status: "MS_COMPLETED",
+ text: "Completed",
+ iconSVG: projectsCompletedSVG,
+ },
+];
+
+export const MilestoneBoard: React.FC<{
+ milestones: ProjectMilestone[];
+ containerStyle?: StyleProp;
+ onSelectMilestone?: (id: string) => void;
+ editable?: boolean;
+}> = ({ onSelectMilestone, containerStyle, editable, milestones }) => {
+ const [hoveredMilestone, setHoveredMilestone] = useState();
+ const [isShowMilestoneForm, showMilestoneForm] = useState(false);
+
+ const {
+ actions: { addMilestone, removeMilestone },
+ } = useMakeRequestState();
+
+ const removeHoveredMilestone = (id: string) => {
+ setHoveredMilestone(undefined);
+ removeMilestone(id);
+ };
+
+ const addNewMilestone = (milestone: MilestoneFormValues) => {
+ showMilestoneForm(false);
+ console.log("adding milestone", milestone);
+ addMilestone(milestone);
+ };
+
+ return (
+
+ {STEPS.map((step, idx) => {
+ const listItems = (milestones || []).filter(
+ (milestone) => milestone.status === step.status,
+ );
+ const isBacklogItem = idx === 0;
+
+ return (
+
+ {listItems.map((milestone) => {
+ const isHovered = hoveredMilestone?.id === milestone.id;
+ return (
+
+ isBacklogItem && editable && setHoveredMilestone(milestone)
+ }
+ onMouseLeave={() =>
+ isBacklogItem && editable && setHoveredMilestone(undefined)
+ }
+ >
+
+
+
+ );
+ })}
+
+ {listItems.length === 0 && (
+
+
+
+
+ {editable ? "No milestones" : "Empty"}
+
+
+ )}
+
+ {isBacklogItem && isShowMilestoneForm && (
+ showMilestoneForm(false)}
+ onSubmit={addNewMilestone}
+ />
+ )}
+
+ {isBacklogItem && editable && !isShowMilestoneForm && (
+ showMilestoneForm(true)}
+ text="Add"
+ size="XS"
+ iconSVG={addCircleSVG}
+ color={neutralFF}
+ bgColor={neutral33}
+ style={{
+ width: "100%",
+ justifyContent: "center",
+ alignItems: "center",
+ }}
+ />
+ )}
+
+
+
+ );
+ })}
+
+ );
+};
diff --git a/packages/screens/Projects/components/MilestoneForm.tsx b/packages/screens/Projects/components/MilestoneForm.tsx
new file mode 100644
index 0000000000..728e60aa11
--- /dev/null
+++ b/packages/screens/Projects/components/MilestoneForm.tsx
@@ -0,0 +1,248 @@
+import { Decimal } from "@cosmjs/math";
+import { zodResolver } from "@hookform/resolvers/zod";
+import React, { useState } from "react";
+import { useForm } from "react-hook-form";
+import { TouchableOpacity, View } from "react-native";
+
+import closeSVG from "../../../../assets/icons/close.svg";
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SVG } from "../../../components/SVG";
+import { TertiaryBox } from "../../../components/boxes/TertiaryBox";
+import { SimpleButton } from "../../../components/buttons/SimpleButton";
+import {
+ SelectInput,
+ SelectInputItem,
+} from "../../../components/inputs/SelectInput";
+import { TextInputCustom } from "../../../components/inputs/TextInputCustom";
+import { SpacerColumn } from "../../../components/spacer";
+import {
+ neutral22,
+ neutral33,
+ neutral44,
+ neutral77,
+ neutralFF,
+ primaryColor,
+ redDefault,
+} from "../../../utils/style/colors";
+import { fontSemibold12 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import {
+ MilestoneFormValues,
+ MilestonePriority,
+ zodMilestoneFormValues,
+} from "../types";
+
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import {
+ NetworkFeature,
+ getNativeCurrency,
+ getNetworkFeature,
+} from "@/networks";
+
+const PRIORITIES: SelectInputItem[] = [
+ { label: "High", value: "MS_PRIORITY_HIGH".toString() },
+ { label: "Medium", value: "MS_PRIORITY_MEDIUM".toString() },
+];
+
+const initialValues: MilestoneFormValues = {
+ title: "",
+ desc: "",
+ priority: "MS_PRIORITY_MEDIUM",
+ amount: 0,
+ duration: 0,
+};
+
+export const MilestoneForm: React.FC<{
+ onSubmit: (milestone: MilestoneFormValues) => void;
+ onClose: () => void;
+}> = ({ onSubmit, onClose }) => {
+ const [priority, setPriority] =
+ useState("MS_PRIORITY_MEDIUM");
+
+ const networkId = useSelectedNetworkId();
+
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+ const currency = getNativeCurrency(networkId, pmFeature?.paymentsDenom);
+ const decimals = currency?.decimals || 0;
+
+ const { handleSubmit, watch, formState, setValue } = useForm({
+ resolver: zodResolver(zodMilestoneFormValues),
+ defaultValues: initialValues,
+ });
+ const values = watch();
+ const { errors } = formState;
+
+ return (
+
+
+ setValue("title", val)}
+ name="milestoneName"
+ label=""
+ placeHolder="⚡️ Type name here..."
+ hideLabel
+ fullWidth
+ noBrokenCorners
+ containerStyle={{ width: "100%" }}
+ height={32}
+ value={values.title}
+ error={errors.title?.message}
+ />
+
+
+
+ setValue("desc", val)}
+ value={values.desc}
+ error={errors.desc?.message}
+ />
+
+
+
+
+
+ Priority
+
+ p.value === priority.toString()) ||
+ PRIORITIES[0]
+ }
+ selectItem={(item) => setPriority(item.value as any)}
+ boxStyle={{ height: 32 }}
+ />
+
+
+
+
+
+
+ Budget
+
+ setValue("amount", +val)}
+ name="milestoneBudget"
+ label=""
+ placeHolder="Type here..."
+ hideLabel
+ fullWidth
+ noBrokenCorners
+ containerStyle={{ flex: 1 }}
+ height={32}
+ value={"" + values.amount}
+ error={errors.amount?.message}
+ testID="milestone-budget"
+ />
+
+
+
+
+
+
+ Duration
+
+ setValue("duration", +val)}
+ name="milestoneDuration"
+ label=""
+ placeHolder="Type here..."
+ hideLabel
+ fullWidth
+ noBrokenCorners
+ containerStyle={{ flex: 1 }}
+ height={32}
+ value={"" + values.duration}
+ error={errors.duration?.message}
+ testID="milestone-duration"
+ />
+
+
+
+
+
+
+ Github link
+
+ setValue("link", val)}
+ name="milestoneGithubLink"
+ label=""
+ placeHolder="Github link..."
+ hideLabel
+ fullWidth
+ noBrokenCorners
+ containerStyle={{ flex: 1 }}
+ height={32}
+ value={values.link}
+ error={errors.link?.message}
+ />
+
+
+
+
+ {
+ console.log("adding milestone: handle sumbit", values);
+ values.priority = priority;
+ // FIXME: loss of precision
+ values.amount = +Decimal.fromUserInput(
+ values.amount.toString(),
+ decimals,
+ ).atomics;
+ onSubmit(values);
+ },
+ (state) => {
+ console.error("adding milestone: invalid", state);
+ },
+ )}
+ text="Confirm"
+ size="XS"
+ color={neutralFF}
+ bgColor={primaryColor}
+ testID="milestone-confirm"
+ style={{
+ width: "100%",
+ justifyContent: "center",
+ alignItems: "center",
+ }}
+ />
+
+
+ onClose?.()}
+ style={{
+ position: "absolute",
+ right: -44,
+ top: "30%",
+ padding: layout.spacing_x1,
+ backgroundColor: neutral33,
+ borderWidth: 1,
+ borderColor: neutral44,
+ borderRadius: 100,
+ }}
+ >
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/MilestoneItem.tsx b/packages/screens/Projects/components/MilestoneItem.tsx
new file mode 100644
index 0000000000..6b28798d5d
--- /dev/null
+++ b/packages/screens/Projects/components/MilestoneItem.tsx
@@ -0,0 +1,162 @@
+import moment from "moment";
+import React from "react";
+import { TouchableOpacity, View } from "react-native";
+
+import { Tag } from "./Milestone";
+import githubSVG from "../../../../assets/icons/github.svg";
+import trashSVG from "../../../../assets/icons/trash.svg";
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SVG } from "../../../components/SVG";
+import { TertiaryBox } from "../../../components/boxes/TertiaryBox";
+import { SocialButton } from "../../../components/buttons/SocialButton";
+import { SpacerColumn } from "../../../components/spacer";
+import {
+ neutral00,
+ neutral22,
+ neutral33,
+ neutral44,
+ neutral77,
+ neutralA3,
+ redDefault,
+} from "../../../utils/style/colors";
+import { fontSemibold13 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import { ProjectMilestone } from "../types";
+
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { NetworkFeature, getNetworkFeature } from "@/networks";
+import { prettyPrice } from "@/utils/coins";
+
+export const MilestoneItem: React.FC<{
+ milestone: ProjectMilestone;
+ isHovered?: boolean;
+ onPress?: (id: string) => void;
+ onDelete?: (id: string) => void;
+}> = ({ milestone, onPress, isHovered, onDelete }) => {
+ const networkId = useSelectedNetworkId();
+
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+
+ return (
+
+ onPress?.(milestone.id)}>
+
+
+ 🔎 {milestone.title}
+
+
+
+
+
+ {milestone.desc}
+
+
+
+
+
+ Duration:{" "}
+ {moment.duration(milestone.duration, "seconds").humanize()}
+
+
+
+
+ {milestone.priority === "MS_PRIORITY_HIGH" && (
+
+ )}
+
+ {milestone.priority === "MS_PRIORITY_MEDIUM" && (
+
+ )}
+
+ {milestone.priority === "MS_PRIORITY_LOW" && (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {isHovered && (
+
+ onDelete?.(milestone.id)}
+ style={{
+ position: "absolute",
+ padding: layout.spacing_x1,
+ backgroundColor: neutral33,
+ borderWidth: 1,
+ borderColor: neutral44,
+ borderRadius: 100,
+ }}
+ >
+
+
+
+ )}
+
+ );
+};
diff --git a/packages/screens/Projects/components/MilestoneList.tsx b/packages/screens/Projects/components/MilestoneList.tsx
new file mode 100644
index 0000000000..dab18ae6ed
--- /dev/null
+++ b/packages/screens/Projects/components/MilestoneList.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import { View } from "react-native";
+import { SvgProps } from "react-native-svg";
+
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SVG } from "../../../components/SVG";
+import { neutral00 } from "../../../utils/style/colors";
+import { fontSemibold13 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+
+export const MilestoneList: React.FC<{
+ iconSVG: React.FC;
+ text: string;
+ count: number;
+ children: React.ReactNode;
+}> = ({ iconSVG, text, count, children }) => {
+ return (
+
+
+
+
+ {text}
+
+
+ {count}
+
+
+ {children}
+
+ );
+};
diff --git a/packages/screens/Projects/components/MilestonePriorityTag.tsx b/packages/screens/Projects/components/MilestonePriorityTag.tsx
new file mode 100644
index 0000000000..658371f0ab
--- /dev/null
+++ b/packages/screens/Projects/components/MilestonePriorityTag.tsx
@@ -0,0 +1,20 @@
+import React from "react";
+
+import { Tag } from "./Milestone";
+import { neutral33, neutralFF } from "../../../utils/style/colors";
+import { MilestonePriority } from "../types";
+
+export const MilestonePriorityTag: React.FC<{
+ priority: MilestonePriority;
+}> = ({ priority }) => {
+ switch (priority) {
+ case "MS_PRIORITY_HIGH":
+ return ;
+ case "MS_PRIORITY_MEDIUM":
+ return ;
+ case "MS_PRIORITY_LOW":
+ return ;
+ default:
+ return ;
+ }
+};
diff --git a/packages/screens/Projects/components/MilestoneStatusTag.tsx b/packages/screens/Projects/components/MilestoneStatusTag.tsx
new file mode 100644
index 0000000000..33f07bf667
--- /dev/null
+++ b/packages/screens/Projects/components/MilestoneStatusTag.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+
+import { Tag } from "./Milestone";
+import { neutralFF } from "../../../utils/style/colors";
+import { MilestoneStatus } from "../types";
+
+export const MilestoneStatusTag: React.FC<{
+ status: MilestoneStatus;
+}> = ({ status }) => {
+ switch (status) {
+ case "MS_OPEN":
+ return ;
+ case "MS_PROGRESS":
+ return ;
+ case "MS_REVIEW":
+ return ;
+ case "MS_COMPLETED":
+ return ;
+ default:
+ return ;
+ }
+};
diff --git a/packages/screens/Projects/components/ProjectBox.tsx b/packages/screens/Projects/components/ProjectBox.tsx
new file mode 100644
index 0000000000..343cbd9e4d
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectBox.tsx
@@ -0,0 +1,249 @@
+import { Link, useLinkBuilder } from "@react-navigation/native";
+import React, { memo, useMemo } from "react";
+import { ScrollView, TouchableOpacity, View } from "react-native";
+
+import { Tag } from "./Milestone";
+import { ProjectStatusTag } from "./ProjectStatusTag";
+import { Project } from "../types";
+
+import discordSVG from "@/assets/icons/discord.svg";
+import githubSVG from "@/assets/icons/github.svg";
+import shareSVG from "@/assets/icons/share.svg";
+import twitterSVG from "@/assets/icons/twitter.svg";
+import websiteSVG from "@/assets/icons/website.svg";
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { ProgressLine } from "@/components/ProgressLine";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { SocialButton } from "@/components/buttons/SocialButton";
+import { RoundedGradientImage } from "@/components/images/RoundedGradientImage";
+import { Separator } from "@/components/separators/Separator";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { useFeedbacks } from "@/context/FeedbacksProvider";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import Clipboard from "@/modules/Clipboard";
+import { getNetworkObjectId, getUserId } from "@/networks";
+import { prettyPrice } from "@/utils/coins";
+import { useAppNavigation } from "@/utils/navigation";
+import { joinElements } from "@/utils/react";
+import {
+ neutral17,
+ neutral77,
+ neutralA3,
+ secondaryColor,
+} from "@/utils/style/colors";
+import {
+ fontSemibold10,
+ fontSemibold13,
+ fontSemibold20,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { normalizeTwitterId } from "@/utils/twitter";
+
+export const ProjectBox: React.FC<{
+ project: Project;
+ width: number;
+}> = memo(({ project, width }) => {
+ const stats = useMemo(() => {
+ if (!project.milestones)
+ return { completed: 0, total: 0, percentCompleted: 0 };
+ const completed = project.milestones.filter(
+ (ms) => ms.status === "MS_COMPLETED",
+ ).length;
+ const total = project.milestones.length;
+ const percentCompleted = Math.floor((completed / total) * 100);
+ return { completed, total, percentCompleted };
+ }, [project.milestones]);
+ const { setToast } = useFeedbacks();
+ const buildLink = useLinkBuilder();
+
+ const networkId = useSelectedNetworkId();
+
+ const navigation = useAppNavigation();
+
+ const gotoProjectsDetail = (localId: string | undefined) => {
+ if (!localId) {
+ return;
+ }
+ navigation.navigate("ProjectsDetail", {
+ id: getNetworkObjectId(networkId, localId),
+ });
+ };
+
+ const onPress = () => gotoProjectsDetail(project.id);
+
+ const bottomElems = [
+ {
+ const pathname = buildLink("ProjectsDetail", {
+ id: getNetworkObjectId(networkId, project.id),
+ });
+ if (!pathname) return;
+
+ const link = new URL(window.location.href);
+ link.pathname = pathname;
+ await Clipboard.setStringAsync(link.href);
+
+ setToast({
+ title: "Copied permanent link",
+ message: "",
+ type: "success",
+ mode: "normal",
+ });
+ }}
+ />,
+ ];
+ if (project.metadata?.teamAndLinkData?.discordLink) {
+ bottomElems.push(
+
+
+ ,
+ );
+ }
+ if (project.metadata?.teamAndLinkData?.websiteLink) {
+ bottomElems.push(
+
+
+ ,
+ );
+ }
+ if (project.metadata?.teamAndLinkData?.githubLink) {
+ bottomElems.push(
+
+
+ ,
+ );
+ }
+ if (project.metadata?.teamAndLinkData?.twitterProfile) {
+ bottomElems.push(
+
+
+ ,
+ );
+ }
+
+ return (
+
+ {/* Body ============================================================== */}
+
+
+
+
+
+
+
+
+
+ {project.metadata?.shortDescData?.name}
+
+
+
+
+ {project.metadata?.shortDescData?.tags
+ ?.split(",")
+ .map((tag, idx) => (
+
+ ))}
+
+
+
+
+
+
+ {project.metadata?.shortDescData?.desc}
+
+
+
+
+
+
+
+ Milestones
+
+
+ {stats.completed}/{stats.total}
+
+
+
+
+
+
+
+ {/* Footer ============================================================== */}
+
+
+
+
+
+
+ Grant:{" "}
+
+
+ {prettyPrice(
+ networkId,
+ project.budget || "0",
+ project.paymentDenom,
+ )}
+
+
+
+
+
+
+
+
+ {joinElements(bottomElems, )}
+
+
+
+
+
+
+ );
+});
diff --git a/packages/screens/Projects/components/ProjectInfo/LeftBlock.tsx b/packages/screens/Projects/components/ProjectInfo/LeftBlock.tsx
new file mode 100644
index 0000000000..94427f1023
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectInfo/LeftBlock.tsx
@@ -0,0 +1,207 @@
+import React, { useState } from "react";
+import { View } from "react-native";
+
+import { Project } from "../../types";
+import { FundProjectModal } from "../FundProjectModal";
+import { Tag } from "../Milestone";
+import { ProjectStatusTag } from "../ProjectStatusTag";
+import { ResolveConflictButton } from "../ResolveConflictButton";
+import { SubmitContractorCandidateModal } from "../SubmitContractorCandidateModal";
+
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { RoundedGradientImage } from "@/components/images/RoundedGradientImage";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import { useAppNavigation } from "@/hooks/navigation/useAppNavigation";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { getNetworkObjectId, getUserId } from "@/networks";
+import {
+ errorColor,
+ neutral00,
+ neutral33,
+ neutral77,
+ neutralA3,
+} from "@/utils/style/colors";
+import {
+ fontSemibold13,
+ fontSemibold14,
+ fontSemibold20,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+type LeftBlockProps = {
+ networkId: string;
+ project: Project;
+};
+
+export const LeftBlock: React.FC = ({ networkId, project }) => {
+ const navigation = useAppNavigation();
+ const [isFundModalVisible, setIsFundModalVisible] = useState(false);
+
+ const projectId = getNetworkObjectId(networkId, project.id);
+
+ const selectedWallet = useSelectedWallet();
+ const walletAddress = selectedWallet?.address || "";
+
+ const projectStatus = project.status;
+ const shortDescData = project.metadata?.shortDescData;
+
+ const authorId = project
+ ? getUserId(networkId, project.sender)
+ : selectedWallet?.userId;
+
+ return (
+
+ {shortDescData?.name}
+
+
+
+ Project creator:{" "}
+
+
+
+
+
+
+
+ {projectStatus && }
+
+
+
+ {shortDescData?.tags?.split(",").map((tag, idx) => {
+ return (
+
+ );
+ })}
+
+
+
+ {/* Image */}
+
+
+ {/* Name and Description */}
+
+
+
+ {shortDescData?.desc}
+
+
+
+
+
+
+ {project &&
+ (walletAddress === project.funder ||
+ walletAddress === project?.contractor) &&
+ project.status === "ACCEPTED" && (
+ <>
+ {
+ project.id !== undefined &&
+ navigation.navigate("ProjectsConflictSolving", {
+ projectId,
+ });
+ }}
+ size="SM"
+ width={280}
+ />
+
+ >
+ )}
+
+ {project.id !== undefined &&
+ project.status === "CONFLICT" &&
+ (walletAddress === project.conflictHandler ||
+ walletAddress === project.contractor ||
+ walletAddress === project.funder) && (
+ <>
+
+
+ >
+ )}
+
+ {/* Actions */}
+ {/* If current user is not contractor, not creator of project and the project has not funder yet then user can become funder */}
+ {walletAddress !== project.sender &&
+ walletAddress !== project.contractor &&
+ !project.funded &&
+ project.status === "CREATED" && (
+ setIsFundModalVisible(true)}
+ size="SM"
+ width={200}
+ />
+ )}
+
+
+
+
+
+
+
+ {project?.id && (
+ setIsFundModalVisible(false)}
+ />
+ )}
+
+ );
+};
+
+export const SubmitCandidacyButton: React.FC<{
+ project: Project;
+}> = ({ project }) => {
+ const [isSubmitContractorModalVisible, setIsSubmitContractorModalVisible] =
+ useState(false);
+ return (
+ <>
+ setIsSubmitContractorModalVisible(false)}
+ project={project}
+ />
+ setIsSubmitContractorModalVisible(true)}
+ size="SM"
+ />
+ >
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectInfo/RelatedUsers.tsx b/packages/screens/Projects/components/ProjectInfo/RelatedUsers.tsx
new file mode 100644
index 0000000000..39dcf666c9
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectInfo/RelatedUsers.tsx
@@ -0,0 +1,83 @@
+import { Link } from "@react-navigation/native";
+import React from "react";
+import { Table, Row, Cell, TableWrapper } from "react-native-reanimated-table";
+
+import { SubmitCandidacyButton } from "./LeftBlock";
+
+import { BrandText } from "@/components/BrandText";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { SpacerColumn } from "@/components/spacer";
+import { UsernameWithAvatar } from "@/components/user/UsernameWithAvatar";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { getUserId } from "@/networks";
+import { Project } from "@/screens/Projects/types";
+import { neutral22, neutralA3 } from "@/utils/style/colors";
+import { fontSemibold14 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+
+type RelatedUsersProps = {
+ networkId: string;
+ project: Project;
+};
+
+export const RelatedUsers: React.FC = ({
+ networkId,
+ project,
+}) => {
+ const wallet = useSelectedWallet();
+ const walletAddress = wallet?.address;
+
+ const showCandidacyButton =
+ !!walletAddress &&
+ !!project &&
+ walletAddress !== project.sender &&
+ walletAddress !== project.funder &&
+ !project.contractor &&
+ project.status === "CREATED" &&
+ !project.contractorCandidates?.includes(walletAddress);
+
+ return (
+
+
+
+
+
+ {[project?.funder, project?.contractor, project?.conflictHandler].map(
+ (cellData, cellIndex) => {
+ let content;
+ if (cellIndex === 1 && !cellData) {
+ if (showCandidacyButton) {
+ content = ;
+ } else {
+ content = (
+
+
+ {project.contractorCandidates.length} candidates
+
+
+ );
+ }
+ } else {
+ content = (
+
+ );
+ }
+ return | ;
+ },
+ )}
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectInfo/RightBlock.tsx b/packages/screens/Projects/components/ProjectInfo/RightBlock.tsx
new file mode 100644
index 0000000000..518b5cb0bc
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectInfo/RightBlock.tsx
@@ -0,0 +1,176 @@
+import { Link } from "@react-navigation/native";
+import moment from "moment/moment";
+import React from "react";
+import { View } from "react-native";
+
+import copySVG from "@/assets/icons/copy.svg";
+import discordSVG from "@/assets/icons/discord.svg";
+import githubSVG from "@/assets/icons/github.svg";
+import twitterSVG from "@/assets/icons/twitter.svg";
+import websiteSVG from "@/assets/icons/website.svg";
+import { BrandText } from "@/components/BrandText";
+import FlexRow from "@/components/FlexRow";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { IconWithTextButton } from "@/components/buttons/SocialButton";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import { useFeedbacks } from "@/context/FeedbacksProvider";
+import Clipboard from "@/modules/Clipboard";
+import { Project } from "@/screens/Projects/types";
+import { prettyPrice } from "@/utils/coins";
+import { joinElements } from "@/utils/react";
+import {
+ neutral22,
+ neutral77,
+ neutralA3,
+ primaryColor,
+ yellowDefault,
+} from "@/utils/style/colors";
+import { fontSemibold20 } from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { normalizeTwitterId } from "@/utils/twitter";
+
+type RightBlockProps = {
+ project: Project;
+ networkId: string;
+};
+
+export const RightBlock: React.FC = ({
+ networkId,
+ project,
+}) => {
+ const { setToast } = useFeedbacks();
+
+ const isFunded = project.funded;
+ const teamAndLinkData = project.metadata?.teamAndLinkData;
+
+ const actions = [
+ {
+ await Clipboard.setStringAsync(window.location.href);
+ setToast({
+ title: "Copied permanent link",
+ message: "",
+ type: "success",
+ mode: "normal",
+ });
+ }}
+ />,
+ ];
+
+ if (teamAndLinkData?.websiteLink) {
+ actions.push(
+
+
+ ,
+ );
+ }
+
+ if (teamAndLinkData?.discordLink) {
+ actions.push(
+
+
+ ,
+ );
+ }
+
+ if (teamAndLinkData?.githubLink) {
+ actions.push(
+
+
+ ,
+ );
+ }
+
+ if (teamAndLinkData?.twitterProfile) {
+ actions.push(
+
+
+ ,
+ );
+ }
+
+ return (
+
+
+
+
+ {isFunded ? "Deposited:" : "Budget:"}
+
+
+
+ {prettyPrice(networkId, project.budget, project.paymentDenom)}
+
+
+
+
+
+
+
+
+
+ Expires on:
+
+
+
+ {/* FIXME */}
+ {moment(/*project.duration ||*/ 0 * 1000 + Date.now()).format(
+ "L",
+ )}{" "}
+
+
+
+
+
+
+
+ {joinElements(actions, )}
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectInfo/index.tsx b/packages/screens/Projects/components/ProjectInfo/index.tsx
new file mode 100644
index 0000000000..9d8e7ba6f5
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectInfo/index.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import { View } from "react-native";
+
+import { Project } from "../../types";
+
+import FlexRow from "@/components/FlexRow";
+import { useSelectedNetworkId } from "@/hooks/useSelectedNetwork";
+import { LeftBlock } from "@/screens/Projects/components/ProjectInfo/LeftBlock";
+import { RelatedUsers } from "@/screens/Projects/components/ProjectInfo/RelatedUsers";
+import { RightBlock } from "@/screens/Projects/components/ProjectInfo/RightBlock";
+import { layout } from "@/utils/style/layout";
+
+export const ProjectInfo: React.FC<{
+ project: Project;
+}> = ({ project }) => {
+ const networkId = useSelectedNetworkId();
+
+ return (
+
+
+ {/* Left block ======================================================= */}
+
+
+
+
+ {/* Right block ======================================================= */}
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectMilestones.tsx b/packages/screens/Projects/components/ProjectMilestones.tsx
new file mode 100644
index 0000000000..6545875f4c
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectMilestones.tsx
@@ -0,0 +1,78 @@
+import React, { useMemo, useState } from "react";
+import { View } from "react-native";
+
+import { MilestoneBoard } from "./MilestoneBoard";
+import { BrandText } from "../../../components/BrandText";
+import FlexRow from "../../../components/FlexRow";
+import { SearchBarInput } from "../../../components/Search/SearchBarInput";
+import { Separator } from "../../../components/separators/Separator";
+import { SpacerRow } from "../../../components/spacer";
+import {
+ neutral77,
+ neutral33,
+ neutral00,
+ neutral17,
+} from "../../../utils/style/colors";
+import { fontSemibold20 } from "../../../utils/style/fonts";
+import { layout } from "../../../utils/style/layout";
+import { ProjectMilestone } from "../types";
+
+export const ProjectMilestones: React.FC<{
+ milestones: ProjectMilestone[];
+ onSelectMilestone?: (id: string) => void;
+}> = ({ milestones, onSelectMilestone }) => {
+ const [searchText, setSearchText] = useState("");
+ const [isHideInfo, setIsHideInfo] = useState(false);
+
+ const filteredMilestones = useMemo(() => {
+ return milestones.filter(
+ (m) => m.title.includes(searchText) || m.desc.includes(searchText),
+ );
+ }, [milestones, searchText]);
+
+ return (
+
+
+ setIsHideInfo(!isHideInfo)}
+ style={fontSemibold20}
+ >
+ All Milestones:
+
+
+
+ {filteredMilestones.length}
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectStatusTag.tsx b/packages/screens/Projects/components/ProjectStatusTag.tsx
new file mode 100644
index 0000000000..e09c710cfe
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectStatusTag.tsx
@@ -0,0 +1,92 @@
+import React from "react";
+
+import { SimpleButton } from "../../../components/buttons/SimpleButton";
+import {
+ neutral00,
+ neutral22,
+ primaryColor,
+ redDefault,
+ secondaryColor,
+} from "../../../utils/style/colors";
+import { ContractStatusFilter } from "../types";
+
+export const ProjectStatusTag: React.FC<{
+ status: ContractStatusFilter | undefined;
+ onPress?: () => void;
+ active?: boolean;
+ size?: "XS" | "SM" | "M" | "XL";
+}> = ({ status, onPress, active, size }) => {
+ let color, bgColor, borderColor, text;
+
+ switch (status) {
+ case "ALL":
+ text = "All";
+ color = secondaryColor;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ case "CREATED":
+ text = "Open";
+ color = "#C8FFAE";
+ bgColor = "#C8FFAE1A";
+ borderColor = "#C8FFAE1A";
+ break;
+ case "ACCEPTED":
+ text = "In Progress";
+ color = "#EAA54B";
+ bgColor = "#EAA54B1A";
+ borderColor = "#EAA54B1A";
+ break;
+ case "COMPLETED":
+ text = "Completed";
+ color = primaryColor;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ case "CANCELED":
+ text = "Canceled";
+ color = redDefault;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ case "REJECTED":
+ text = "Rejected";
+ color = redDefault;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ case "CONFLICT":
+ text = "Conflict";
+ color = redDefault;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ case "ABORTED_IN_FAVOR_OF_CONTRACTOR":
+ case "ABORTED_IN_FAVOR_OF_FUNDER":
+ text = "Aborted";
+ color = redDefault;
+ bgColor = neutral00;
+ borderColor = neutral22;
+ break;
+ default:
+ color = secondaryColor;
+ bgColor = neutral00;
+ borderColor = neutral00;
+ text = "unknown";
+ break;
+ }
+
+ return (
+ onPress?.()}
+ text={text}
+ size={size}
+ bgColor={bgColor}
+ color={color}
+ style={{
+ borderColor: active ? secondaryColor : borderColor,
+ }}
+ testID={`project-status-${status || "UNKNOWN"}`}
+ />
+ );
+};
diff --git a/packages/screens/Projects/components/ProjectsStatusFilterButtons.tsx b/packages/screens/Projects/components/ProjectsStatusFilterButtons.tsx
new file mode 100644
index 0000000000..6fcd01bf44
--- /dev/null
+++ b/packages/screens/Projects/components/ProjectsStatusFilterButtons.tsx
@@ -0,0 +1,63 @@
+import React from "react";
+
+import { ProjectStatusTag } from "./ProjectStatusTag";
+import FlexRow from "../../../components/FlexRow";
+import { SpacerRow } from "../../../components/spacer";
+import { ContractStatusFilter } from "../types";
+
+export const ProjectsStatusFilterButtons: React.FC<{
+ status: ContractStatusFilter;
+ onChange: (newFilter: ContractStatusFilter) => void;
+}> = ({ status, onChange }) => {
+ return (
+
+ onChange("ALL")}
+ />
+
+
+
+ onChange("CREATED")}
+ />
+
+
+
+ onChange("ACCEPTED")}
+ />
+
+
+
+ onChange("REJECTED")}
+ />
+
+
+
+ onChange("COMPLETED")}
+ />
+
+ );
+};
diff --git a/packages/screens/Projects/components/ResolveConflictButton.tsx b/packages/screens/Projects/components/ResolveConflictButton.tsx
new file mode 100644
index 0000000000..40994e1bbd
--- /dev/null
+++ b/packages/screens/Projects/components/ResolveConflictButton.tsx
@@ -0,0 +1,28 @@
+import React, { FC } from "react";
+
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { useAppNavigation } from "@/utils/navigation";
+
+export const ResolveConflictButton: FC<{
+ projectId: string | undefined;
+}> = ({ projectId }) => {
+ const navigation = useAppNavigation();
+ return (
+ <>
+ {
+ if (!projectId) {
+ return;
+ }
+ navigation.navigate("ProjectsConflictSolving", {
+ projectId,
+ });
+ }}
+ size="SM"
+ width={280}
+ />
+ >
+ );
+};
diff --git a/packages/screens/Projects/components/SubmitContractorCandidateModal.tsx b/packages/screens/Projects/components/SubmitContractorCandidateModal.tsx
new file mode 100644
index 0000000000..4a685de891
--- /dev/null
+++ b/packages/screens/Projects/components/SubmitContractorCandidateModal.tsx
@@ -0,0 +1,128 @@
+import { useQueryClient } from "@tanstack/react-query";
+import React, { useState } from "react";
+import { View } from "react-native";
+
+import gnoSVG from "@/assets/icons/networks/gno.svg";
+import { BrandText } from "@/components/BrandText";
+import { SVG } from "@/components/SVG";
+import { TertiaryBox } from "@/components/boxes/TertiaryBox";
+import { PrimaryButton } from "@/components/buttons/PrimaryButton";
+import { SecondaryButton } from "@/components/buttons/SecondaryButton";
+import ModalBase from "@/components/modals/ModalBase";
+import { SpacerColumn, SpacerRow } from "@/components/spacer";
+import {
+ useSelectedNetworkId,
+ useSelectedNetworkInfo,
+} from "@/hooks/useSelectedNetwork";
+import useSelectedWallet from "@/hooks/useSelectedWallet";
+import { getNetworkObjectId } from "@/networks";
+import { Tag } from "@/screens/Projects/components/Milestone";
+import { useEscrowContract } from "@/screens/Projects/hooks/useEscrowContract";
+import { Project } from "@/screens/Projects/types";
+import { neutral17, neutral77 } from "@/utils/style/colors";
+import {
+ fontSemibold12,
+ fontSemibold13,
+ fontSemibold14,
+} from "@/utils/style/fonts";
+import { layout } from "@/utils/style/layout";
+import { tinyAddress } from "@/utils/text";
+
+type SubmitContractorCandidateModalProps = {
+ isVisible: boolean;
+ onClose: () => void;
+ project: Project;
+};
+
+export const SubmitContractorCandidateModal: React.FC<
+ SubmitContractorCandidateModalProps
+> = ({ isVisible, onClose, project }) => {
+ const networkId = useSelectedNetworkId();
+ const selectedWallet = useSelectedWallet();
+ const selectedNetwork = useSelectedNetworkInfo();
+ const queryClient = useQueryClient();
+
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const { execEscrowMethod } = useEscrowContract(
+ networkId,
+ selectedWallet?.address,
+ );
+
+ const submitContractorCandidate = async () => {
+ setIsSubmitting(true);
+
+ const localIdentifier = project?.id?.toString();
+
+ await execEscrowMethod("SubmitContractorCandidate", [localIdentifier]);
+
+ const projectId = getNetworkObjectId(networkId, localIdentifier);
+
+ await queryClient.invalidateQueries(["project", projectId]);
+
+ onClose();
+ setIsSubmitting(false);
+ };
+
+ return (
+
+
+ You’re making the signature to validate a transaction
+
+
+
+
+
+
+
+
+
+
+
+ {selectedNetwork?.displayName}
+
+
+
+ {tinyAddress(selectedWallet?.address, 16)}
+
+
+
+ {selectedWallet?.address && }
+
+
+
+
+ submitContractorCandidate()}
+ testID="confirm-and-sign"
+ />
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/screens/Projects/components/TNSResult.tsx b/packages/screens/Projects/components/TNSResult.tsx
new file mode 100644
index 0000000000..d133045551
--- /dev/null
+++ b/packages/screens/Projects/components/TNSResult.tsx
@@ -0,0 +1,49 @@
+import React from "react";
+import { View } from "react-native";
+
+import { SearchResultsSection } from "../../../components/Search/SearchBarResults";
+import { AvatarWithName } from "../../../components/user/AvatarWithName";
+import { neutral00, neutral33 } from "../../../utils/style/colors";
+import { layout } from "../../../utils/style/layout";
+
+const SEARCH_RESULTS_NAMES_MARGIN = layout.spacing_x1;
+
+export const TNSResult: React.FC<{
+ names: string[];
+ visible: boolean;
+ networkId: string;
+ onSelected: (name: string) => void;
+}> = ({ names, networkId, onSelected, visible }) => {
+ if (!visible) return null;
+ return (
+
+
+ {names.map((n) => (
+ onSelected(n)}
+ />
+ ))}
+
+
+ );
+};
diff --git a/packages/screens/Projects/defaultValues.ts b/packages/screens/Projects/defaultValues.ts
new file mode 100644
index 0000000000..07f282d5f8
--- /dev/null
+++ b/packages/screens/Projects/defaultValues.ts
@@ -0,0 +1,32 @@
+import {
+ ProjectFormData,
+ ProjectTeamAndLinkFormData,
+} from "./hooks/useMakeRequestHook";
+
+/*
+const emptyTeamAndLink: ProjectTeamAndLinkFormData = {
+ websiteLink: "",
+ twitterProfile: "",
+ discordLink: "",
+ githubLink: "",
+ teamDesc: "",
+};
+*/
+
+export const emptyProjectFormData: ProjectFormData = {
+ creatorAddress: "",
+ name: "",
+ description: "",
+ arbitratorAddress: "",
+ coverImg: "",
+ creatorKind: "contractor",
+ tags: "",
+};
+
+export const fakeTeamAndLink: ProjectTeamAndLinkFormData = {
+ websiteLink: "https://website.com",
+ twitterProfile: "https://twitter.com",
+ discordLink: "https://discord.com",
+ githubLink: "https://github.com",
+ teamDesc: "This is long team description",
+};
diff --git a/packages/screens/Projects/hooks/useEscrowContract.ts b/packages/screens/Projects/hooks/useEscrowContract.ts
new file mode 100644
index 0000000000..bd1a391a80
--- /dev/null
+++ b/packages/screens/Projects/hooks/useEscrowContract.ts
@@ -0,0 +1,98 @@
+import { GnoJSONRPCProvider } from "@gnolang/gno-js-client";
+
+import { useFeedbacks } from "@/context/FeedbacksProvider";
+import {
+ getNetworkFeature,
+ mustGetGnoNetwork,
+ NetworkFeature,
+} from "@/networks";
+import { useUtils } from "@/screens/Projects/hooks/useUtils";
+import { adenaVMCall, extractGnoString } from "@/utils/gno";
+
+export const useEscrowContract = (
+ networkId: string | undefined,
+ walletAddress: string | undefined,
+) => {
+ const { mustGetValue } = useUtils();
+ const { setToastError } = useFeedbacks();
+
+ const _getEscrowInfo = (networkId: string) => {
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+
+ if (!pmFeature) {
+ throw Error("Project Manager is not supported on this network");
+ }
+
+ const gnoNetwork = mustGetGnoNetwork(networkId);
+ const escrowPkgPath = mustGetValue(
+ pmFeature?.projectsManagerPkgPath,
+ "escrow pkg path",
+ );
+
+ return { gnoNetworkEndpoint: gnoNetwork.endpoint, escrowPkgPath };
+ };
+
+ // This will call contract method and get the data
+ const queryEscrow = async (methodName: string, args: any[]) => {
+ if (!networkId) {
+ setToastError({ title: "Error", message: "networkId not given" });
+ return;
+ }
+
+ const { gnoNetworkEndpoint, escrowPkgPath } = _getEscrowInfo(networkId);
+
+ const client = new GnoJSONRPCProvider(gnoNetworkEndpoint);
+ const argsStr = args
+ .map((arg) => (typeof arg === "number" ? arg : `"${arg}"`))
+ .join(",");
+
+ const res = await client.evaluateExpression(
+ escrowPkgPath,
+ `${methodName}(${argsStr})`,
+ );
+
+ return extractGnoString(res);
+ };
+
+ // This will execute the method and does not return result
+ // only through error in case of problem
+ const execEscrowMethod = async (
+ func: string,
+ args: string[],
+ send: string = "",
+ gasWanted: number = 2_000_000,
+ ) => {
+ try {
+ if (!networkId) {
+ setToastError({ title: "Error", message: "networkId not given" });
+ return false;
+ }
+
+ const { escrowPkgPath } = _getEscrowInfo(networkId);
+
+ const caller = mustGetValue(walletAddress, "caller");
+
+ await adenaVMCall(
+ networkId,
+ {
+ caller,
+ send,
+ pkg_path: escrowPkgPath,
+ func,
+ args,
+ },
+ { gasWanted },
+ );
+
+ return true;
+ } catch (e: any) {
+ setToastError({ title: "Error", message: e.message });
+ return false;
+ }
+ };
+
+ return { execEscrowMethod, queryEscrow };
+};
diff --git a/packages/screens/Projects/hooks/useMakeRequestHook.tsx b/packages/screens/Projects/hooks/useMakeRequestHook.tsx
new file mode 100644
index 0000000000..909527e07e
--- /dev/null
+++ b/packages/screens/Projects/hooks/useMakeRequestHook.tsx
@@ -0,0 +1,125 @@
+import { useRoute } from "@react-navigation/native";
+import { useMemo } from "react";
+import { z } from "zod";
+import { create } from "zustand";
+
+import { useAppNavigation } from "../../../utils/navigation";
+import { emptyProjectFormData, fakeTeamAndLink } from "../defaultValues";
+import { MilestoneFormValues } from "../types";
+
+export const zodProjectTeamAndLinkFormData = z.object({
+ websiteLink: z.string().url(),
+ twitterProfile: z.string().url(),
+ discordLink: z.string().url(),
+ githubLink: z.string().url(),
+ teamDesc: z.string(),
+});
+
+export type ProjectTeamAndLinkFormData = z.infer<
+ typeof zodProjectTeamAndLinkFormData
+>;
+
+export const zodProjectFormData = z.object({
+ name: z.string().min(3),
+ description: z.string().min(10),
+ creatorKind: z.enum(["funder", "contractor"]),
+ creatorAddress: z.string().min(1),
+ targetAddress: z.string().min(1).optional(),
+ arbitratorAddress: z.string().min(1),
+ tags: z.string(),
+ coverImg: z.string().min(1), // web3 uri
+});
+
+export type ProjectFormData = z.infer;
+
+type MakeRequestState = {
+ stepIndice: number;
+ projectFormData: ProjectFormData;
+ teamAndLinkData: ProjectTeamAndLinkFormData;
+ milestones: MilestoneFormValues[];
+ actions: {
+ setShortDesc: (shortDescData: ProjectFormData) => void;
+ setTeamAndLink: (teamAndLinkData: ProjectTeamAndLinkFormData) => void;
+
+ addMilestone: (milestone: MilestoneFormValues) => void;
+ removeMilestone: (id: string) => void;
+ };
+};
+
+const TOTAL_STEPS = 5;
+
+const useMakeRequestStore = create((set, get) => ({
+ stepIndice: 1,
+ projectFormData: emptyProjectFormData,
+ teamAndLinkData: fakeTeamAndLink,
+ milestones: [],
+ actions: {
+ setShortDesc: (shortDescData) => set({ projectFormData: shortDescData }),
+ setTeamAndLink: (teamAndLinkData) => {
+ set({ teamAndLinkData });
+ },
+ addMilestone: (milestone) => {
+ const updatedMilestones = [...get().milestones, milestone].map(
+ (t, idx) => {
+ t.id = idx.toString();
+ return t;
+ },
+ );
+
+ set({ milestones: updatedMilestones });
+ },
+ removeMilestone: (id) => {
+ const updatedMilestones = get()
+ .milestones.filter((t) => t.id !== id)
+ .map((t, idx) => {
+ t.id = idx.toString();
+ return t;
+ });
+
+ set({ milestones: updatedMilestones });
+ },
+ },
+}));
+
+export const useMakeRequestState = () => {
+ const navigation = useAppNavigation();
+ const store = useMakeRequestStore();
+ const route = useRoute();
+ const step = !route.params ? 1 : (route.params as any).step;
+
+ const stepIndex = useMemo(() => {
+ try {
+ let res = step ? parseInt(step, 10) : 1;
+ res = Number.isInteger(res) ? res : 1;
+ res = res > 5 || res < 0 ? 1 : res;
+ return res;
+ } catch {
+ return 1;
+ }
+ }, [step]);
+
+ const gotoStep = (stepIndex: number) => {
+ navigation.navigate("ProjectsMakeRequest", { step: stepIndex });
+ };
+
+ const goNextStep = () => {
+ const nextStep = Math.min(stepIndex + 1, TOTAL_STEPS);
+ gotoStep(nextStep);
+ };
+
+ const goPrevStep = () => {
+ const prevStep = Math.max(stepIndex - 1, 1);
+ gotoStep(prevStep);
+ };
+
+ return {
+ ...store,
+ stepIndice: stepIndex,
+ actions: {
+ ...store.actions,
+ goNextStep,
+ goPrevStep,
+ gotoStep,
+ },
+ };
+};
diff --git a/packages/screens/Projects/hooks/useProjects.ts b/packages/screens/Projects/hooks/useProjects.ts
new file mode 100644
index 0000000000..66092791c3
--- /dev/null
+++ b/packages/screens/Projects/hooks/useProjects.ts
@@ -0,0 +1,114 @@
+import { GnoJSONRPCProvider } from "@gnolang/gno-js-client";
+import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
+import { useMemo } from "react";
+import { z } from "zod";
+
+import {
+ NetworkFeature,
+ getGnoNetwork,
+ getNetworkFeature,
+ parseNetworkObjectId,
+} from "../../../networks";
+import { Project, zodProject } from "../types";
+
+import { extractGnoJSONString } from "@/utils/gno";
+
+export const useProject = (projectId: string | undefined) => {
+ return useQuery(
+ ["project", projectId],
+ async () => {
+ const [network, localIdentifierStr] = parseNetworkObjectId(projectId);
+ if (!network || !localIdentifierStr) {
+ return null;
+ }
+
+ const gnoNetwork = getGnoNetwork(network.id);
+ if (!gnoNetwork) {
+ return null;
+ }
+
+ const pmFeature = getNetworkFeature(
+ network.id,
+ NetworkFeature.GnoProjectManager,
+ );
+
+ if (!pmFeature) {
+ return null;
+ }
+
+ const client = new GnoJSONRPCProvider(gnoNetwork.endpoint);
+ const query = `RenderContractJSON(${parseInt(localIdentifierStr, 10)})`;
+ const contractData = await client.evaluateExpression(
+ pmFeature.projectsManagerPkgPath,
+ query,
+ );
+
+ const j = extractGnoJSONString(contractData);
+
+ return zodProject.parse(j);
+ },
+ { staleTime: Infinity },
+ );
+};
+
+export type ProjectFilter =
+ | { byCandidatesForFunder: { funder: string } }
+ | { byFunder: { funder: string } }
+ | { byContractor: { contractor: string } }
+ | { byContractorAndFunder: { contractor: string; funder: string } }
+ | null;
+
+export const useProjects = (
+ networkId: string,
+ filter: ProjectFilter = null,
+) => {
+ const { data, ...other } = useInfiniteQuery<{
+ projects: Project[];
+ nextOffset: number;
+ }>(
+ ["projects", networkId, filter],
+ async ({ pageParam = 0 }) => {
+ const gnoNetwork = getGnoNetwork(networkId);
+ if (!gnoNetwork) {
+ return { projects: [], nextOffset: 0 };
+ }
+
+ const pmFeature = getNetworkFeature(
+ networkId,
+ NetworkFeature.GnoProjectManager,
+ );
+ if (!pmFeature) {
+ return { projects: [], nextOffset: 0 };
+ }
+
+ const client = new GnoJSONRPCProvider(gnoNetwork.endpoint);
+
+ const limit = 12;
+
+ const pkgPath = pmFeature.projectsManagerPkgPath;
+ const expr = `RenderContractsJSON(${pageParam},${limit},${JSON.stringify(JSON.stringify(filter))})`;
+
+ const contractsData = await client.evaluateExpression(pkgPath, expr);
+
+ const j = extractGnoJSONString(contractsData);
+
+ const projects = z.array(zodProject).parse(j);
+
+ return {
+ projects,
+ nextOffset: pageParam + projects.length,
+ };
+ },
+ {
+ staleTime: Infinity,
+ getNextPageParam: ({ nextOffset }) => nextOffset,
+ },
+ );
+
+ const projects = useMemo(() => {
+ if (!data) return [];
+ return data.pages.flatMap((page) => page.projects);
+ }, [data]);
+
+ return { projects, ...other };
+};
diff --git a/packages/screens/Projects/hooks/useUtils.ts b/packages/screens/Projects/hooks/useUtils.ts
new file mode 100644
index 0000000000..33951febea
--- /dev/null
+++ b/packages/screens/Projects/hooks/useUtils.ts
@@ -0,0 +1,20 @@
+import { useFeedbacks } from "../../../context/FeedbacksProvider";
+
+export const useUtils = () => {
+ const { setToast } = useFeedbacks();
+
+ const mustGetValue = (value?: string, name?: string) => {
+ if (!value) {
+ setToast({
+ title: "Error",
+ type: "error",
+ mode: "normal",
+ message: `failed to get ${name || "value"}`,
+ });
+ throw Error(`failed to get ${name || "value"}`);
+ }
+ return value;
+ };
+
+ return { mustGetValue };
+};
diff --git a/packages/screens/Projects/types.ts b/packages/screens/Projects/types.ts
new file mode 100644
index 0000000000..dd3bf39376
--- /dev/null
+++ b/packages/screens/Projects/types.ts
@@ -0,0 +1,160 @@
+import * as zod from "zod";
+import { z } from "zod";
+
+import { zodTryParseJSON } from "@/utils/sanitize";
+
+const zodMilestonePriority = z.enum([
+ "MS_PRIORITY_HIGH",
+ "MS_PRIORITY_MEDIUM",
+ "MS_PRIORITY_LOW",
+]);
+
+export type MilestonePriority = z.infer;
+
+export const zodMilestoneFormValues = zod.object({
+ id: zod.string().optional(),
+ title: zod
+ .string()
+ .min(3)
+ .regex(/^[^,]*$/, "Should not contain ,"),
+ desc: zod
+ .string()
+ .min(10)
+ .regex(/^[^,]*$/, "Should not contain ,"),
+ amount: zod.number().positive().int(),
+ priority: zodMilestonePriority,
+ link: zod.string().url().optional(),
+ duration: zod.number().min(1),
+});
+
+export type MilestoneFormValues = zod.infer;
+
+export interface MilestoneRequest {
+ title: string;
+ desc: string;
+ amount: string;
+ duration: string;
+ link: string;
+ priority: string;
+}
+
+export const zodMilestoneStatus = z.enum([
+ "MS_OPEN",
+ "MS_PROGRESS",
+ "MS_REVIEW",
+ "MS_COMPLETED",
+]);
+
+export type MilestoneStatus = z.infer;
+
+const zodProjectMilestone = z.object({
+ id: z.string(),
+ title: z.string(),
+ desc: z.string(),
+ amount: z.string(),
+ paid: z.string(),
+ duration: z.number(), // seconds
+ link: z.string(),
+ funded: z.boolean(),
+ priority: zodMilestonePriority,
+ status: zodMilestoneStatus,
+});
+
+export type ProjectMilestone = z.infer;
+
+export const previewMilestoneForm = (fm: MilestoneFormValues) => {
+ const m: ProjectMilestone = {
+ ...fm,
+ id: fm.id || "",
+ status: "MS_OPEN",
+ paid: "0",
+ amount: fm.amount.toString(),
+ link: fm.link || "",
+ funded: false,
+ };
+ return m;
+};
+
+const zodContractStatus = z.enum([
+ "CREATED",
+ "ACCEPTED",
+ "CANCELED",
+ "COMPLETED",
+ "REJECTED",
+ "CONFLICT",
+ "ABORTED_IN_FAVOR_OF_CONTRACTOR",
+ "ABORTED_IN_FAVOR_OF_FUNDER",
+]);
+
+type ContractStatus = z.infer;
+
+export type ContractStatusFilter = ContractStatus | "ALL";
+
+const zodConflictOutcome = z.enum([
+ "RESUME_CONTRACT",
+ "REFUND_FUNDER",
+ "PAY_CONTRACTOR",
+]);
+
+const zodConflict = z.object({
+ initiator: z.string(),
+ createdAt: z.coerce.date(),
+ respondedAt: z.coerce.date().optional(),
+ resolvedAt: z.coerce.date().optional(),
+ initiatorMessage: z.string(),
+ responseMessage: z.string().optional(),
+ resolutionMessage: z.string().optional(),
+ outcome: zodConflictOutcome.optional(),
+});
+
+const zodProjectShortDescData = z.object({
+ name: z.string().optional(),
+ desc: z.string().optional(),
+ coverImg: z.string().optional(),
+ tags: z.string().optional(),
+});
+
+export type ProjectShortDescData = z.infer;
+
+const zodProjectTeamAndLinkData = z.object({
+ websiteLink: z.string().optional(),
+ twitterProfile: z.string().optional(),
+ discordLink: z.string().optional(),
+ githubLink: z.string().optional(),
+ teamDesc: z.string().optional(),
+});
+
+export type ProjectTeamAndLinkData = z.infer;
+
+const zodProjectMetadata = z.object({
+ shortDescData: zodProjectShortDescData.optional(),
+ teamAndLinkData: zodProjectTeamAndLinkData.optional(),
+});
+
+export const zodProject = z.object({
+ id: z.string(),
+ sender: z.string(),
+ contractor: z.string(),
+ contractorCandidates: z.array(z.string()),
+ funder: z.string(),
+ paymentDenom: z.string(),
+ metadata: z
+ .string()
+ .transform((data) => zodTryParseJSON(zodProjectMetadata, data)),
+ status: zodContractStatus,
+ expireAt: z.coerce.date(),
+ funderFeedback: z.string(),
+ contractorFeedback: z.string(),
+ milestones: z.array(zodProjectMilestone),
+ pausedBy: z.string(),
+ conflictHandler: z.string(),
+ handlerCandidate: z.string(),
+ handlerSuggestor: z.string(),
+ createdAt: z.coerce.date(),
+ budget: z.string(),
+ funded: z.boolean(),
+ rejectReason: z.string(),
+ conflicts: z.array(zodConflict),
+});
+
+export type Project = z.infer;
diff --git a/packages/screens/Projects/utils.ts b/packages/screens/Projects/utils.ts
new file mode 100644
index 0000000000..0dead50bc6
--- /dev/null
+++ b/packages/screens/Projects/utils.ts
@@ -0,0 +1,12 @@
+import { Project } from "./types";
+
+export const getProjectStats = (project: Project) => {
+ if (!project.milestones)
+ return { completed: 0, total: 0, percentCompleted: 0 };
+ const completed = project.milestones.filter(
+ (ms) => ms.status === "MS_COMPLETED",
+ ).length;
+ const total = project.milestones.length;
+ const percentCompleted = Math.floor((completed / total) * 100);
+ return { completed, total, percentCompleted };
+};
diff --git a/packages/screens/RiotGame/RiotGameEnrollScreen.tsx b/packages/screens/RiotGame/RiotGameEnrollScreen.tsx
index 25d44550db..f10c954cca 100644
--- a/packages/screens/RiotGame/RiotGameEnrollScreen.tsx
+++ b/packages/screens/RiotGame/RiotGameEnrollScreen.tsx
@@ -9,7 +9,6 @@ import { useSelector } from "react-redux";
import { EnrollSlot } from "./component/EnrollSlot";
import { GameContentView } from "./component/GameContentView";
import { RipperSelectorModal } from "./component/RipperGridSelectorModal";
-import { SimpleButton } from "./component/SimpleButton";
import controllerSVG from "../../../assets/game/controller-yellow.svg";
import closeSVG from "../../../assets/icons/close.svg";
import useSelectedWallet from "../../hooks/useSelectedWallet";
@@ -18,6 +17,7 @@ import { NFT } from "@/api/marketplace/v1/marketplace";
import { BrandText } from "@/components/BrandText";
import { SVG } from "@/components/SVG";
import { LegacyTertiaryBox } from "@/components/boxes/LegacyTertiaryBox";
+import { SimpleButton } from "@/components/buttons/SimpleButton";
import { TertiaryButton } from "@/components/buttons/TertiaryButton";
import { useFeedbacks } from "@/context/FeedbacksProvider";
import { useAppNavigation } from "@/hooks/navigation/useAppNavigation";
diff --git a/packages/screens/RiotGame/component/FightSectionHeader.tsx b/packages/screens/RiotGame/component/FightSectionHeader.tsx
index ca09a341f7..e3ae5e4e8b 100644
--- a/packages/screens/RiotGame/component/FightSectionHeader.tsx
+++ b/packages/screens/RiotGame/component/FightSectionHeader.tsx
@@ -1,11 +1,11 @@
import React from "react";
import { StyleSheet, View } from "react-native";
-import { SimpleButton } from "./SimpleButton";
import addCircleSVG from "../../../../assets/icons/add-circle.svg";
import FlexRow from "../../../components/FlexRow";
import { BrandText } from "@/components/BrandText";
+import { SimpleButton } from "@/components/buttons/SimpleButton";
import { useAppNavigation } from "@/hooks/navigation/useAppNavigation";
import { neutral17, yellowDefault } from "@/utils/style/colors";
import { fontMedium48, fontSemibold28 } from "@/utils/style/fonts";
diff --git a/packages/screens/RiotGame/component/RipperGridSelectorModal.tsx b/packages/screens/RiotGame/component/RipperGridSelectorModal.tsx
index 486977a8c4..87c9b9b7b0 100644
--- a/packages/screens/RiotGame/component/RipperGridSelectorModal.tsx
+++ b/packages/screens/RiotGame/component/RipperGridSelectorModal.tsx
@@ -13,7 +13,6 @@ import { TouchableOpacity } from "react-native-gesture-handler";
import { RipperAvatar } from "./RipperAvatar";
import { RipperStatsSection } from "./RipperStatsSection";
-import { SimpleButton } from "./SimpleButton";
import controllerSVG from "../../../../assets/game/controller.svg";
import dashedBorderPNG from "../../../../assets/game/dashed-border.png";
import closeSVG from "../../../../assets/icons/close.svg";
@@ -23,6 +22,7 @@ import { NFT } from "@/api/marketplace/v1/marketplace";
import { BrandText } from "@/components/BrandText";
import { SVG } from "@/components/SVG";
import { LegacyTertiaryBox } from "@/components/boxes/LegacyTertiaryBox";
+import { SimpleButton } from "@/components/buttons/SimpleButton";
import { SpacerRow } from "@/components/spacer";
import { useIsMobile } from "@/hooks/useIsMobile";
import { getRipperRarity, isNFTStaked } from "@/utils/game";
diff --git a/packages/screens/RiotGame/component/RipperSelectorModal.tsx b/packages/screens/RiotGame/component/RipperSelectorModal.tsx
index de66b52f93..6c3208e2d8 100644
--- a/packages/screens/RiotGame/component/RipperSelectorModal.tsx
+++ b/packages/screens/RiotGame/component/RipperSelectorModal.tsx
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
import {
Modal,
ModalProps,
- StyleSheet,
+ ViewStyle,
View,
ImageBackground,
ScrollView,
@@ -12,7 +12,6 @@ import {
import { AvailableRippersGrid } from "./AvailableRippersGrid";
import { RipperAvatar } from "./RipperAvatar";
import { RipperStatsSection } from "./RipperStatsSection";
-import { SimpleButton } from "./SimpleButton";
import controllerSVG from "../../../../assets/game/controller.svg";
import dashedBorderPNG from "../../../../assets/game/dashed-border.png";
import closeSVG from "../../../../assets/icons/close.svg";
@@ -21,6 +20,7 @@ import FlexRow from "../../../components/FlexRow";
import { NFT } from "@/api/marketplace/v1/marketplace";
import { BrandText } from "@/components/BrandText";
import { SVG } from "@/components/SVG";
+import { SimpleButton } from "@/components/buttons/SimpleButton";
import { SpacerRow } from "@/components/spacer";
import { useBreeding } from "@/hooks/riotGame/useBreeding";
import { useIsMobile } from "@/hooks/useIsMobile";
@@ -89,8 +89,8 @@ export const RipperSelectorModal: React.FC = ({
visible={visible}
{...props}
>
-
-
+
+
@@ -120,7 +120,7 @@ export const RipperSelectorModal: React.FC = ({
/>
-
+
= ({
@@ -172,38 +172,38 @@ export const RipperSelectorModal: React.FC = ({
);
};
-// FIXME: remove StyleSheet.create
-// eslint-disable-next-line no-restricted-syntax
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: withAlpha(neutral00, 0.95),
- paddingTop: headerHeight,
- borderWidth: 1,
- },
- dashedBorder: {
- width: RIPPER_IMAGE_SIZE,
- height: RIPPER_IMAGE_SIZE,
- marginTop: layout.spacing_x2_5,
- },
- roundedContainer: {
- width: RIPPER_IMAGE_SIZE - 4,
- height: RIPPER_IMAGE_SIZE - 4,
- position: "absolute",
- left: 2,
- top: 2,
- borderRadius: 999,
- overflow: "hidden",
- },
- btnGroup: {
- marginTop: layout.spacing_x2_5,
- flexDirection: "row",
- alignSelf: "center",
- },
- closeIcon: {
- position: "absolute",
- right: 10,
- top: 10,
- zIndex: 1,
- },
-});
+const styleContainer: ViewStyle = {
+ flex: 1,
+ backgroundColor: withAlpha(neutral00, 0.95),
+ paddingTop: headerHeight,
+ borderWidth: 1,
+};
+
+const styleDashedBorder: ViewStyle = {
+ width: RIPPER_IMAGE_SIZE,
+ height: RIPPER_IMAGE_SIZE,
+ marginTop: layout.spacing_x2_5,
+};
+
+const styleRoundedContainer: ViewStyle = {
+ width: RIPPER_IMAGE_SIZE - 4,
+ height: RIPPER_IMAGE_SIZE - 4,
+ position: "absolute",
+ left: 2,
+ top: 2,
+ borderRadius: 999,
+ overflow: "hidden",
+};
+
+const styleBtnGroup: ViewStyle = {
+ marginTop: layout.spacing_x2_5,
+ flexDirection: "row",
+ alignSelf: "center",
+};
+
+const styleCloseIcon: ViewStyle = {
+ position: "absolute",
+ right: 10,
+ top: 10,
+ zIndex: 1,
+};
diff --git a/packages/screens/Settings/SettingsScreen.tsx b/packages/screens/Settings/SettingsScreen.tsx
index bdcf8e0eb8..5deec15b2e 100644
--- a/packages/screens/Settings/SettingsScreen.tsx
+++ b/packages/screens/Settings/SettingsScreen.tsx
@@ -96,6 +96,7 @@ export const SettingsScreen: ScreenFC<"Settings"> = () => {
description: "",
state: testnetEnabled,
}}
+ testID="testnet-switch"
/>
diff --git a/packages/screens/Settings/components/SettingItem.tsx b/packages/screens/Settings/components/SettingItem.tsx
index 86f442b701..279f0d4884 100644
--- a/packages/screens/Settings/components/SettingItem.tsx
+++ b/packages/screens/Settings/components/SettingItem.tsx
@@ -12,11 +12,16 @@ export const SettingItem: React.FC<{
item: SettingItemType;
onPress: (item: SettingItemType) => void;
disabled?: boolean;
-}> = ({ item, onPress, disabled }) => {
+ testID?: string;
+}> = ({ item, onPress, disabled, testID }) => {
const commonStyles = useCommonStyles();
return (
- onPress(item)} disabled={disabled}>
+ onPress(item)}
+ disabled={disabled}
+ testID={testID}
+ >
{item.title}
diff --git a/packages/scripts/addrFromMnemo.ts b/packages/scripts/addrFromMnemo.ts
new file mode 100644
index 0000000000..bea781710f
--- /dev/null
+++ b/packages/scripts/addrFromMnemo.ts
@@ -0,0 +1,27 @@
+import { GnoWallet } from "@gnolang/gno-js-client";
+import { program } from "commander";
+
+import { NetworkKind, getNetwork } from "@/networks";
+
+const main = async () => {
+ program.option("-n, --network ", "network");
+ program.option("-m, --mnemonic ", "mnemonic");
+ program.parse();
+ const { network: networkId, mnemonic } = program.opts() as {
+ network: string;
+ mnemonic: string;
+ };
+ const network = getNetwork(networkId);
+ if (!network) {
+ console.error(`Network "${networkId}" not found`);
+ return;
+ }
+ if (network.kind !== NetworkKind.Gno) {
+ console.error(`Only Gno networks are supported for now`);
+ }
+ const wallet = await GnoWallet.fromMnemonic(mnemonic);
+ const address = await wallet.getAddress();
+ console.log(address);
+};
+
+main();
diff --git a/packages/scripts/gnoQuery.ts b/packages/scripts/gnoQuery.ts
index 8a6f26f31c..779611a8b2 100644
--- a/packages/scripts/gnoQuery.ts
+++ b/packages/scripts/gnoQuery.ts
@@ -1,22 +1,34 @@
-import { GnoJSONRPCProvider } from "@gnolang/gno-js-client";
+import child_process from "child_process";
import { program } from "commander";
-import { gnoTeritoriNetwork } from "../networks/gno-teritori";
+import sqh from "./sqh";
+
+import { getGnoNetwork } from "@/networks";
const main = async () => {
+ program.argument("network-id", "network id");
program.argument("realm", "realm pkg path");
program.argument("query", "eval query");
program.parse();
- const [realm, query] = program.args as [string, string];
-
- const network = gnoTeritoriNetwork;
- const provider = new GnoJSONRPCProvider(network.endpoint);
- try {
- const rawRes = await provider.evaluateExpression(realm, query);
- console.log(rawRes);
- } catch (e) {
- console.error(JSON.stringify(e));
+ const [networkId, realm, query] = program.args as [string, string, string];
+
+ const network = getGnoNetwork(networkId);
+ if (!network) {
+ console.error(`Network "${networkId}" not found`);
+ return;
+ }
+
+ if (!realm) {
+ console.log("missing realm argument");
}
+
+ if (!query) {
+ console.log("missing query argument");
+ }
+
+ const cmd = `gnokey query vm/qeval -remote ${sqh(network.endpoint)} -data ${sqh(`${realm}.${query}`)}`;
+ console.log("> " + cmd);
+ child_process.execSync(cmd, { stdio: "inherit" });
};
main();
diff --git a/packages/scripts/inject-projects.ts b/packages/scripts/inject-projects.ts
new file mode 100644
index 0000000000..457682acbd
--- /dev/null
+++ b/packages/scripts/inject-projects.ts
@@ -0,0 +1,113 @@
+import { faker } from "@faker-js/faker";
+import * as child_process from "child_process";
+import { program } from "commander";
+import { capitalize, range } from "lodash";
+
+import sqh from "./sqh";
+
+import { NetworkFeature, getGnoNetwork, getNetworkFeature } from "@/networks";
+
+const main = async () => {
+ program
+ .option("-n, --network ", "Network ID")
+ .option("-w, --wallet ", "Wallet name")
+ .option("-c, --count ", "Number of projects to create")
+ .parse();
+
+ const opts = program.opts() as {
+ network: string;
+ wallet: string;
+ count: string;
+ };
+
+ const count = parseInt(opts.count, 10);
+ if (isNaN(count) || count <= 0) {
+ throw new Error("Invalid count");
+ }
+
+ const network = getGnoNetwork(opts.network);
+ if (!network) {
+ throw new Error("Network not found");
+ }
+ const pmFeature = getNetworkFeature(
+ network.id,
+ NetworkFeature.GnoProjectManager,
+ );
+ if (!pmFeature) {
+ throw new Error("Project manager feature not found");
+ }
+
+ console.log(
+ `Creating ${count} projects on ${network.displayName} with ${opts.wallet} wallet`,
+ );
+
+ for (let i = 0; i < count; i++) {
+ const teamAndLinkData: Record = {};
+
+ if (faker.helpers.maybe(() => true)) {
+ teamAndLinkData.websiteLink = faker.internet.url();
+ }
+ if (faker.helpers.maybe(() => true)) {
+ teamAndLinkData.twitterProfile =
+ "@" + faker.person.firstName().toLowerCase();
+ }
+ if (faker.helpers.maybe(() => true)) {
+ teamAndLinkData.discordLink = "https://discord.com";
+ }
+ if (faker.helpers.maybe(() => true)) {
+ teamAndLinkData.githubLink =
+ "https://github.com/" + faker.person.firstName().toLowerCase();
+ }
+ if (faker.helpers.maybe(() => true)) {
+ teamAndLinkData.teamDesc = faker.lorem.paragraph();
+ }
+
+ const metadata = {
+ shortDescData: {
+ name: faker.lorem.sentence(3).slice(0, -1),
+ desc:
+ capitalize(faker.hacker.phrase()) +
+ "\n\n" +
+ faker.lorem.paragraphs(10),
+ tags: [
+ ...new Set(
+ range(0, faker.number.int({ min: 3, max: 10 })).map(() =>
+ faker.hacker.noun(),
+ ),
+ ),
+ ].join(","),
+ coverImg: faker.image.urlPicsumPhotos(),
+ },
+ teamAndLinkData,
+ };
+
+ const milestones = [];
+ for (let j = 0; j < faker.number.int({ min: 3, max: 6 }); j++) {
+ milestones.push({
+ title: faker.lorem.sentence(3).slice(0, -1),
+ desc: faker.lorem.paragraphs(3),
+ priority: faker.helpers.arrayElement([
+ "MS_PRIORITY_HIGH",
+ "MS_PRIORITY_MEDIUM",
+ "MS_PRIORITY_LOW",
+ ]),
+ amount: faker.number
+ .bigInt({ min: "420000", max: "4200000" })
+ .toString(),
+ duration: faker.number.bigInt({ min: "3600", max: "36000" }).toString(),
+ link: faker.internet.url(),
+ });
+ }
+
+ const totalPrice = milestones.reduce(
+ (acc, m) => acc + BigInt(m.amount),
+ BigInt(0),
+ );
+
+ const cmd = `gnokey maketx call -insecure-password-stdin -pkgpath ${sqh(pmFeature.projectsManagerPkgPath)} -func "CreateContractJSON" -gas-fee 1000000ugnot -gas-wanted 10000000 -send "${totalPrice}ugnot" -broadcast -chainid ${sqh(network.chainId)} -args "" -args "g1xfjfdfyka23agew9g6qst030pr85q0ggac7vuj" -args ${sqh(pmFeature.paymentsDenom)} -args ${sqh(JSON.stringify(metadata))} -args "200000" -args ${sqh(JSON.stringify(milestones))} -args "g108cszmcvs4r3k67k7h5zuhm4el3qhlrxzhshtv" -remote ${sqh(network.endpoint)} ${sqh(opts.wallet)}`;
+ console.log(">", cmd);
+ child_process.execSync(cmd, { input: "\n" });
+ }
+};
+
+main();
diff --git a/packages/scripts/install-gno.ts b/packages/scripts/install-gno.ts
new file mode 100644
index 0000000000..66db6555c3
--- /dev/null
+++ b/packages/scripts/install-gno.ts
@@ -0,0 +1,18 @@
+import child_process from "child_process";
+import fs from "fs/promises";
+import os from "os";
+import path from "path";
+
+import sqh from "./sqh";
+
+const ref = "fec2d18f630b44ccc2121472aa2284cd9c8caf6f";
+const remote = "https://github.com/gnolang/gno.git";
+
+const main = async () => {
+ const buildDir = await fs.mkdtemp(path.join(os.tmpdir(), "gno-build-"));
+ const cmd = `git clone ${sqh(remote)} ${sqh(buildDir)} && cd ${sqh(buildDir)} && git checkout ${sqh(ref)} && make install`;
+ console.log(">", cmd);
+ child_process.execSync(cmd, { stdio: "inherit" });
+};
+
+main();
diff --git a/packages/scripts/validateNetworks.ts b/packages/scripts/validateNetworks.ts
index 13d81ed592..37fae66237 100644
--- a/packages/scripts/validateNetworks.ts
+++ b/packages/scripts/validateNetworks.ts
@@ -1,5 +1,7 @@
import { allNetworks, getNativeCurrency, NetworkKind } from "../networks";
+import { allFeatureObjects } from "@/networks/features";
+
const ids: { [key: string]: boolean } = {};
const idPrefixes: { [key: string]: boolean } = {};
const cosmosChainIds: { [key: string]: boolean } = {};
@@ -94,6 +96,22 @@ for (const net of allNetworks) {
`feature object '${feature.type}' of network '${net.id}' does not have a corresponding feature declaration`,
);
}
+ const zodFeatureObj = allFeatureObjects.find(
+ (zo) => zo.shape.type.value === feature.type,
+ );
+ if (!zodFeatureObj) {
+ throw new Error(
+ `feature object '${feature.type}' of network '${net.id}' does not have a corresponding zod declaration`,
+ );
+ }
+ try {
+ zodFeatureObj.parse(feature);
+ } catch (e) {
+ const msg = e instanceof Error ? e.message : JSON.stringify(e, null, 2);
+ throw new Error(
+ `feature object '${feature.type}' of network '${net.id}' does not match the zod declaration: ${msg}`,
+ );
+ }
featureObjects[feature.type] = true;
}
}
diff --git a/packages/utils/gno.ts b/packages/utils/gno.ts
index 99612d9f86..ca966e119d 100644
--- a/packages/utils/gno.ts
+++ b/packages/utils/gno.ts
@@ -7,7 +7,7 @@ interface AdenaDoContractMessage {
value: { [key in string]: any };
}
-interface RequestDocontractMessage {
+export interface RequestDocontractMessage {
messages: AdenaDoContractMessage[];
gasFee: number;
gasWanted: number;
diff --git a/packages/utils/navigation.ts b/packages/utils/navigation.ts
index 5b410d972f..b8309a3a87 100644
--- a/packages/utils/navigation.ts
+++ b/packages/utils/navigation.ts
@@ -82,6 +82,14 @@ export type RootStackParamList = {
Settings: undefined;
+ Projects?: { network?: string };
+ ProjectsManager: { view?: string };
+ ProjectsPayment: { projectId: string; milestoneId: string };
+ ProjectsCompleteMilestone: { projectId: string; milestoneId: string };
+ ProjectsMakeRequest: { step?: number };
+ ProjectsDetail: { id: string };
+ ProjectsConflictSolving: { projectId: string };
+
OrganizationDeployer: undefined;
Organizations?: { network?: string };
CoreDAO: undefined;
@@ -230,6 +238,15 @@ const navConfig: {
Organizations: "orgs",
CoreDAO: "core-dao",
+ // === Projects Program
+ Projects: "projects",
+ ProjectsPayment: "projects/payment",
+ ProjectsCompleteMilestone:
+ "projects/completeMilestone/:projectId/:milestoneId",
+ ProjectsManager: "projects/manager/:view",
+ ProjectsMakeRequest: "projects/make-request",
+ ProjectsDetail: "projects/:id",
+ ProjectsConflictSolving: "projects/:projectId/conflicts",
// === Organization
OrganizationGetStarted: "organization-get-started",
diff --git a/packages/utils/sidebar.ts b/packages/utils/sidebar.ts
index 05b2227334..ecd93d68d5 100644
--- a/packages/utils/sidebar.ts
+++ b/packages/utils/sidebar.ts
@@ -12,6 +12,7 @@ import messagesSVG from "../../assets/icons/messages.svg";
import multisigSVG from "../../assets/icons/multisig.svg";
import osmosisCircleSVG from "../../assets/icons/networks/osmosis-circle.svg";
import pathwarSVG from "../../assets/icons/pathwar.svg";
+import projectsProgramSVG from "../../assets/icons/projects-program.svg";
import riotersGameSVG from "../../assets/icons/rioters-game.svg";
import stakingSVG from "../../assets/icons/staking.svg";
import tnsServiceSVG from "../../assets/icons/tns-service.svg";
@@ -123,6 +124,12 @@ export const SIDEBAR_LIST: SidebarRecordType = {
route: "RiotGame",
icon: riotersGameSVG,
},
+ projectsProgram: {
+ title: "Projects Program",
+ id: "Projects Program",
+ route: "Projects",
+ icon: projectsProgramSVG,
+ },
riotersFooter: {
title: "Rioters Footer",
id: "Rioters Footer",
diff --git a/packages/utils/style/colors.ts b/packages/utils/style/colors.ts
index e88e9fb716..da6c983192 100644
--- a/packages/utils/style/colors.ts
+++ b/packages/utils/style/colors.ts
@@ -42,6 +42,7 @@ export const neutral77 = "#777777";
export const neutral88 = "#888888";
export const neutral99 = "#999999";
export const neutralA3 = "#A3A3A3";
+export const neutralFF = "#FFFFFF";
export const transparentColor = "transparent";
export const additionalRed = "#FFAEAE";
diff --git a/packages/utils/types/dapp-store.ts b/packages/utils/types/dapp-store.ts
index 4dc08b1fe9..c58082f197 100644
--- a/packages/utils/types/dapp-store.ts
+++ b/packages/utils/types/dapp-store.ts
@@ -13,6 +13,7 @@ export interface dAppType {
selectedByDefault: boolean;
alwaysOn: boolean;
order?: number;
+ devOnly?: boolean;
}
export interface dAppGroup {
diff --git a/packages/utils/wallet/getNativeWallet.ts b/packages/utils/wallet/getNativeWallet.ts
index aac55fe3ae..2480aa6a93 100644
--- a/packages/utils/wallet/getNativeWallet.ts
+++ b/packages/utils/wallet/getNativeWallet.ts
@@ -1,5 +1,5 @@
import { Secp256k1HdWallet } from "@cosmjs/amino";
-import { stringToPath } from "@cosmjs/amino/node_modules/@cosmjs/crypto/build/slip10";
+import { stringToPath } from "@cosmjs/crypto";
import { getValueFor, remove, save } from "./secure-store";
diff --git a/packages/utils/walletProvider.ts b/packages/utils/walletProvider.ts
index 2fa980676c..e9554fb221 100644
--- a/packages/utils/walletProvider.ts
+++ b/packages/utils/walletProvider.ts
@@ -6,4 +6,5 @@ export enum WalletProvider {
Adena = "Adena",
Store = "Store",
Native = "Native",
+ Gnotest = "Gnotest",
}
diff --git a/paralint.json b/paralint.json
index 83e70cc65b..c979d64a46 100644
--- a/paralint.json
+++ b/paralint.json
@@ -1,6 +1,6 @@
{
"eslint": "eslint --cache --ext .js,.jsx,.ts,.tsx .",
- "tsc": "tsc",
+ "tsc": "tsc --pretty",
"depcheck": "depcheck",
"unused-exports": "yarn unused-exports",
"validate-networks": "yarn validate-networks",
diff --git a/tsconfig.json b/tsconfig.json
index f37d0c7b51..c838cfa151 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"extends": "expo/tsconfig.base",
- "target": "ES5",
+ "target": "ES6",
"compilerOptions": {
"useDefineForClassFields": false, // this is needed by cosmwasm-ts-codegen clients
"strict": true,
diff --git a/yarn.lock b/yarn.lock
index 299fa27f09..fd2b420606 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2170,6 +2170,13 @@ __metadata:
languageName: node
linkType: hard
+"@colors/colors@npm:1.5.0":
+ version: 1.5.0
+ resolution: "@colors/colors@npm:1.5.0"
+ checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425
+ languageName: node
+ linkType: hard
+
"@confio/ics23@npm:^0.6.8":
version: 0.6.8
resolution: "@confio/ics23@npm:0.6.8"
@@ -2288,6 +2295,21 @@ __metadata:
languageName: node
linkType: hard
+"@cosmjs/crypto@npm:0.32.2, @cosmjs/crypto@npm:^0.32.2":
+ version: 0.32.2
+ resolution: "@cosmjs/crypto@npm:0.32.2"
+ dependencies:
+ "@cosmjs/encoding": ^0.32.2
+ "@cosmjs/math": ^0.32.2
+ "@cosmjs/utils": ^0.32.2
+ "@noble/hashes": ^1
+ bn.js: ^5.2.0
+ elliptic: ^6.5.4
+ libsodium-wrappers-sumo: ^0.7.11
+ checksum: 7600bd48f718b8c352038bf96af325b9597310ccf51d2885bba4603a567b52d59446d193288f519ddf354a8668bd0ffba899c518642b3c9bb039bf24a7261faa
+ languageName: node
+ linkType: hard
+
"@cosmjs/crypto@npm:^0.29.3, @cosmjs/crypto@npm:^0.29.5":
version: 0.29.5
resolution: "@cosmjs/crypto@npm:0.29.5"
@@ -2318,21 +2340,6 @@ __metadata:
languageName: node
linkType: hard
-"@cosmjs/crypto@npm:^0.32.2":
- version: 0.32.2
- resolution: "@cosmjs/crypto@npm:0.32.2"
- dependencies:
- "@cosmjs/encoding": ^0.32.2
- "@cosmjs/math": ^0.32.2
- "@cosmjs/utils": ^0.32.2
- "@noble/hashes": ^1
- bn.js: ^5.2.0
- elliptic: ^6.5.4
- libsodium-wrappers-sumo: ^0.7.11
- checksum: 7600bd48f718b8c352038bf96af325b9597310ccf51d2885bba4603a567b52d59446d193288f519ddf354a8668bd0ffba899c518642b3c9bb039bf24a7261faa
- languageName: node
- linkType: hard
-
"@cosmjs/crypto@npm:^0.32.4":
version: 0.32.4
resolution: "@cosmjs/crypto@npm:0.32.4"
@@ -2359,6 +2366,17 @@ __metadata:
languageName: node
linkType: hard
+"@cosmjs/encoding@npm:0.32.2, @cosmjs/encoding@npm:^0.32.2":
+ version: 0.32.2
+ resolution: "@cosmjs/encoding@npm:0.32.2"
+ dependencies:
+ base64-js: ^1.3.0
+ bech32: ^1.1.4
+ readonly-date: ^1.0.0
+ checksum: a9ee00b730aa7f422cf3946097cb96a0c9d5d7a9f6b3aa31d8e96e4f815220928226ae2133b76e835c781df0231e9691c8ebf1c98f68468e2f936a1d431e4c30
+ languageName: node
+ linkType: hard
+
"@cosmjs/encoding@npm:^0.20.0":
version: 0.20.1
resolution: "@cosmjs/encoding@npm:0.20.1"
@@ -2392,17 +2410,6 @@ __metadata:
languageName: node
linkType: hard
-"@cosmjs/encoding@npm:^0.32.2":
- version: 0.32.2
- resolution: "@cosmjs/encoding@npm:0.32.2"
- dependencies:
- base64-js: ^1.3.0
- bech32: ^1.1.4
- readonly-date: ^1.0.0
- checksum: a9ee00b730aa7f422cf3946097cb96a0c9d5d7a9f6b3aa31d8e96e4f815220928226ae2133b76e835c781df0231e9691c8ebf1c98f68468e2f936a1d431e4c30
- languageName: node
- linkType: hard
-
"@cosmjs/encoding@npm:^0.32.4":
version: 0.32.4
resolution: "@cosmjs/encoding@npm:0.32.4"
@@ -2493,6 +2500,15 @@ __metadata:
languageName: node
linkType: hard
+"@cosmjs/math@npm:0.32.2, @cosmjs/math@npm:^0.32.2":
+ version: 0.32.2
+ resolution: "@cosmjs/math@npm:0.32.2"
+ dependencies:
+ bn.js: ^5.2.0
+ checksum: 3ea9c811d1b53b61f24c10ae4e3707fb7f926194202e5c57ea5aa1a41996ffc872ce5599967f74cc6f289d30e064d372b7ff30c1128d682847b865ca597aca59
+ languageName: node
+ linkType: hard
+
"@cosmjs/math@npm:^0.20.0":
version: 0.20.1
resolution: "@cosmjs/math@npm:0.20.1"
@@ -2520,15 +2536,6 @@ __metadata:
languageName: node
linkType: hard
-"@cosmjs/math@npm:^0.32.2":
- version: 0.32.2
- resolution: "@cosmjs/math@npm:0.32.2"
- dependencies:
- bn.js: ^5.2.0
- checksum: 3ea9c811d1b53b61f24c10ae4e3707fb7f926194202e5c57ea5aa1a41996ffc872ce5599967f74cc6f289d30e064d372b7ff30c1128d682847b865ca597aca59
- languageName: node
- linkType: hard
-
"@cosmjs/math@npm:^0.32.4":
version: 0.32.4
resolution: "@cosmjs/math@npm:0.32.4"
@@ -2915,6 +2922,42 @@ __metadata:
languageName: node
linkType: hard
+"@cypress/request@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "@cypress/request@npm:3.0.1"
+ dependencies:
+ aws-sign2: ~0.7.0
+ aws4: ^1.8.0
+ caseless: ~0.12.0
+ combined-stream: ~1.0.6
+ extend: ~3.0.2
+ forever-agent: ~0.6.1
+ form-data: ~2.3.2
+ http-signature: ~1.3.6
+ is-typedarray: ~1.0.0
+ isstream: ~0.1.2
+ json-stringify-safe: ~5.0.1
+ mime-types: ~2.1.19
+ performance-now: ^2.1.0
+ qs: 6.10.4
+ safe-buffer: ^5.1.2
+ tough-cookie: ^4.1.3
+ tunnel-agent: ^0.6.0
+ uuid: ^8.3.2
+ checksum: 7175522ebdbe30e3c37973e204c437c23ce659e58d5939466615bddcd58d778f3a8ea40f087b965ae8b8138ea8d102b729c6eb18c6324f121f3778f4a2e8e727
+ languageName: node
+ linkType: hard
+
+"@cypress/xvfb@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "@cypress/xvfb@npm:1.2.4"
+ dependencies:
+ debug: ^3.1.0
+ lodash.once: ^4.1.1
+ checksum: 7bdcdaeb1bb692ec9d9bf8ec52538aa0bead6764753f4a067a171a511807a43fab016f7285a56bef6a606c2467ff3f1365e1ad2d2d583b81beed849ee1573fd1
+ languageName: node
+ linkType: hard
+
"@dotlottie/common@npm:0.7.9":
version: 0.7.9
resolution: "@dotlottie/common@npm:0.7.9"
@@ -4213,6 +4256,13 @@ __metadata:
languageName: node
linkType: hard
+"@faker-js/faker@npm:^8.4.1":
+ version: 8.4.1
+ resolution: "@faker-js/faker@npm:8.4.1"
+ checksum: d802d531f8929562715adc279cfec763c9a4bc596ec67b0ce43fd0ae61b285d2b0eec6f1f4aa852452a63721a842fe7e81926dce7bd92acca94b01e2a1f55f5a
+ languageName: node
+ linkType: hard
+
"@gar/promisify@npm:^1.0.1":
version: 1.1.3
resolution: "@gar/promisify@npm:1.1.3"
@@ -4291,6 +4341,15 @@ __metadata:
languageName: node
linkType: hard
+"@hookform/resolvers@npm:^3.6.0":
+ version: 3.6.0
+ resolution: "@hookform/resolvers@npm:3.6.0"
+ peerDependencies:
+ react-hook-form: ^7.0.0
+ checksum: a230fd2d0b571ddb8795f587284211e17f942de6b75ba235f613f54d3c17561e3a6483deee48c7dd5a6f52131769c5e59e4ed04823447084c28b6191d7e2d9dd
+ languageName: node
+ linkType: hard
+
"@humanwhocodes/config-array@npm:^0.11.13":
version: 0.11.14
resolution: "@humanwhocodes/config-array@npm:0.11.14"
@@ -5673,6 +5732,16 @@ __metadata:
languageName: node
linkType: hard
+"@react-native-picker/picker@npm:2.6.1":
+ version: 2.6.1
+ resolution: "@react-native-picker/picker@npm:2.6.1"
+ peerDependencies:
+ react: ">=16"
+ react-native: ">=0.57"
+ checksum: a8c58d5d945350b70fd8b5d66dfe97dd04641277db7c702912d8c41ae4da94cfef8b0b73bfa493adfdee8f089af6e0316872c3ee61a4efc18528e6e25a5452bc
+ languageName: node
+ linkType: hard
+
"@react-native/assets-registry@npm:0.73.1, @react-native/assets-registry@npm:~0.73.1":
version: 0.73.1
resolution: "@react-native/assets-registry@npm:0.73.1"
@@ -6825,6 +6894,20 @@ __metadata:
languageName: node
linkType: hard
+"@types/sinonjs__fake-timers@npm:8.1.1":
+ version: 8.1.1
+ resolution: "@types/sinonjs__fake-timers@npm:8.1.1"
+ checksum: ca09d54d47091d87020824a73f026300fa06b17cd9f2f9b9387f28b549364b141ef194ee28db762f6588de71d8febcd17f753163cb7ea116b8387c18e80ebd5c
+ languageName: node
+ linkType: hard
+
+"@types/sizzle@npm:^2.3.2":
+ version: 2.3.8
+ resolution: "@types/sizzle@npm:2.3.8"
+ checksum: 2ac62443dc917f5f903cbd9afc51c7d6cc1c6569b4e1a15faf04aea5b13b486e7f208650014c3dc4fed34653eded3e00fe5abffe0e6300cbf0e8a01beebf11a6
+ languageName: node
+ linkType: hard
+
"@types/stack-utils@npm:^2.0.0":
version: 2.0.3
resolution: "@types/stack-utils@npm:2.0.3"
@@ -7339,6 +7422,13 @@ __metadata:
languageName: node
linkType: hard
+"ansi-colors@npm:^4.1.1":
+ version: 4.1.3
+ resolution: "ansi-colors@npm:4.1.3"
+ checksum: a9c2ec842038a1fabc7db9ece7d3177e2fe1c5dc6f0c51ecfbf5f39911427b89c00b5dc6b8bd95f82a26e9b16aaae2e83d45f060e98070ce4d1333038edceb0e
+ languageName: node
+ linkType: hard
+
"ansi-escapes@npm:^2.0.0":
version: 2.0.0
resolution: "ansi-escapes@npm:2.0.0"
@@ -7353,7 +7443,7 @@ __metadata:
languageName: node
linkType: hard
-"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.2":
+"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.0, ansi-escapes@npm:^4.3.2":
version: 4.3.2
resolution: "ansi-escapes@npm:4.3.2"
dependencies:
@@ -7487,6 +7577,13 @@ __metadata:
languageName: node
linkType: hard
+"arch@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "arch@npm:2.2.0"
+ checksum: e21b7635029fe8e9cdd5a026f9a6c659103e63fff423834323cdf836a1bb240a72d0c39ca8c470f84643385cf581bd8eda2cad8bf493e27e54bd9783abe9101f
+ languageName: node
+ linkType: hard
+
"arg@npm:5.0.2":
version: 5.0.2
resolution: "arg@npm:5.0.2"
@@ -7638,6 +7735,22 @@ __metadata:
languageName: node
linkType: hard
+"asn1@npm:~0.2.3":
+ version: 0.2.6
+ resolution: "asn1@npm:0.2.6"
+ dependencies:
+ safer-buffer: ~2.1.0
+ checksum: 39f2ae343b03c15ad4f238ba561e626602a3de8d94ae536c46a4a93e69578826305366dc09fbb9b56aec39b4982a463682f259c38e59f6fa380cd72cd61e493d
+ languageName: node
+ linkType: hard
+
+"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "assert-plus@npm:1.0.0"
+ checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64
+ languageName: node
+ linkType: hard
+
"assert@npm:^2.1.0":
version: 2.1.0
resolution: "assert@npm:2.1.0"
@@ -7676,6 +7789,13 @@ __metadata:
languageName: node
linkType: hard
+"astral-regex@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "astral-regex@npm:2.0.0"
+ checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766
+ languageName: node
+ linkType: hard
+
"async-limiter@npm:~1.0.0":
version: 1.0.1
resolution: "async-limiter@npm:1.0.1"
@@ -7683,6 +7803,13 @@ __metadata:
languageName: node
linkType: hard
+"async@npm:^3.2.0":
+ version: 3.2.5
+ resolution: "async@npm:3.2.5"
+ checksum: 5ec77f1312301dee02d62140a6b1f7ee0edd2a0f983b6fd2b0849b969f245225b990b47b8243e7b9ad16451a53e7f68e753700385b706198ced888beedba3af4
+ languageName: node
+ linkType: hard
+
"asynciterator.prototype@npm:^1.0.0":
version: 1.0.0
resolution: "asynciterator.prototype@npm:1.0.0"
@@ -7720,6 +7847,20 @@ __metadata:
languageName: node
linkType: hard
+"aws-sign2@npm:~0.7.0":
+ version: 0.7.0
+ resolution: "aws-sign2@npm:0.7.0"
+ checksum: b148b0bb0778098ad8cf7e5fc619768bcb51236707ca1d3e5b49e41b171166d8be9fdc2ea2ae43d7decf02989d0aaa3a9c4caa6f320af95d684de9b548a71525
+ languageName: node
+ linkType: hard
+
+"aws4@npm:^1.8.0":
+ version: 1.12.0
+ resolution: "aws4@npm:1.12.0"
+ checksum: 68f79708ac7c335992730bf638286a3ee0a645cf12575d557860100767c500c08b30e24726b9f03265d74116417f628af78509e1333575e9f8d52a80edfe8cbc
+ languageName: node
+ linkType: hard
+
"axios@npm:0.21.1":
version: 0.21.1
resolution: "axios@npm:0.21.1"
@@ -8014,6 +8155,15 @@ __metadata:
languageName: node
linkType: hard
+"bcrypt-pbkdf@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "bcrypt-pbkdf@npm:1.0.2"
+ dependencies:
+ tweetnacl: ^0.14.3
+ checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291
+ languageName: node
+ linkType: hard
+
"bech32@npm:1.1.4, bech32@npm:^1.1.3, bech32@npm:^1.1.4":
version: 1.1.4
resolution: "bech32@npm:1.1.4"
@@ -8097,6 +8247,20 @@ __metadata:
languageName: node
linkType: hard
+"blob-util@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "blob-util@npm:2.0.2"
+ checksum: d543e6b92e4ca715ca33c78e89a07a2290d43e5b2bc897d7ec588c5c7bbf59df93e45225ac0c9258aa6ce4320358990f99c9288f1c48280f8ec5d7a2e088d19b
+ languageName: node
+ linkType: hard
+
+"bluebird@npm:^3.7.2":
+ version: 3.7.2
+ resolution: "bluebird@npm:3.7.2"
+ checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef
+ languageName: node
+ linkType: hard
+
"blueimp-md5@npm:^2.10.0":
version: 2.19.0
resolution: "blueimp-md5@npm:2.19.0"
@@ -8365,7 +8529,7 @@ __metadata:
languageName: node
linkType: hard
-"buffer@npm:^5.4.3, buffer@npm:^5.5.0, buffer@npm:^5.6.0":
+"buffer@npm:^5.4.3, buffer@npm:^5.5.0, buffer@npm:^5.6.0, buffer@npm:^5.7.1":
version: 5.7.1
resolution: "buffer@npm:5.7.1"
dependencies:
@@ -8477,6 +8641,13 @@ __metadata:
languageName: node
linkType: hard
+"cachedir@npm:^2.3.0":
+ version: 2.4.0
+ resolution: "cachedir@npm:2.4.0"
+ checksum: 43198514eaa61f65b5535ed29ad651f22836fba3868ed58a6a87731f05462f317d39098fa3ac778801c25455483c9b7f32a2fcad1f690a978947431f12a0f4d0
+ languageName: node
+ linkType: hard
+
"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.4, call-bind@npm:^1.0.5":
version: 1.0.5
resolution: "call-bind@npm:1.0.5"
@@ -8569,6 +8740,13 @@ __metadata:
languageName: node
linkType: hard
+"caseless@npm:~0.12.0":
+ version: 0.12.0
+ resolution: "caseless@npm:0.12.0"
+ checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751
+ languageName: node
+ linkType: hard
+
"chain-registry@npm:1.10.0":
version: 1.10.0
resolution: "chain-registry@npm:1.10.0"
@@ -8644,6 +8822,13 @@ __metadata:
languageName: node
linkType: hard
+"check-more-types@npm:^2.24.0":
+ version: 2.24.0
+ resolution: "check-more-types@npm:2.24.0"
+ checksum: b09080ec3404d20a4b0ead828994b2e5913236ef44ed3033a27062af0004cf7d2091fbde4b396bf13b7ce02fb018bc9960b48305e6ab2304cd82d73ed7a51ef4
+ languageName: node
+ linkType: hard
+
"chownr@npm:^2.0.0":
version: 2.0.0
resolution: "chownr@npm:2.0.0"
@@ -8797,6 +8982,29 @@ __metadata:
languageName: node
linkType: hard
+"cli-table3@npm:~0.6.1":
+ version: 0.6.5
+ resolution: "cli-table3@npm:0.6.5"
+ dependencies:
+ "@colors/colors": 1.5.0
+ string-width: ^4.2.0
+ dependenciesMeta:
+ "@colors/colors":
+ optional: true
+ checksum: ab7afbf4f8597f1c631f3ee6bb3481d0bfeac8a3b81cffb5a578f145df5c88003b6cfff46046a7acae86596fdd03db382bfa67f20973b6b57425505abc47e42c
+ languageName: node
+ linkType: hard
+
+"cli-truncate@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "cli-truncate@npm:2.1.0"
+ dependencies:
+ slice-ansi: ^3.0.0
+ string-width: ^4.2.0
+ checksum: bf1e4e6195392dc718bf9cd71f317b6300dc4a9191d052f31046b8773230ece4fa09458813bf0e3455a5e68c0690d2ea2c197d14a8b85a7b5e01c97f4b5feb5d
+ languageName: node
+ linkType: hard
+
"cli-truncate@npm:^4.0.0":
version: 4.0.0
resolution: "cli-truncate@npm:4.0.0"
@@ -8964,7 +9172,7 @@ __metadata:
languageName: node
linkType: hard
-"colorette@npm:^2.0.20":
+"colorette@npm:^2.0.16, colorette@npm:^2.0.20":
version: 2.0.20
resolution: "colorette@npm:2.0.20"
checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d
@@ -8978,7 +9186,7 @@ __metadata:
languageName: node
linkType: hard
-"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8":
+"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
@@ -9015,6 +9223,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^6.2.1":
+ version: 6.2.1
+ resolution: "commander@npm:6.2.1"
+ checksum: d7090410c0de6bc5c67d3ca41c41760d6d268f3c799e530aafb73b7437d1826bbf0d2a3edac33f8b57cc9887b4a986dce307fa5557e109be40eadb7c43b21742
+ languageName: node
+ linkType: hard
+
"commander@npm:^7.2.0":
version: 7.2.0
resolution: "commander@npm:7.2.0"
@@ -9029,6 +9244,13 @@ __metadata:
languageName: node
linkType: hard
+"common-tags@npm:^1.8.0":
+ version: 1.8.2
+ resolution: "common-tags@npm:1.8.2"
+ checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff
+ languageName: node
+ linkType: hard
+
"commondir@npm:^1.0.1":
version: 1.0.1
resolution: "commondir@npm:1.0.1"
@@ -9134,6 +9356,13 @@ __metadata:
languageName: node
linkType: hard
+"core-util-is@npm:1.0.2":
+ version: 1.0.2
+ resolution: "core-util-is@npm:1.0.2"
+ checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab
+ languageName: node
+ linkType: hard
+
"core-util-is@npm:~1.0.0":
version: 1.0.3
resolution: "core-util-is@npm:1.0.3"
@@ -9440,6 +9669,58 @@ __metadata:
languageName: node
linkType: hard
+"cypress@npm:^13.9.0":
+ version: 13.9.0
+ resolution: "cypress@npm:13.9.0"
+ dependencies:
+ "@cypress/request": ^3.0.0
+ "@cypress/xvfb": ^1.2.4
+ "@types/sinonjs__fake-timers": 8.1.1
+ "@types/sizzle": ^2.3.2
+ arch: ^2.2.0
+ blob-util: ^2.0.2
+ bluebird: ^3.7.2
+ buffer: ^5.7.1
+ cachedir: ^2.3.0
+ chalk: ^4.1.0
+ check-more-types: ^2.24.0
+ cli-cursor: ^3.1.0
+ cli-table3: ~0.6.1
+ commander: ^6.2.1
+ common-tags: ^1.8.0
+ dayjs: ^1.10.4
+ debug: ^4.3.4
+ enquirer: ^2.3.6
+ eventemitter2: 6.4.7
+ execa: 4.1.0
+ executable: ^4.1.1
+ extract-zip: 2.0.1
+ figures: ^3.2.0
+ fs-extra: ^9.1.0
+ getos: ^3.2.1
+ is-ci: ^3.0.1
+ is-installed-globally: ~0.4.0
+ lazy-ass: ^1.6.0
+ listr2: ^3.8.3
+ lodash: ^4.17.21
+ log-symbols: ^4.0.0
+ minimist: ^1.2.8
+ ospath: ^1.2.2
+ pretty-bytes: ^5.6.0
+ process: ^0.11.10
+ proxy-from-env: 1.0.0
+ request-progress: ^3.0.0
+ semver: ^7.5.3
+ supports-color: ^8.1.1
+ tmp: ~0.2.1
+ untildify: ^4.0.0
+ yauzl: ^2.10.0
+ bin:
+ cypress: bin/cypress
+ checksum: ec2e0237d2a38d53d4e5c05fe1c37f7fe0bb13de798045ba091b6a5cf0edd7b3a282f4d8f4c063e3988ee048d06dcf4fef91d83d63a56cee9f9ff68685f3946d
+ languageName: node
+ linkType: hard
+
"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6":
version: 3.2.4
resolution: "d3-array@npm:3.2.4"
@@ -9564,6 +9845,22 @@ __metadata:
languageName: node
linkType: hard
+"dashdash@npm:^1.12.0":
+ version: 1.14.1
+ resolution: "dashdash@npm:1.14.1"
+ dependencies:
+ assert-plus: ^1.0.0
+ checksum: 3634c249570f7f34e3d34f866c93f866c5b417f0dd616275decae08147dcdf8fccfaa5947380ccfb0473998ea3a8057c0b4cd90c875740ee685d0624b2983598
+ languageName: node
+ linkType: hard
+
+"dayjs@npm:^1.10.4":
+ version: 1.11.11
+ resolution: "dayjs@npm:1.11.11"
+ checksum: 84788275aad8a87fee4f1ce4be08861df29687aae6b7b43dd65350118a37dda56772a3902f802cb2dc651dfed447a5a8df62d88f0fb900dba8333e411190a5d5
+ languageName: node
+ linkType: hard
+
"dayjs@npm:^1.8.15":
version: 1.11.10
resolution: "dayjs@npm:1.11.10"
@@ -10092,6 +10389,16 @@ __metadata:
languageName: node
linkType: hard
+"ecc-jsbn@npm:~0.1.1":
+ version: 0.1.2
+ resolution: "ecc-jsbn@npm:0.1.2"
+ dependencies:
+ jsbn: ~0.1.0
+ safer-buffer: ^2.1.0
+ checksum: 22fef4b6203e5f31d425f5b711eb389e4c6c2723402e389af394f8411b76a488fa414d309d866e2b577ce3e8462d344205545c88a8143cc21752a5172818888a
+ languageName: node
+ linkType: hard
+
"ee-first@npm:1.1.1":
version: 1.1.1
resolution: "ee-first@npm:1.1.1"
@@ -10224,6 +10531,16 @@ __metadata:
languageName: node
linkType: hard
+"enquirer@npm:^2.3.6":
+ version: 2.4.1
+ resolution: "enquirer@npm:2.4.1"
+ dependencies:
+ ansi-colors: ^4.1.1
+ strip-ansi: ^6.0.1
+ checksum: f080f11a74209647dbf347a7c6a83c8a47ae1ebf1e75073a808bc1088eb780aa54075bfecd1bcdb3e3c724520edb8e6ee05da031529436b421b71066fcc48cb5
+ languageName: node
+ linkType: hard
+
"entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0":
version: 4.5.0
resolution: "entities@npm:4.5.0"
@@ -10947,6 +11264,13 @@ __metadata:
languageName: node
linkType: hard
+"eventemitter2@npm:6.4.7":
+ version: 6.4.7
+ resolution: "eventemitter2@npm:6.4.7"
+ checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66
+ languageName: node
+ linkType: hard
+
"eventemitter3@npm:1.x.x":
version: 1.2.0
resolution: "eventemitter3@npm:1.2.0"
@@ -10993,6 +11317,23 @@ __metadata:
languageName: node
linkType: hard
+"execa@npm:4.1.0":
+ version: 4.1.0
+ resolution: "execa@npm:4.1.0"
+ dependencies:
+ cross-spawn: ^7.0.0
+ get-stream: ^5.0.0
+ human-signals: ^1.1.1
+ is-stream: ^2.0.0
+ merge-stream: ^2.0.0
+ npm-run-path: ^4.0.0
+ onetime: ^5.1.0
+ signal-exit: ^3.0.2
+ strip-final-newline: ^2.0.0
+ checksum: e30d298934d9c52f90f3847704fd8224e849a081ab2b517bbc02f5f7732c24e56a21f14cb96a08256deffeb2d12b2b7cb7e2b014a12fb36f8d3357e06417ed55
+ languageName: node
+ linkType: hard
+
"execa@npm:^1.0.0":
version: 1.0.0
resolution: "execa@npm:1.0.0"
@@ -11025,6 +11366,15 @@ __metadata:
languageName: node
linkType: hard
+"executable@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "executable@npm:4.1.1"
+ dependencies:
+ pify: ^2.2.0
+ checksum: f01927ce59bccec804e171bf859a26e362c1f50aa9ebc69f7cafdcce3859d29d4b6267fd47237c18b0a1830614bd3f0ee14b7380d9bad18a4e7af9b5f0b6984f
+ languageName: node
+ linkType: hard
+
"expand-tilde@npm:^2.0.0, expand-tilde@npm:^2.0.2":
version: 2.0.2
resolution: "expand-tilde@npm:2.0.2"
@@ -11361,7 +11711,7 @@ __metadata:
languageName: node
linkType: hard
-"extend@npm:^3.0.0":
+"extend@npm:^3.0.0, extend@npm:~3.0.2":
version: 3.0.2
resolution: "extend@npm:3.0.2"
checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515
@@ -11397,7 +11747,7 @@ __metadata:
languageName: node
linkType: hard
-"extract-zip@npm:^2.0.1":
+"extract-zip@npm:2.0.1, extract-zip@npm:^2.0.1":
version: 2.0.1
resolution: "extract-zip@npm:2.0.1"
dependencies:
@@ -11414,6 +11764,20 @@ __metadata:
languageName: node
linkType: hard
+"extsprintf@npm:1.3.0":
+ version: 1.3.0
+ resolution: "extsprintf@npm:1.3.0"
+ checksum: cee7a4a1e34cffeeec18559109de92c27517e5641991ec6bab849aa64e3081022903dd53084f2080d0d2530803aa5ee84f1e9de642c365452f9e67be8f958ce2
+ languageName: node
+ linkType: hard
+
+"extsprintf@npm:^1.2.0":
+ version: 1.4.1
+ resolution: "extsprintf@npm:1.4.1"
+ checksum: a2f29b241914a8d2bad64363de684821b6b1609d06ae68d5b539e4de6b28659715b5bea94a7265201603713b7027d35399d10b0548f09071c5513e65e8323d33
+ languageName: node
+ linkType: hard
+
"eyes@npm:^0.1.8":
version: 0.1.8
resolution: "eyes@npm:0.1.8"
@@ -11598,6 +11962,15 @@ __metadata:
languageName: node
linkType: hard
+"figures@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "figures@npm:3.2.0"
+ dependencies:
+ escape-string-regexp: ^1.0.5
+ checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b
+ languageName: node
+ linkType: hard
+
"file-entry-cache@npm:^6.0.1":
version: 6.0.1
resolution: "file-entry-cache@npm:6.0.1"
@@ -11792,6 +12165,13 @@ __metadata:
languageName: node
linkType: hard
+"forever-agent@npm:~0.6.1":
+ version: 0.6.1
+ resolution: "forever-agent@npm:0.6.1"
+ checksum: 766ae6e220f5fe23676bb4c6a99387cec5b7b62ceb99e10923376e27bfea72f3c3aeec2ba5f45f3f7ba65d6616965aa7c20b15002b6860833bb6e394dea546a8
+ languageName: node
+ linkType: hard
+
"form-data@npm:^2.3.3":
version: 2.5.1
resolution: "form-data@npm:2.5.1"
@@ -11825,6 +12205,17 @@ __metadata:
languageName: node
linkType: hard
+"form-data@npm:~2.3.2":
+ version: 2.3.3
+ resolution: "form-data@npm:2.3.3"
+ dependencies:
+ asynckit: ^0.4.0
+ combined-stream: ^1.0.6
+ mime-types: ^2.1.12
+ checksum: 10c1780fa13dbe1ff3100114c2ce1f9307f8be10b14bf16e103815356ff567b6be39d70fc4a40f8990b9660012dc24b0f5e1dde1b6426166eb23a445ba068ca3
+ languageName: node
+ linkType: hard
+
"freeport-async@npm:2.0.0":
version: 2.0.0
resolution: "freeport-async@npm:2.0.0"
@@ -12014,7 +12405,7 @@ __metadata:
languageName: node
linkType: hard
-"get-stream@npm:^5.1.0":
+"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0":
version: 5.2.0
resolution: "get-stream@npm:5.2.0"
dependencies:
@@ -12056,6 +12447,24 @@ __metadata:
languageName: node
linkType: hard
+"getos@npm:^3.2.1":
+ version: 3.2.1
+ resolution: "getos@npm:3.2.1"
+ dependencies:
+ async: ^3.2.0
+ checksum: 42fd78a66d47cebd3e09de5566cc0044e034b08f4a000a310dbd89a77b02c65d8f4002554bfa495ea5bdc4fa9d515f5ac785a7cc474ba45383cc697f865eeaf1
+ languageName: node
+ linkType: hard
+
+"getpass@npm:^0.1.1":
+ version: 0.1.7
+ resolution: "getpass@npm:0.1.7"
+ dependencies:
+ assert-plus: ^1.0.0
+ checksum: ab18d55661db264e3eac6012c2d3daeafaab7a501c035ae0ccb193c3c23e9849c6e29b6ac762b9c2adae460266f925d55a3a2a3a3c8b94be2f222df94d70c046
+ languageName: node
+ linkType: hard
+
"glob-parent@npm:^5.1.2":
version: 5.1.2
resolution: "glob-parent@npm:5.1.2"
@@ -12168,6 +12577,15 @@ __metadata:
languageName: node
linkType: hard
+"global-dirs@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "global-dirs@npm:3.0.1"
+ dependencies:
+ ini: 2.0.0
+ checksum: 70147b80261601fd40ac02a104581432325c1c47329706acd773f3a6ce99bb36d1d996038c85ccacd482ad22258ec233c586b6a91535b1a116b89663d49d6438
+ languageName: node
+ linkType: hard
+
"global-modules@npm:^1.0.0":
version: 1.0.0
resolution: "global-modules@npm:1.0.0"
@@ -12568,6 +12986,17 @@ __metadata:
languageName: node
linkType: hard
+"http-signature@npm:~1.3.6":
+ version: 1.3.6
+ resolution: "http-signature@npm:1.3.6"
+ dependencies:
+ assert-plus: ^1.0.0
+ jsprim: ^2.0.2
+ sshpk: ^1.14.1
+ checksum: 10be2af4764e71fee0281392937050201ee576ac755c543f570d6d87134ce5e858663fe999a7adb3e4e368e1e356d0d7fec6b9542295b875726ff615188e7a0c
+ languageName: node
+ linkType: hard
+
"http2-wrapper@npm:^1.0.0-beta.5.2":
version: 1.0.3
resolution: "http2-wrapper@npm:1.0.3"
@@ -12598,6 +13027,13 @@ __metadata:
languageName: node
linkType: hard
+"human-signals@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "human-signals@npm:1.1.1"
+ checksum: d587647c9e8ec24e02821b6be7de5a0fc37f591f6c4e319b3054b43fd4c35a70a94c46fc74d8c1a43c47fde157d23acd7421f375e1c1365b09a16835b8300205
+ languageName: node
+ linkType: hard
+
"human-signals@npm:^2.1.0":
version: 2.1.0
resolution: "human-signals@npm:2.1.0"
@@ -12750,6 +13186,13 @@ __metadata:
languageName: node
linkType: hard
+"ini@npm:2.0.0":
+ version: 2.0.0
+ resolution: "ini@npm:2.0.0"
+ checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e
+ languageName: node
+ linkType: hard
+
"ini@npm:^1.3.4, ini@npm:~1.3.0":
version: 1.3.8
resolution: "ini@npm:1.3.8"
@@ -12999,6 +13442,17 @@ __metadata:
languageName: node
linkType: hard
+"is-ci@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "is-ci@npm:3.0.1"
+ dependencies:
+ ci-info: ^3.2.0
+ bin:
+ is-ci: bin.js
+ checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e
+ languageName: node
+ linkType: hard
+
"is-core-module@npm:^2.12.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1":
version: 2.13.1
resolution: "is-core-module@npm:2.13.1"
@@ -13113,6 +13567,16 @@ __metadata:
languageName: node
linkType: hard
+"is-installed-globally@npm:~0.4.0":
+ version: 0.4.0
+ resolution: "is-installed-globally@npm:0.4.0"
+ dependencies:
+ global-dirs: ^3.0.0
+ is-path-inside: ^3.0.2
+ checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399
+ languageName: node
+ linkType: hard
+
"is-interactive@npm:^1.0.0":
version: 1.0.0
resolution: "is-interactive@npm:1.0.0"
@@ -13324,6 +13788,13 @@ __metadata:
languageName: node
linkType: hard
+"is-typedarray@npm:~1.0.0":
+ version: 1.0.0
+ resolution: "is-typedarray@npm:1.0.0"
+ checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7
+ languageName: node
+ linkType: hard
+
"is-unicode-supported@npm:^0.1.0":
version: 0.1.0
resolution: "is-unicode-supported@npm:0.1.0"
@@ -13440,6 +13911,13 @@ __metadata:
languageName: node
linkType: hard
+"isstream@npm:~0.1.2":
+ version: 0.1.2
+ resolution: "isstream@npm:0.1.2"
+ checksum: 1eb2fe63a729f7bdd8a559ab552c69055f4f48eb5c2f03724430587c6f450783c8f1cd936c1c952d0a927925180fcc892ebd5b174236cf1065d4bd5bdb37e963
+ languageName: node
+ linkType: hard
+
"istanbul-lib-coverage@npm:^3.2.0":
version: 3.2.2
resolution: "istanbul-lib-coverage@npm:3.2.2"
@@ -13774,6 +14252,13 @@ __metadata:
languageName: node
linkType: hard
+"jsbn@npm:~0.1.0":
+ version: 0.1.1
+ resolution: "jsbn@npm:0.1.1"
+ checksum: e5ff29c1b8d965017ef3f9c219dacd6e40ad355c664e277d31246c90545a02e6047018c16c60a00f36d561b3647215c41894f5d869ada6908a2e0ce4200c88f2
+ languageName: node
+ linkType: hard
+
"jsc-android@npm:^250231.0.0":
version: 250231.0.0
resolution: "jsc-android@npm:250231.0.0"
@@ -13895,6 +14380,13 @@ __metadata:
languageName: node
linkType: hard
+"json-schema@npm:0.4.0":
+ version: 0.4.0
+ resolution: "json-schema@npm:0.4.0"
+ checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72
+ languageName: node
+ linkType: hard
+
"json-stable-stringify-without-jsonify@npm:^1.0.1":
version: 1.0.1
resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
@@ -13902,7 +14394,7 @@ __metadata:
languageName: node
linkType: hard
-"json-stringify-safe@npm:^5.0.1":
+"json-stringify-safe@npm:^5.0.1, json-stringify-safe@npm:~5.0.1":
version: 5.0.1
resolution: "json-stringify-safe@npm:5.0.1"
checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee
@@ -13961,6 +14453,18 @@ __metadata:
languageName: node
linkType: hard
+"jsprim@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "jsprim@npm:2.0.2"
+ dependencies:
+ assert-plus: 1.0.0
+ extsprintf: 1.3.0
+ json-schema: 0.4.0
+ verror: 1.10.0
+ checksum: d175f6b1991e160cb0aa39bc857da780e035611986b5492f32395411879fdaf4e513d98677f08f7352dac93a16b66b8361c674b86a3fa406e2e7af6b26321838
+ languageName: node
+ linkType: hard
+
"jsx-ast-utils@npm:^2.4.1 || ^3.0.0":
version: 3.3.5
resolution: "jsx-ast-utils@npm:3.3.5"
@@ -14017,6 +14521,13 @@ __metadata:
languageName: node
linkType: hard
+"lazy-ass@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "lazy-ass@npm:1.6.0"
+ checksum: 5a3ebb17915b03452320804466345382a6c25ac782ec4874fecdb2385793896cd459be2f187dc7def8899180c32ee0ab9a1aa7fe52193ac3ff3fe29bb0591729
+ languageName: node
+ linkType: hard
+
"leaflet.markercluster@npm:^1.5.3":
version: 1.5.3
resolution: "leaflet.markercluster@npm:1.5.3"
@@ -14210,6 +14721,27 @@ __metadata:
languageName: node
linkType: hard
+"listr2@npm:^3.8.3":
+ version: 3.14.0
+ resolution: "listr2@npm:3.14.0"
+ dependencies:
+ cli-truncate: ^2.1.0
+ colorette: ^2.0.16
+ log-update: ^4.0.0
+ p-map: ^4.0.0
+ rfdc: ^1.3.0
+ rxjs: ^7.5.1
+ through: ^2.3.8
+ wrap-ansi: ^7.0.0
+ peerDependencies:
+ enquirer: ">= 2.3.0 < 3"
+ peerDependenciesMeta:
+ enquirer:
+ optional: true
+ checksum: fdb8b2d6bdf5df9371ebd5082bee46c6d0ca3d1e5f2b11fbb5a127839855d5f3da9d4968fce94f0a5ec67cac2459766abbb1faeef621065ebb1829b11ef9476d
+ languageName: node
+ linkType: hard
+
"listr2@npm:^8.0.1":
version: 8.0.1
resolution: "listr2@npm:8.0.1"
@@ -14284,6 +14816,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.once@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "lodash.once@npm:4.1.1"
+ checksum: d768fa9f9b4e1dc6453be99b753906f58990e0c45e7b2ca5a3b40a33111e5d17f6edf2f768786e2716af90a8e78f8f91431ab8435f761fef00f9b0c256f6d245
+ languageName: node
+ linkType: hard
+
"lodash.throttle@npm:^4.1.1":
version: 4.1.1
resolution: "lodash.throttle@npm:4.1.1"
@@ -14307,7 +14846,7 @@ __metadata:
languageName: node
linkType: hard
-"log-symbols@npm:^4.1.0":
+"log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0":
version: 4.1.0
resolution: "log-symbols@npm:4.1.0"
dependencies:
@@ -14317,6 +14856,18 @@ __metadata:
languageName: node
linkType: hard
+"log-update@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "log-update@npm:4.0.0"
+ dependencies:
+ ansi-escapes: ^4.3.0
+ cli-cursor: ^3.1.0
+ slice-ansi: ^4.0.0
+ wrap-ansi: ^6.2.0
+ checksum: ae2f85bbabc1906034154fb7d4c4477c79b3e703d22d78adee8b3862fa913942772e7fa11713e3d96fb46de4e3cabefbf5d0a544344f03b58d3c4bff52aa9eb2
+ languageName: node
+ linkType: hard
+
"log-update@npm:^6.0.0":
version: 6.0.0
resolution: "log-update@npm:6.0.0"
@@ -14942,7 +15493,7 @@ __metadata:
languageName: node
linkType: hard
-"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.34":
+"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.19, mime-types@npm:~2.1.34":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
@@ -15061,7 +15612,7 @@ __metadata:
languageName: node
linkType: hard
-"minimist@npm:^1.2.0, minimist@npm:^1.2.6":
+"minimist@npm:^1.2.0, minimist@npm:^1.2.6, minimist@npm:^1.2.8":
version: 1.2.8
resolution: "minimist@npm:1.2.8"
checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0
@@ -15593,7 +16144,7 @@ __metadata:
languageName: node
linkType: hard
-"npm-run-path@npm:^4.0.1":
+"npm-run-path@npm:^4.0.0, npm-run-path@npm:^4.0.1":
version: 4.0.1
resolution: "npm-run-path@npm:4.0.1"
dependencies:
@@ -15903,6 +16454,13 @@ __metadata:
languageName: node
linkType: hard
+"ospath@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "ospath@npm:1.2.2"
+ checksum: 505f48a4f4f1c557d6c656ec985707726e3714721680139be037613e903aa8c8fa4ddd8d1342006f9b2dc0065e6e20f8b7bea2ee05354f31257044790367b347
+ languageName: node
+ linkType: hard
+
"p-cancelable@npm:^2.0.0":
version: 2.1.1
resolution: "p-cancelable@npm:2.1.1"
@@ -16217,6 +16775,13 @@ __metadata:
languageName: node
linkType: hard
+"performance-now@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "performance-now@npm:2.1.0"
+ checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550
+ languageName: node
+ linkType: hard
+
"picocolors@npm:^1.0.0":
version: 1.0.0
resolution: "picocolors@npm:1.0.0"
@@ -16238,6 +16803,13 @@ __metadata:
languageName: node
linkType: hard
+"pify@npm:^2.2.0":
+ version: 2.3.0
+ resolution: "pify@npm:2.3.0"
+ checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba
+ languageName: node
+ linkType: hard
+
"pify@npm:^4.0.1":
version: 4.0.1
resolution: "pify@npm:4.0.1"
@@ -16421,7 +16993,7 @@ __metadata:
languageName: node
linkType: hard
-"pretty-bytes@npm:5.6.0":
+"pretty-bytes@npm:5.6.0, pretty-bytes@npm:^5.6.0":
version: 5.6.0
resolution: "pretty-bytes@npm:5.6.0"
checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd
@@ -16465,7 +17037,7 @@ __metadata:
languageName: node
linkType: hard
-"process@npm:^0.11.1":
+"process@npm:^0.11.1, process@npm:^0.11.10":
version: 0.11.10
resolution: "process@npm:0.11.10"
checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3
@@ -16610,6 +17182,13 @@ __metadata:
languageName: node
linkType: hard
+"proxy-from-env@npm:1.0.0":
+ version: 1.0.0
+ resolution: "proxy-from-env@npm:1.0.0"
+ checksum: 292e28d1de0c315958d71d8315eb546dd3cd8c8cbc2dab7c54eeb9f5c17f421771964ad0b5e1f77011bab2305bdae42e1757ce33bdb1ccc3e87732322a8efcf1
+ languageName: node
+ linkType: hard
+
"proxy-from-env@npm:^1.1.0":
version: 1.1.0
resolution: "proxy-from-env@npm:1.1.0"
@@ -16617,6 +17196,13 @@ __metadata:
languageName: node
linkType: hard
+"psl@npm:^1.1.33":
+ version: 1.9.0
+ resolution: "psl@npm:1.9.0"
+ checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d
+ languageName: node
+ linkType: hard
+
"public-encrypt@npm:^4.0.0":
version: 4.0.3
resolution: "public-encrypt@npm:4.0.3"
@@ -16678,6 +17264,15 @@ __metadata:
languageName: node
linkType: hard
+"qs@npm:6.10.4":
+ version: 6.10.4
+ resolution: "qs@npm:6.10.4"
+ dependencies:
+ side-channel: ^1.0.4
+ checksum: 31e4fedd759d01eae52dde6692abab175f9af3e639993c5caaa513a2a3607b34d8058d3ae52ceeccf37c3025f22ed5e90e9ddd6c2537e19c0562ddd10dc5b1eb
+ languageName: node
+ linkType: hard
+
"query-string@npm:^7.1.3":
version: 7.1.3
resolution: "query-string@npm:7.1.3"
@@ -16690,6 +17285,13 @@ __metadata:
languageName: node
linkType: hard
+"querystringify@npm:^2.1.1":
+ version: 2.2.0
+ resolution: "querystringify@npm:2.2.0"
+ checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15
+ languageName: node
+ linkType: hard
+
"queue-microtask@npm:^1.2.2":
version: 1.2.3
resolution: "queue-microtask@npm:1.2.3"
@@ -16968,6 +17570,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-hoverable@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "react-native-hoverable@npm:0.2.0"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: 9ca468d07c660ea30013da3921e09fdb42b479ce9f69e867e60bd56dbb49cb407998e07d3aa2ab6662e55f7b1cec9bc806ba9517ca9fd31839c1ebcbd4a7d26f
+ languageName: node
+ linkType: hard
+
"react-native-image-picker@npm:^7.1.0":
version: 7.1.0
resolution: "react-native-image-picker@npm:7.1.0"
@@ -17095,6 +17707,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-reanimated-table@npm:^0.0.2":
+ version: 0.0.2
+ resolution: "react-native-reanimated-table@npm:0.0.2"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-native: ">=0.6.0"
+ checksum: ab1a326d9880bc49febbb1ab325ede544c86b4ca2faf713904e8aa64d05478e36f6d545a819bc82a7d234c23ea6cf9e4fcbc2dc804a7e7f9240d5f21eb28e76c
+ languageName: node
+ linkType: hard
+
"react-native-reanimated@npm:^3.6.2":
version: 3.6.2
resolution: "react-native-reanimated@npm:3.6.2"
@@ -17642,6 +18264,15 @@ __metadata:
languageName: node
linkType: hard
+"request-progress@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "request-progress@npm:3.0.0"
+ dependencies:
+ throttleit: ^1.0.0
+ checksum: 6ea1761dcc8a8b7b5894afd478c0286aa31bd69438d7050294bd4fd0d0b3e09b5cde417d38deef9c49809039c337d8744e4bb49d8632b0c3e4ffa5e8a687e0fd
+ languageName: node
+ linkType: hard
+
"require-directory@npm:^2.1.1":
version: 2.1.1
resolution: "require-directory@npm:2.1.1"
@@ -17688,6 +18319,13 @@ __metadata:
languageName: node
linkType: hard
+"requires-port@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "requires-port@npm:1.0.0"
+ checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff
+ languageName: node
+ linkType: hard
+
"reselect@npm:^4.1.8":
version: 4.1.8
resolution: "reselect@npm:4.1.8"
@@ -18030,7 +18668,7 @@ __metadata:
languageName: node
linkType: hard
-"rxjs@npm:^7.8.1":
+"rxjs@npm:^7.5.1, rxjs@npm:^7.8.1":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
@@ -18083,7 +18721,7 @@ __metadata:
languageName: node
linkType: hard
-"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.1.0":
+"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0
@@ -18562,6 +19200,28 @@ __metadata:
languageName: node
linkType: hard
+"slice-ansi@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "slice-ansi@npm:3.0.0"
+ dependencies:
+ ansi-styles: ^4.0.0
+ astral-regex: ^2.0.0
+ is-fullwidth-code-point: ^3.0.0
+ checksum: 5ec6d022d12e016347e9e3e98a7eb2a592213a43a65f1b61b74d2c78288da0aded781f665807a9f3876b9daa9ad94f64f77d7633a0458876c3a4fdc4eb223f24
+ languageName: node
+ linkType: hard
+
+"slice-ansi@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "slice-ansi@npm:4.0.0"
+ dependencies:
+ ansi-styles: ^4.0.0
+ astral-regex: ^2.0.0
+ is-fullwidth-code-point: ^3.0.0
+ checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756
+ languageName: node
+ linkType: hard
+
"slice-ansi@npm:^5.0.0":
version: 5.0.0
resolution: "slice-ansi@npm:5.0.0"
@@ -18733,6 +19393,27 @@ __metadata:
languageName: node
linkType: hard
+"sshpk@npm:^1.14.1":
+ version: 1.18.0
+ resolution: "sshpk@npm:1.18.0"
+ dependencies:
+ asn1: ~0.2.3
+ assert-plus: ^1.0.0
+ bcrypt-pbkdf: ^1.0.0
+ dashdash: ^1.12.0
+ ecc-jsbn: ~0.1.1
+ getpass: ^0.1.1
+ jsbn: ~0.1.0
+ safer-buffer: ^2.0.2
+ tweetnacl: ~0.14.0
+ bin:
+ sshpk-conv: bin/sshpk-conv
+ sshpk-sign: bin/sshpk-sign
+ sshpk-verify: bin/sshpk-verify
+ checksum: 01d43374eee3a7e37b3b82fdbecd5518cbb2e47ccbed27d2ae30f9753f22bd6ffad31225cb8ef013bc3fb7785e686cea619203ee1439a228f965558c367c3cfa
+ languageName: node
+ linkType: hard
+
"ssri@npm:^10.0.0":
version: 10.0.5
resolution: "ssri@npm:10.0.5"
@@ -19159,7 +19840,7 @@ __metadata:
languageName: node
linkType: hard
-"supports-color@npm:^8.0.0":
+"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1":
version: 8.1.1
resolution: "supports-color@npm:8.1.1"
dependencies:
@@ -19312,11 +19993,12 @@ __metadata:
"@chain-registry/utils": 1.18.0
"@cosmjs/amino": 0.32.2
"@cosmjs/cosmwasm-stargate": 0.32.2
- "@cosmjs/encoding": ^0.32.2
- "@cosmjs/math": ^0.32.2
+ "@cosmjs/crypto": 0.32.2
+ "@cosmjs/encoding": 0.32.2
+ "@cosmjs/math": 0.32.2
"@cosmjs/proto-signing": 0.32.2
"@cosmjs/stargate": 0.32.2
- "@cosmjs/tendermint-rpc": ^0.32.2
+ "@cosmjs/tendermint-rpc": 0.32.2
"@cosmology/core": 2.0.1
"@cosmwasm/ts-codegen": ^0.35.7
"@dotlottie/react-player": ^1.6.5
@@ -19331,7 +20013,10 @@ __metadata:
"@ethersproject/providers": ^5.7.2
"@expo-google-fonts/exo": ^0.2.2
"@expo/metro-runtime": ~3.1.3
+ "@faker-js/faker": ^8.4.1
"@gnolang/gno-js-client": ^1.3.0
+ "@gnolang/tm2-js-client": ^1.2.1
+ "@hookform/resolvers": ^3.6.0
"@improbable-eng/grpc-web": ^0.15.0
"@improbable-eng/grpc-web-node-http-transport": ^0.15.0
"@improbable-eng/grpc-web-react-native-transport": ^0.15.0
@@ -19347,6 +20032,7 @@ __metadata:
"@react-native-clipboard/clipboard": ^1.13.2
"@react-native-community/slider": 4.4.2
"@react-native-masked-view/masked-view": 0.3.0
+ "@react-native-picker/picker": 2.6.1
"@react-navigation/bottom-tabs": ^6.5.11
"@react-navigation/drawer": ^6.6.6
"@react-navigation/native": ^6.0.11
@@ -19377,6 +20063,7 @@ __metadata:
cosmos-endpoints-scorer: ^0.1.0
cross-env: ^7.0.3
crypto-browserify: ^3.12.0
+ cypress: ^13.9.0
depcheck: ^1.4.7
dotenv: ^16.3.1
draft-convert: ^2.1.13
@@ -19438,6 +20125,7 @@ __metadata:
react-native-gesture-handler: ~2.14.0
react-native-get-random-values: ~1.8.0
react-native-heroicons: ^3.2.0
+ react-native-hoverable: ^0.2.0
react-native-image-picker: ^7.1.0
react-native-keyboard-aware-scrollview: ^2.1.0
react-native-leaflet-view: ^0.1.2
@@ -19449,6 +20137,7 @@ __metadata:
react-native-qrcode-svg: ^6.2.0
react-native-reanimated: ^3.6.2
react-native-reanimated-carousel: 4.0.0-alpha.9
+ react-native-reanimated-table: ^0.0.2
react-native-redash: ^18.0.0
react-native-safe-area-context: 4.8.2
react-native-screens: ~3.29.0
@@ -19478,6 +20167,7 @@ __metadata:
waveform-data: ^4.3.0
yaml: ^2.3.4
zod: ^3.22.4
+ zustand: ^4.4.7
languageName: unknown
linkType: soft
@@ -19562,6 +20252,13 @@ __metadata:
languageName: node
linkType: hard
+"throttleit@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "throttleit@npm:1.0.1"
+ checksum: 32e0b12ca5810cd34dfce0408c7cb658dfd039848a073466eaac667ce6e846cafa53ac518e4b01dc6f34e6652b66fd29a5c6b666718ec5086ef328a9d029dc75
+ languageName: node
+ linkType: hard
+
"through2@npm:^2.0.1":
version: 2.0.5
resolution: "through2@npm:2.0.5"
@@ -19572,7 +20269,7 @@ __metadata:
languageName: node
linkType: hard
-"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.6":
+"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.6, through@npm:^2.3.8":
version: 2.3.8
resolution: "through@npm:2.3.8"
checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd
@@ -19607,6 +20304,13 @@ __metadata:
languageName: node
linkType: hard
+"tmp@npm:~0.2.1":
+ version: 0.2.3
+ resolution: "tmp@npm:0.2.3"
+ checksum: 73b5c96b6e52da7e104d9d44afb5d106bb1e16d9fa7d00dbeb9e6522e61b571fbdb165c756c62164be9a3bbe192b9b268c236d370a2a0955c7689cd2ae377b95
+ languageName: node
+ linkType: hard
+
"tmpl@npm:1.0.5":
version: 1.0.5
resolution: "tmpl@npm:1.0.5"
@@ -19637,6 +20341,18 @@ __metadata:
languageName: node
linkType: hard
+"tough-cookie@npm:^4.1.3":
+ version: 4.1.4
+ resolution: "tough-cookie@npm:4.1.4"
+ dependencies:
+ psl: ^1.1.33
+ punycode: ^2.1.1
+ universalify: ^0.2.0
+ url-parse: ^1.5.3
+ checksum: 5815059f014c31179a303c673f753f7899a6fce94ac93712c88ea5f3c26e0c042b5f0c7a599a00f8e0feeca4615dba75c3dffc54f3c1a489978aa8205e09307c
+ languageName: node
+ linkType: hard
+
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
@@ -19766,6 +20482,22 @@ __metadata:
languageName: node
linkType: hard
+"tunnel-agent@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "tunnel-agent@npm:0.6.0"
+ dependencies:
+ safe-buffer: ^5.0.1
+ checksum: 05f6510358f8afc62a057b8b692f05d70c1782b70db86d6a1e0d5e28a32389e52fa6e7707b6c5ecccacc031462e4bc35af85ecfe4bbc341767917b7cf6965711
+ languageName: node
+ linkType: hard
+
+"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0":
+ version: 0.14.5
+ resolution: "tweetnacl@npm:0.14.5"
+ checksum: 6061daba1724f59473d99a7bb82e13f211cdf6e31315510ae9656fefd4779851cb927adad90f3b488c8ed77c106adc0421ea8055f6f976ff21b27c5c4e918487
+ languageName: node
+ linkType: hard
+
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
version: 0.4.0
resolution: "type-check@npm:0.4.0"
@@ -20164,6 +20896,13 @@ __metadata:
languageName: node
linkType: hard
+"universalify@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "universalify@npm:0.2.0"
+ checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5
+ languageName: node
+ linkType: hard
+
"universalify@npm:^1.0.0":
version: 1.0.0
resolution: "universalify@npm:1.0.0"
@@ -20192,6 +20931,13 @@ __metadata:
languageName: node
linkType: hard
+"untildify@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "untildify@npm:4.0.0"
+ checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9
+ languageName: node
+ linkType: hard
+
"update-browserslist-db@npm:^1.0.13":
version: 1.0.13
resolution: "update-browserslist-db@npm:1.0.13"
@@ -20222,6 +20968,16 @@ __metadata:
languageName: node
linkType: hard
+"url-parse@npm:^1.5.3":
+ version: 1.5.10
+ resolution: "url-parse@npm:1.5.10"
+ dependencies:
+ querystringify: ^2.1.1
+ requires-port: ^1.0.0
+ checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf
+ languageName: node
+ linkType: hard
+
"use-latest-callback@npm:^0.1.7":
version: 0.1.9
resolution: "use-latest-callback@npm:0.1.9"
@@ -20231,7 +20987,7 @@ __metadata:
languageName: node
linkType: hard
-"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0":
+"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0":
version: 1.2.0
resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
@@ -20364,6 +21120,17 @@ __metadata:
languageName: node
linkType: hard
+"verror@npm:1.10.0":
+ version: 1.10.0
+ resolution: "verror@npm:1.10.0"
+ dependencies:
+ assert-plus: ^1.0.0
+ core-util-is: 1.0.2
+ extsprintf: ^1.2.0
+ checksum: c431df0bedf2088b227a4e051e0ff4ca54df2c114096b0c01e1cbaadb021c30a04d7dd5b41ab277bcd51246ca135bf931d4c4c796ecae7a4fef6d744ecef36ea
+ languageName: node
+ linkType: hard
+
"vfile-message@npm:^3.0.0":
version: 3.1.4
resolution: "vfile-message@npm:3.1.4"
@@ -21449,3 +22216,23 @@ __metadata:
checksum: 80bfd7f8039b24fddeb0718a2ec7c02aa9856e4838d6aa4864335a047b6b37a3273b191ef335bf0b2002e5c514ef261ffcda5a589fb084a48c336ffc4cdbab7f
languageName: node
linkType: hard
+
+"zustand@npm:^4.4.7":
+ version: 4.5.0
+ resolution: "zustand@npm:4.5.0"
+ dependencies:
+ use-sync-external-store: 1.2.0
+ peerDependencies:
+ "@types/react": ">=16.8"
+ immer: ">=9.0.6"
+ react: ">=16.8"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ checksum: 91685492ab33bb656b98e07d8fff2be1794d8e68ac5dc546ec457f4ae3d709f0c19de9e93045b9ee5d6b704f64503d9e085ffe1f600f6ade0459e572d1cf5c0d
+ languageName: node
+ linkType: hard