From 4871053072b0b6063928254c1f01ee27c02ee16d Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:58:08 -0800 Subject: [PATCH 01/32] fix: currency display in non-english locales --- src/lib/components/elements/asset.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/components/elements/asset.svelte b/src/lib/components/elements/asset.svelte index b17fcd61..9be07b61 100644 --- a/src/lib/components/elements/asset.svelte +++ b/src/lib/components/elements/asset.svelte @@ -29,6 +29,7 @@ const currencyOptions: Intl.NumberFormatOptions = { style: 'currency', currency: asset?.symbol.name, + currencyDisplay: 'narrowSymbol', minimumFractionDigits: context.settings.data.advancedMode ? asset?.symbol.precision : undefined }; From a302c8cf730ce5fcb3ae2a2f5bd02c1e6e8f8ed6 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Mon, 2 Dec 2024 19:23:19 -0800 Subject: [PATCH 02/32] Fixed action layout --- .../actions/[action]/[[data]]/+page.svelte | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/routes/[network]/(explorer)/contract/[contract]/actions/[action]/[[data]]/+page.svelte b/src/routes/[network]/(explorer)/contract/[contract]/actions/[action]/[[data]]/+page.svelte index ea98bfba..58d87297 100644 --- a/src/routes/[network]/(explorer)/contract/[contract]/actions/[action]/[[data]]/+page.svelte +++ b/src/routes/[network]/(explorer)/contract/[contract]/actions/[action]/[[data]]/+page.svelte @@ -10,12 +10,11 @@ import Button from '$lib/components/button/button.svelte'; import Card from '$lib/components/layout/box/card.svelte'; import Code from '$lib/components/code.svelte'; - import Grid from '$lib/components/layout/grid.svelte'; import Label from '$lib/components/input/label.svelte'; - import Stack from '$lib/components/layout/stack.svelte'; import Textinput from '$lib/components/input/text.svelte'; import Fields from './fields.svelte'; + import { MultiCard } from '$lib/components/layout'; const { data } = $props(); @@ -118,32 +117,30 @@ } - - - - - - - - {#if data.ricardian} -

Ricardian Contract

- {#if data.ricardian.meta} -

Title: {data.ricardian.meta.title}

-

Summary: {data.ricardian.meta.summary}

- {/if} - {#if data.ricardian.text} -

{data.ricardian.text}

- {/if} + + + + + + + {#if data.ricardian} +

Ricardian Contract

+ {#if data.ricardian.meta} +

Title: {data.ricardian.meta.title}

+

Summary: {data.ricardian.meta.summary}

{/if} -

Data Representation

- {#if decoded} - {JSON.stringify(decoded, null, 2)} - {:else} -

Fill out the form to create a representation of the data in this type of action.

+ {#if data.ricardian.text} +

{data.ricardian.text}

{/if} -
-
-
+ {/if} +

Data Representation

+ {#if decoded} + {JSON.stringify(decoded, null, 2)} + {:else} +

Fill out the form to create a representation of the data in this type of action.

+ {/if} + +

Transaction Link

From cc867b379f50a0861096c5feef4a7810c973ef3c Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Wed, 4 Dec 2024 18:11:38 -0800 Subject: [PATCH 03/32] Updated MetaMask plugins --- bun.lockb | Bin 257448 -> 257432 bytes package.json | 4 ++-- yarn.lock | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bun.lockb b/bun.lockb index 4467472f8ba15dd21fb0a04416c59a1e10b99b00..772574f4624a693dc1bd37286d6639763515d692 100755 GIT binary patch delta 22811 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 HmY@F*$7QOY delta 22853 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 F{{sysvNQky diff --git a/package.json b/package.json index e4043456..90979b12 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@tailwindcss/container-queries": "^0.1.1", "@wharfkit/account": "^1.2.0", "@wharfkit/account-creation-plugin-greymass": "^1.2.0", - "@wharfkit/account-creation-plugin-metamask": "^1.0.2", + "@wharfkit/account-creation-plugin-metamask": "^1.1.1", "@wharfkit/antelope": "^1.0.11", "@wharfkit/common": "^1.4.0", "@wharfkit/contract": "^1.1.5", @@ -62,7 +62,7 @@ "@wharfkit/session": "^1.4.0", "@wharfkit/transact-plugin-resource-provider": "^1.1.1", "@wharfkit/wallet-plugin-anchor": "^1.4.0", - "@wharfkit/wallet-plugin-metamask": "1.0.0-rc10", + "@wharfkit/wallet-plugin-metamask": "^1.1.0", "@wharfkit/wallet-plugin-privatekey": "^1.1.0", "@wharfkit/wallet-plugin-scatter": "^1.5.1", "@wharfkit/wallet-plugin-tokenpocket": "^1.5.1", diff --git a/yarn.lock b/yarn.lock index 0739b77c..336c6fe1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,6 +1,6 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 -# bun ./bun.lockb --hash: 3831074445BB38D9-319bbcb8908b3c95-0BAE303A407F69C6-a6664dd7a47d6926 +# bun ./bun.lockb --hash: ECB05F2A4F6B5A6B-e8c95a7b99cf9889-8602410DB5AD8AB1-91762af158999f06 "@accuser/svelte-plausible-analytics@^1.0.0": @@ -1467,10 +1467,10 @@ "@greymass/create-account" "greymass/create-account" tslib "^2.1.0" -"@wharfkit/account-creation-plugin-metamask@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@wharfkit/account-creation-plugin-metamask/-/account-creation-plugin-metamask-1.0.2.tgz" - integrity sha512-OPLqzADfoHEoO+ND5/d9ERlLOZT9wz7KL3oilXmajbtri6ucirwqNgAMClxOFPcerXzct+/EYFnSIxIVnpsWfg== +"@wharfkit/account-creation-plugin-metamask@^1.1.1": + version "1.1.1" + resolved "https://registry.npmjs.org/@wharfkit/account-creation-plugin-metamask/-/account-creation-plugin-metamask-1.1.1.tgz" + integrity sha512-CqeLZWPrNU1eqj+Rxqm6c4IdtPF0DhX5BP5RoUF0ISWeCq23+R+CboCvugEUC6u15YIjHSqxsSV60FgRM5kHBA== dependencies: "@greymass/create-account" "^1.0.2" "@metamask/providers" "^17.0.0" @@ -1601,10 +1601,10 @@ isomorphic-ws "^5.0.0" ws "^8.13.0" -"@wharfkit/wallet-plugin-metamask@1.0.0-rc10": - version "1.0.0-rc10" - resolved "https://registry.npmjs.org/@wharfkit/wallet-plugin-metamask/-/wallet-plugin-metamask-1.0.0-rc10.tgz" - integrity sha512-y+3W2L83YCNYlRzJLIcSJ1GwW/98eykeJmu6LAsbhHjsx9aOCOKLXU5DHHWTlRB+Vmd8i09ExSaV/tfFPy54SQ== +"@wharfkit/wallet-plugin-metamask@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@wharfkit/wallet-plugin-metamask/-/wallet-plugin-metamask-1.1.0.tgz" + integrity sha512-ve5GnIX7myxbPrLrGITvHCW6CKyYEMHx0R2FC5QT3ItF2ImPfYRysodnRbv2KfVewrJK/uDvzxIs4VhU9HZjGQ== dependencies: "@metamask/providers" "^17.0.0" tslib "^2.1.0" From 4bb4cf9827416580a55a7a4a2c7bcd816c14baaa Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Wed, 4 Dec 2024 18:23:25 -0800 Subject: [PATCH 04/32] Updating key display logic for advanced mode --- src/lib/state/metamask.svelte.ts | 3 ++- .../(wallets)/metamask/+page.svelte | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/lib/state/metamask.svelte.ts b/src/lib/state/metamask.svelte.ts index e645c923..912369a4 100644 --- a/src/lib/state/metamask.svelte.ts +++ b/src/lib/state/metamask.svelte.ts @@ -9,7 +9,8 @@ export class MetaMaskState { public isInstalled = $state(false); public error = $state(null); public installedSnap = $state(null); - public publicKey = $state(null); + public publicKey = $state(null); // active + public ownerKey = $state(null); // owner public snapsDetected = $derived(this.snapProvider !== null); diff --git a/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte b/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte index f0875233..eac31177 100644 --- a/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte +++ b/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte @@ -39,9 +39,10 @@ if (isInstalled) { connect(); accountCreationPluginMetamask - .retrievePublicKey(data.network.chain.id) + .retrievePublicKeys(data.network.chain.id) .then((publicKey) => { - metaMaskState.publicKey = publicKey; + metaMaskState.publicKey = publicKey.activePublicKey; + metaMaskState.ownerKey = publicKey.ownerPublicKey; }); } }); @@ -221,8 +222,18 @@ {/if} {#if context.settings.data.advancedMode} -

EOS Wallet Public Key

-

{metaMaskState.publicKey}

+

EOS Wallet Public Key (Active)

+

+ + {metaMaskState.publicKey} + +

+

EOS Wallet Public Key (Owner)

+

+ + {metaMaskState.ownerKey} + +

{/if} {/if} From 0aadff199d4f6c165a5670b7b6f279e30004f319 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Fri, 15 Nov 2024 18:13:27 -0800 Subject: [PATCH 05/32] Scaffolding out msig page data --- .../msig/[proposer]/[proposal]/+page.svelte | 8 +-- .../msig/[proposer]/[proposal]/+page.ts | 47 +++++++-------- .../api/msig/[proposer]/[proposal]/+server.ts | 59 +++++++++++++++++++ 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 src/routes/[network]/api/msig/[proposer]/[proposal]/+server.ts diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte index bb02bd93..08f3a03c 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte @@ -1,7 +1,7 @@
 {JSON.stringify(data.proposal, null, 2)}
-
--> + diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts index 36fb3d7f..62e2c146 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts @@ -1,26 +1,27 @@ -// import { error } from '@sveltejs/kit'; -// import { Name, type API } from '@wharfkit/antelope'; - +import { PackedTransaction } from '@wharfkit/antelope'; import type { PageLoad } from './$types'; -export const load: PageLoad = async () => { - // const result = await getClient(fetch).v1.chain.get_table_rows({ - // code: 'eosio.msig', - // scope: params.proposer, - // table: 'proposal', - // lower_bound: Name.from(params.proposal), - // upper_bound: Name.from(params.proposal), - // limit: 1 - // }); - // if (!result.rows.length) { - // return error(404, { - // message: `Proposal ${params.proposer}/${params.proposal} not found.` - // }); - // } - // const proposal = result.rows[0]; - // return { - // proposer: params.proposer, - // name: params.proposal, - // proposal - // }; +export const load: PageLoad = async ({ fetch, params, parent }) => { + const { network } = await parent(); + const response = await fetch(`/${params.network}/api/msig/${params.proposer}/${params.proposal}`); + const json = await response.json(); + const packed = PackedTransaction.from({ + compression: false, + signatures: [], + packed_trx: json.proposal.packed_transaction, + packed_context_free_data: [] + }); + const transaction = packed.getTransaction(); + return { + title: `${params.proposal}`, + subtitle: `An MSIG proposed by ${params.proposer} on the ${network.chain.name} Network`, + proposal: { + approvals: json.approvals, + proposer: params.proposer, + name: params.proposal, + hash: transaction.id, + packed, + transaction + } + }; }; diff --git a/src/routes/[network]/api/msig/[proposer]/[proposal]/+server.ts b/src/routes/[network]/api/msig/[proposer]/[proposal]/+server.ts new file mode 100644 index 00000000..a940bce3 --- /dev/null +++ b/src/routes/[network]/api/msig/[proposer]/[proposal]/+server.ts @@ -0,0 +1,59 @@ +import { json, type RequestEvent } from '@sveltejs/kit'; + +import { getChainDefinitionFromParams } from '$lib/state/network.svelte'; +import { Name } from '@wharfkit/antelope'; +import { getCacheHeaders } from '$lib/utils'; +import { getBackendNetwork } from '$lib/wharf/client/ssr.js'; + +export async function GET({ fetch, params }: RequestEvent) { + const chain = getChainDefinitionFromParams(String(params.network)); + if (!chain) { + return json({ error: 'Invalid chain specified' }, { status: 400 }); + } + if (!params.proposer) { + return json({ error: 'Proposer must be specified' }, { status: 400 }); + } + if (!params.proposal) { + return json({ error: 'Proposal name required' }, { status: 400 }); + } + + const network = getBackendNetwork(chain, fetch); + + const proposals = await network.client.v1.chain.get_table_rows({ + code: 'eosio.msig', + scope: params.proposer, + table: 'proposal', + lower_bound: Name.from(params.proposal), + upper_bound: Name.from(params.proposal), + limit: 1 + }); + + const approvals2 = await network.client.v1.chain.get_table_rows({ + code: 'eosio.msig', + scope: params.proposer, + table: 'approvals2', + lower_bound: Name.from(params.proposal), + upper_bound: Name.from(params.proposal), + limit: 1 + }); + + if (!proposals.rows.length) { + return json({ error: 'msig record not found' }, { status: 400 }); + } + + const proposal = proposals.rows[0]; + const approvals = approvals2.rows[0]; + + return json( + { + ts: new Date(), + proposer: params.proposer, + name: params.proposal, + proposal, + approvals + }, + { + headers: getCacheHeaders(5) + } + ); +} From ec1b546adc843417d8fbc100ae2e851acd9f6a88 Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:19:42 -0800 Subject: [PATCH 06/32] feat: msig layout --- .../msig/[proposer]/[proposal]/+layout.svelte | 26 +++ .../msig/[proposer]/[proposal]/+layout.ts | 27 +++ .../msig/[proposer]/[proposal]/+page.svelte | 173 ++++++++++++++++-- .../msig/[proposer]/[proposal]/+page.ts | 36 ++-- .../[proposer]/[proposal]/data/+page.svelte | 9 + 5 files changed, 238 insertions(+), 33 deletions(-) create mode 100644 src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.svelte create mode 100644 src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts create mode 100644 src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/data/+page.svelte diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.svelte new file mode 100644 index 00000000..d7015c47 --- /dev/null +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.svelte @@ -0,0 +1,26 @@ + + + + {#if settings.data.debugMode} + + {/if} + + {@render children()} + diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts new file mode 100644 index 00000000..f6008f10 --- /dev/null +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts @@ -0,0 +1,27 @@ +import { PackedTransaction } from '@wharfkit/antelope'; +import type { LayoutLoad } from './$types'; + +export const load: LayoutLoad = async ({ fetch, params, parent }) => { + const { network } = await parent(); + const response = await fetch(`/${params.network}/api/msig/${params.proposer}/${params.proposal}`); + const json = await response.json(); + const packed = PackedTransaction.from({ + compression: false, + signatures: [], + packed_trx: json.proposal.packed_transaction, + packed_context_free_data: [] + }); + const transaction = packed.getTransaction(); + return { + title: `${params.proposal}`, + subtitle: `An MSIG proposed by ${params.proposer} on the ${network.chain.name} Network`, + proposal: { + approvals: json.approvals, + proposer: params.proposer, + name: params.proposal, + hash: transaction.id, + packed, + transaction + } + }; +}; diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte index 08f3a03c..278fcd31 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte @@ -1,16 +1,167 @@ - + +
+
+
+ + + + {totalApproved} + + Approved +
+ +
+ + + + {totalRequested} + + Requested +
+
+
+ + +

Requested Approvals

+ + + + + + + + + + + {#each proposal.approvals.requested_approvals as requested} + {@const { actor, permission } = requested.level} + + + + + + {/each} + +
ActorPermissionStatus
{permission} + {@render approvalCard(nameHasApproved(Name.from(actor)))} +
+
+ + +

Proposed Actions

+ {#each proposal.transaction.actions as action} + {JSON.stringify(action, null, 2)} + {/each} +
+ + +

Details

+ +
+ + + + + {proposal.name} + + + {proposal.transaction.expiration} ({relativeTimeToExpiry}) + + + {proposal.hash} + +
+ + +
+ + + {#if userIsApprover} + {#if userHasApproved} + + {:else} + + {/if} + {/if} + + {#if userIsProposer && !alreadyExpired} + + {/if} +
+ +{#snippet approvalCard(approved?: boolean)} + {#if approved} + Approved + {:else} + Pending + {/if} +{/snippet} - -
-{JSON.stringify(data.proposal, null, 2)}
-
+ diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts index 62e2c146..30d4e280 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts @@ -1,27 +1,19 @@ -import { PackedTransaction } from '@wharfkit/antelope'; +import { Name } from '@wharfkit/antelope'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ fetch, params, parent }) => { - const { network } = await parent(); - const response = await fetch(`/${params.network}/api/msig/${params.proposer}/${params.proposal}`); - const json = await response.json(); - const packed = PackedTransaction.from({ - compression: false, - signatures: [], - packed_trx: json.proposal.packed_transaction, - packed_context_free_data: [] - }); - const transaction = packed.getTransaction(); +export const load: PageLoad = async ({ parent }) => { + const { proposal } = await parent(); + + const requested_names: Name[] = proposal.approvals.requested_approvals.map(({ level }) => + Name.from(level.actor) + ); + + const provided_names: Name[] = proposal.approvals.provided_approvals.map(({ level }) => + Name.from(level.actor) + ); + return { - title: `${params.proposal}`, - subtitle: `An MSIG proposed by ${params.proposer} on the ${network.chain.name} Network`, - proposal: { - approvals: json.approvals, - proposer: params.proposer, - name: params.proposal, - hash: transaction.id, - packed, - transaction - } + requested_names, + provided_names }; }; diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/data/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/data/+page.svelte new file mode 100644 index 00000000..cfde73ac --- /dev/null +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/data/+page.svelte @@ -0,0 +1,9 @@ + + + + {JSON.stringify(props.data, null, 2)} + From 411b95a4e6318dfe3db5b84ec3470df715b3b2b3 Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:24:11 -0800 Subject: [PATCH 07/32] fix: type error --- .../(explorer)/msig/[proposer]/[proposal]/+page.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts index 30d4e280..489162b5 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts @@ -1,15 +1,16 @@ import { Name } from '@wharfkit/antelope'; import type { PageLoad } from './$types'; +import { PermissionLevel } from '@wharfkit/antelope'; export const load: PageLoad = async ({ parent }) => { const { proposal } = await parent(); - const requested_names: Name[] = proposal.approvals.requested_approvals.map(({ level }) => - Name.from(level.actor) + const requested_names: Name[] = proposal.approvals.requested_approvals.map( + ({ level }: { level: PermissionLevel }) => Name.from(level.actor) ); - const provided_names: Name[] = proposal.approvals.provided_approvals.map(({ level }) => - Name.from(level.actor) + const provided_names: Name[] = proposal.approvals.provided_approvals.map( + ({ level }: { level: PermissionLevel }) => Name.from(level.actor) ); return { From 796776a37dee6983c609ac3223e99832f03494fb Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Mon, 2 Dec 2024 19:14:09 -0800 Subject: [PATCH 08/32] Adding msig contract --- Makefile | 1 + src/lib/state/network.svelte.ts | 2 + src/lib/wharf/chains.ts | 2 + src/lib/wharf/contracts/msig.ts | 264 ++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 src/lib/wharf/contracts/msig.ts diff --git a/Makefile b/Makefile index 1f1cb727..5a1929ee 100644 --- a/Makefile +++ b/Makefile @@ -32,4 +32,5 @@ install: codegen: npx @wharfkit/cli generate -u $(API_EOS_CHAIN) -f src/lib/wharf/contracts/system.ts eosio npx @wharfkit/cli generate -u $(API_EOS_CHAIN) -f src/lib/wharf/contracts/token.ts eosio.token + npx @wharfkit/cli generate -u $(API_EOS_CHAIN) -f src/lib/wharf/contracts/msig.ts eosio.msig npx @wharfkit/cli generate -u $(API_EOS_CHAIN) -f src/lib/wharf/contracts/delphioracle.ts delphioracle diff --git a/src/lib/state/network.svelte.ts b/src/lib/state/network.svelte.ts index 28f979c4..389469e4 100644 --- a/src/lib/state/network.svelte.ts +++ b/src/lib/state/network.svelte.ts @@ -6,6 +6,7 @@ import { snapOrigins } from '@wharfkit/wallet-plugin-metamask'; import { Types as DelphiOracleTypes } from '$lib/wharf/contracts/delphioracle'; import { Contract as DelphiOracleContract } from '$lib/wharf/contracts/delphioracle'; +import { Contract as MSIGContract } from '$lib/wharf/contracts/msig'; import { Contract as SystemContract, Types as SystemTypes } from '$lib/wharf/contracts/system'; import { Contract as TokenContract } from '$lib/wharf/contracts/token'; @@ -81,6 +82,7 @@ export class NetworkState { }); this.contracts = { + msig: new MSIGContract({ client: this.client }), token: new TokenContract({ client: this.client }), system: new SystemContract({ client: this.client }) }; diff --git a/src/lib/wharf/chains.ts b/src/lib/wharf/chains.ts index 14aee4f3..02290ad2 100644 --- a/src/lib/wharf/chains.ts +++ b/src/lib/wharf/chains.ts @@ -2,11 +2,13 @@ import type { Asset } from '@wharfkit/antelope'; import type { ChainIndices } from '@wharfkit/common'; import { Contract as DelphiOracleContract } from '$lib/wharf/contracts/delphioracle'; +import { Contract as MSIGContract } from '$lib/wharf/contracts/msig'; import { Contract as SystemContract } from '$lib/wharf/contracts/system'; import { Contract as TokenContract } from '$lib/wharf/contracts/token'; export interface DefaultContracts { delphioracle?: DelphiOracleContract; + msig: MSIGContract; token: TokenContract; system: SystemContract; } diff --git a/src/lib/wharf/contracts/msig.ts b/src/lib/wharf/contracts/msig.ts new file mode 100644 index 00000000..2e9c5ea1 --- /dev/null +++ b/src/lib/wharf/contracts/msig.ts @@ -0,0 +1,264 @@ +import type {Action, BytesType, Checksum256Type, NameType, UInt16Type} from '@wharfkit/antelope' +import { + ABI, + Blob, + Bytes, + Checksum256, + Name, + Struct, + TimePoint, + TimePointSec, + UInt16, + UInt32, + UInt8, + VarUInt, +} from '@wharfkit/antelope' +import type {ActionOptions, ContractArgs, PartialBy, Table} from '@wharfkit/contract' +import {Contract as BaseContract} from '@wharfkit/contract' +export const abiBlob = Blob.from( + 'DmVvc2lvOjphYmkvMS4yABAGYWN0aW9uAAQHYWNjb3VudARuYW1lBG5hbWUEbmFtZQ1hdXRob3JpemF0aW9uEnBlcm1pc3Npb25fbGV2ZWxbXQRkYXRhBWJ5dGVzCGFwcHJvdmFsAAIFbGV2ZWwQcGVybWlzc2lvbl9sZXZlbAR0aW1lCnRpbWVfcG9pbnQOYXBwcm92YWxzX2luZm8ABAd2ZXJzaW9uBXVpbnQ4DXByb3Bvc2FsX25hbWUEbmFtZRNyZXF1ZXN0ZWRfYXBwcm92YWxzCmFwcHJvdmFsW10ScHJvdmlkZWRfYXBwcm92YWxzCmFwcHJvdmFsW10HYXBwcm92ZQAECHByb3Bvc2VyBG5hbWUNcHJvcG9zYWxfbmFtZQRuYW1lBWxldmVsEHBlcm1pc3Npb25fbGV2ZWwNcHJvcG9zYWxfaGFzaAxjaGVja3N1bTI1NiQGY2FuY2VsAAMIcHJvcG9zZXIEbmFtZQ1wcm9wb3NhbF9uYW1lBG5hbWUIY2FuY2VsZXIEbmFtZQRleGVjAAMIcHJvcG9zZXIEbmFtZQ1wcm9wb3NhbF9uYW1lBG5hbWUIZXhlY3V0ZXIEbmFtZQlleHRlbnNpb24AAgR0eXBlBnVpbnQxNgRkYXRhBWJ5dGVzCmludmFsaWRhdGUAAQdhY2NvdW50BG5hbWUMaW52YWxpZGF0aW9uAAIHYWNjb3VudARuYW1lFmxhc3RfaW52YWxpZGF0aW9uX3RpbWUKdGltZV9wb2ludBJvbGRfYXBwcm92YWxzX2luZm8AAw1wcm9wb3NhbF9uYW1lBG5hbWUTcmVxdWVzdGVkX2FwcHJvdmFscxJwZXJtaXNzaW9uX2xldmVsW10ScHJvdmlkZWRfYXBwcm92YWxzEnBlcm1pc3Npb25fbGV2ZWxbXRBwZXJtaXNzaW9uX2xldmVsAAIFYWN0b3IEbmFtZQpwZXJtaXNzaW9uBG5hbWUIcHJvcG9zYWwAAw1wcm9wb3NhbF9uYW1lBG5hbWUScGFja2VkX3RyYW5zYWN0aW9uBWJ5dGVzEmVhcmxpZXN0X2V4ZWNfdGltZQx0aW1lX3BvaW50PyQHcHJvcG9zZQAECHByb3Bvc2VyBG5hbWUNcHJvcG9zYWxfbmFtZQRuYW1lCXJlcXVlc3RlZBJwZXJtaXNzaW9uX2xldmVsW10DdHJ4C3RyYW5zYWN0aW9uC3RyYW5zYWN0aW9uEnRyYW5zYWN0aW9uX2hlYWRlcgMUY29udGV4dF9mcmVlX2FjdGlvbnMIYWN0aW9uW10HYWN0aW9ucwhhY3Rpb25bXRZ0cmFuc2FjdGlvbl9leHRlbnNpb25zC2V4dGVuc2lvbltdEnRyYW5zYWN0aW9uX2hlYWRlcgAGCmV4cGlyYXRpb24OdGltZV9wb2ludF9zZWMNcmVmX2Jsb2NrX251bQZ1aW50MTYQcmVmX2Jsb2NrX3ByZWZpeAZ1aW50MzITbWF4X25ldF91c2FnZV93b3Jkcwl2YXJ1aW50MzIQbWF4X2NwdV91c2FnZV9tcwV1aW50OAlkZWxheV9zZWMJdmFydWludDMyCXVuYXBwcm92ZQADCHByb3Bvc2VyBG5hbWUNcHJvcG9zYWxfbmFtZQRuYW1lBWxldmVsEHBlcm1pc3Npb25fbGV2ZWwGAAAAQG16azUHYXBwcm92ZdYDLS0tCnNwZWNfdmVyc2lvbjogIjAuMi4wIgp0aXRsZTogQXBwcm92ZSBQcm9wb3NlZCBUcmFuc2FjdGlvbgpzdW1tYXJ5OiAne3tub3dyYXAgbGV2ZWwuYWN0b3J9fSBhcHByb3ZlcyB0aGUge3tub3dyYXAgcHJvcG9zYWxfbmFtZX19IHByb3Bvc2FsJwppY29uOiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZW9zbmV0d29ya2ZvdW5kYXRpb24vZW9zLXN5c3RlbS1jb250cmFjdHMvbWFpbi9jb250cmFjdHMvaWNvbnMvbXVsdGlzaWcucG5nIzRmYjQxZDNjZjAyZDBkZDJkMzVhMjkzMDhlOTNjMmQ4MjZlYzc3MGQ2YmI1MjBkYjY2OGY1MzA3NjRiZTcxNTMKLS0tCgp7e2xldmVsLmFjdG9yfX0gYXBwcm92ZXMgdGhlIHt7cHJvcG9zYWxfbmFtZX19IHByb3Bvc2FsIHByb3Bvc2VkIGJ5IHt7cHJvcG9zZXJ9fSB3aXRoIHRoZSB7e2xldmVsLnBlcm1pc3Npb259fSBwZXJtaXNzaW9uIG9mIHt7bGV2ZWwuYWN0b3J9fS4AAAAARIWmQQZjYW5jZWySAy0tLQpzcGVjX3ZlcnNpb246ICIwLjIuMCIKdGl0bGU6IENhbmNlbCBQcm9wb3NlZCBUcmFuc2FjdGlvbgpzdW1tYXJ5OiAne3tub3dyYXAgY2FuY2VsZXJ9fSBjYW5jZWxzIHRoZSB7e25vd3JhcCBwcm9wb3NhbF9uYW1lfX0gcHJvcG9zYWwnCmljb246IGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lb3NuZXR3b3JrZm91bmRhdGlvbi9lb3Mtc3lzdGVtLWNvbnRyYWN0cy9tYWluL2NvbnRyYWN0cy9pY29ucy9tdWx0aXNpZy5wbmcjNGZiNDFkM2NmMDJkMGRkMmQzNWEyOTMwOGU5M2MyZDgyNmVjNzcwZDZiYjUyMGRiNjY4ZjUzMDc2NGJlNzE1MwotLS0KCnt7Y2FuY2VsZXJ9fSBjYW5jZWxzIHRoZSB7e3Byb3Bvc2FsX25hbWV9fSBwcm9wb3NhbCBzdWJtaXR0ZWQgYnkge3twcm9wb3Nlcn19LgAAAAAAgFRXBGV4ZWPaAy0tLQpzcGVjX3ZlcnNpb246ICIwLjIuMCIKdGl0bGU6IEV4ZWN1dGUgUHJvcG9zZWQgVHJhbnNhY3Rpb24Kc3VtbWFyeTogJ3t7bm93cmFwIGV4ZWN1dGVyfX0gZXhlY3V0ZXMgdGhlIHt7bm93cmFwIHByb3Bvc2FsX25hbWV9fSBwcm9wb3NhbCcKaWNvbjogaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Vvc25ldHdvcmtmb3VuZGF0aW9uL2Vvcy1zeXN0ZW0tY29udHJhY3RzL21haW4vY29udHJhY3RzL2ljb25zL211bHRpc2lnLnBuZyM0ZmI0MWQzY2YwMmQwZGQyZDM1YTI5MzA4ZTkzYzJkODI2ZWM3NzBkNmJiNTIwZGI2NjhmNTMwNzY0YmU3MTUzCi0tLQoKe3tleGVjdXRlcn19IGV4ZWN1dGVzIHRoZSB7e3Byb3Bvc2FsX25hbWV9fSBwcm9wb3NhbCBzdWJtaXR0ZWQgYnkge3twcm9wb3Nlcn19IGlmIHRoZSBtaW5pbXVtIHJlcXVpcmVkIGFwcHJvdmFscyBmb3IgdGhlIHByb3Bvc2FsIGhhdmUgYmVlbiBzZWN1cmVkLgCAyia5aPZ0CmludmFsaWRhdGWQAy0tLQpzcGVjX3ZlcnNpb246ICIwLjIuMCIKdGl0bGU6IEludmFsaWRhdGUgQWxsIEFwcHJvdmFscwpzdW1tYXJ5OiAne3tub3dyYXAgYWNjb3VudH19IGludmFsaWRhdGVzIGFwcHJvdmFscyBvbiBvdXRzdGFuZGluZyBwcm9wb3NhbHMnCmljb246IGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lb3NuZXR3b3JrZm91bmRhdGlvbi9lb3Mtc3lzdGVtLWNvbnRyYWN0cy9tYWluL2NvbnRyYWN0cy9pY29ucy9tdWx0aXNpZy5wbmcjNGZiNDFkM2NmMDJkMGRkMmQzNWEyOTMwOGU5M2MyZDgyNmVjNzcwZDZiYjUyMGRiNjY4ZjUzMDc2NGJlNzE1MwotLS0KCnt7YWNjb3VudH19IGludmFsaWRhdGVzIGFsbCBhcHByb3ZhbHMgb24gcHJvcG9zYWxzIHdoaWNoIGhhdmUgbm90IHlldCBleGVjdXRlZC4AAABAYVrprQdwcm9wb3NlvAUtLS0Kc3BlY192ZXJzaW9uOiAiMC4yLjAiCnRpdGxlOiBQcm9wb3NlIFRyYW5zYWN0aW9uCnN1bW1hcnk6ICd7e25vd3JhcCBwcm9wb3Nlcn19IGNyZWF0ZXMgdGhlIHt7bm93cmFwIHByb3Bvc2FsX25hbWV9fScKaWNvbjogaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Vvc25ldHdvcmtmb3VuZGF0aW9uL2Vvcy1zeXN0ZW0tY29udHJhY3RzL21haW4vY29udHJhY3RzL2ljb25zL211bHRpc2lnLnBuZyM0ZmI0MWQzY2YwMmQwZGQyZDM1YTI5MzA4ZTkzYzJkODI2ZWM3NzBkNmJiNTIwZGI2NjhmNTMwNzY0YmU3MTUzCi0tLQoKe3twcm9wb3Nlcn19IGNyZWF0ZXMgdGhlIHt7cHJvcG9zYWxfbmFtZX19IHByb3Bvc2FsIGZvciB0aGUgZm9sbG93aW5nIHRyYW5zYWN0aW9uOgp7e3RvX2pzb24gdHJ4fX0KClRoZSBwcm9wb3NhbCByZXF1ZXN0cyBhcHByb3ZhbHMgZnJvbSB0aGUgZm9sbG93aW5nIGFjY291bnRzIGF0IHRoZSBzcGVjaWZpZWQgcGVybWlzc2lvbiBsZXZlbHM6Cnt7I2VhY2ggcmVxdWVzdGVkfX0KICAgKyB7e3RoaXMucGVybWlzc2lvbn19IHBlcm1pc3Npb24gb2Yge3t0aGlzLmFjdG9yfX0Ke3svZWFjaH19CgpJZiB0aGUgcHJvcG9zZWQgdHJhbnNhY3Rpb24gaXMgbm90IGV4ZWN1dGVkIHByaW9yIHRvIHt7dHJ4LmV4cGlyYXRpb259fSwgdGhlIHByb3Bvc2FsIHdpbGwgYXV0b21hdGljYWxseSBleHBpcmUuAABQm95azdQJdW5hcHByb3ZljwQtLS0Kc3BlY192ZXJzaW9uOiAiMC4yLjAiCnRpdGxlOiBVbmFwcHJvdmUgUHJvcG9zZWQgVHJhbnNhY3Rpb24Kc3VtbWFyeTogJ3t7bm93cmFwIGxldmVsLmFjdG9yfX0gcmV2b2tlcyB0aGUgYXBwcm92YWwgcHJldmlvdXNseSBwcm92aWRlZCB0byB7e25vd3JhcCBwcm9wb3NhbF9uYW1lfX0gcHJvcG9zYWwnCmljb246IGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lb3NuZXR3b3JrZm91bmRhdGlvbi9lb3Mtc3lzdGVtLWNvbnRyYWN0cy9tYWluL2NvbnRyYWN0cy9pY29ucy9tdWx0aXNpZy5wbmcjNGZiNDFkM2NmMDJkMGRkMmQzNWEyOTMwOGU5M2MyZDgyNmVjNzcwZDZiYjUyMGRiNjY4ZjUzMDc2NGJlNzE1MwotLS0KCnt7bGV2ZWwuYWN0b3J9fSByZXZva2VzIHRoZSBhcHByb3ZhbCBwcmV2aW91c2x5IHByb3ZpZGVkIGF0IHRoZWlyIHt7bGV2ZWwucGVybWlzc2lvbn19IHBlcm1pc3Npb24gbGV2ZWwgZnJvbSB0aGUge3twcm9wb3NhbF9uYW1lfX0gcHJvcG9zYWwgcHJvcG9zZWQgYnkge3twcm9wb3Nlcn19LgQAAMDRbHprNQNpNjQAABJvbGRfYXBwcm92YWxzX2luZm8AgMDRbHprNQNpNjQAAA5hcHByb3ZhbHNfaW5mbwAAAADgaPZ0A2k2NAAADGludmFsaWRhdGlvbgAAANFgWumtA2k2NAAACHByb3Bvc2FsAAAAAAA=' +) +export const abi = ABI.from(abiBlob) +export namespace Types { + @Struct.type('permission_level') + export class permission_level extends Struct { + @Struct.field(Name) + declare actor: Name + @Struct.field(Name) + declare permission: Name + } + @Struct.type('action') + export class action extends Struct { + @Struct.field(Name) + declare account: Name + @Struct.field(Name) + declare name: Name + @Struct.field(permission_level, {array: true}) + declare authorization: permission_level[] + @Struct.field(Bytes) + declare data: Bytes + } + @Struct.type('approval') + export class approval extends Struct { + @Struct.field(permission_level) + declare level: permission_level + @Struct.field(TimePoint) + declare time: TimePoint + } + @Struct.type('approvals_info') + export class approvals_info extends Struct { + @Struct.field(UInt8) + declare version: UInt8 + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(approval, {array: true}) + declare requested_approvals: approval[] + @Struct.field(approval, {array: true}) + declare provided_approvals: approval[] + } + @Struct.type('approve') + export class approve extends Struct { + @Struct.field(Name) + declare proposer: Name + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(permission_level) + declare level: permission_level + @Struct.field(Checksum256, {optional: true}) + declare proposal_hash?: Checksum256 + } + @Struct.type('cancel') + export class cancel extends Struct { + @Struct.field(Name) + declare proposer: Name + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(Name) + declare canceler: Name + } + @Struct.type('exec') + export class exec extends Struct { + @Struct.field(Name) + declare proposer: Name + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(Name) + declare executer: Name + } + @Struct.type('extension') + export class extension extends Struct { + @Struct.field(UInt16) + declare type: UInt16 + @Struct.field(Bytes) + declare data: Bytes + } + @Struct.type('invalidate') + export class invalidate extends Struct { + @Struct.field(Name) + declare account: Name + } + @Struct.type('invalidation') + export class invalidation extends Struct { + @Struct.field(Name) + declare account: Name + @Struct.field(TimePoint) + declare last_invalidation_time: TimePoint + } + @Struct.type('old_approvals_info') + export class old_approvals_info extends Struct { + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(permission_level, {array: true}) + declare requested_approvals: permission_level[] + @Struct.field(permission_level, {array: true}) + declare provided_approvals: permission_level[] + } + @Struct.type('proposal') + export class proposal extends Struct { + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(Bytes) + declare packed_transaction: Bytes + @Struct.field(TimePoint, {optional: true}) + declare earliest_exec_time?: TimePoint + } + @Struct.type('transaction_header') + export class transaction_header extends Struct { + @Struct.field(TimePointSec) + declare expiration: TimePointSec + @Struct.field(UInt16) + declare ref_block_num: UInt16 + @Struct.field(UInt32) + declare ref_block_prefix: UInt32 + @Struct.field(VarUInt) + declare max_net_usage_words: VarUInt + @Struct.field(UInt8) + declare max_cpu_usage_ms: UInt8 + @Struct.field(VarUInt) + declare delay_sec: VarUInt + } + @Struct.type('transaction') + export class transaction extends transaction_header { + @Struct.field(action, {array: true}) + declare context_free_actions: action[] + @Struct.field(action, {array: true}) + declare actions: action[] + @Struct.field(extension, {array: true}) + declare transaction_extensions: extension[] + } + @Struct.type('propose') + export class propose extends Struct { + @Struct.field(Name) + declare proposer: Name + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(permission_level, {array: true}) + declare requested: permission_level[] + @Struct.field(transaction) + declare trx: transaction + } + @Struct.type('unapprove') + export class unapprove extends Struct { + @Struct.field(Name) + declare proposer: Name + @Struct.field(Name) + declare proposal_name: Name + @Struct.field(permission_level) + declare level: permission_level + } +} +export const TableMap = { + approvals: Types.old_approvals_info, + approvals2: Types.approvals_info, + invals: Types.invalidation, + proposal: Types.proposal, +} +export interface TableTypes { + approvals: Types.old_approvals_info + approvals2: Types.approvals_info + invals: Types.invalidation + proposal: Types.proposal +} +export type RowType = T extends keyof TableTypes ? TableTypes[T] : any +export type TableNames = keyof TableTypes +export namespace ActionParams { + export namespace Type { + export interface permission_level { + actor: NameType + permission: NameType + } + export interface transaction { + context_free_actions: Type.action[] + actions: Type.action[] + transaction_extensions: Type.extension[] + } + export interface action { + account: NameType + name: NameType + authorization: Type.permission_level[] + data: BytesType + } + export interface extension { + type: UInt16Type + data: BytesType + } + } + export interface approve { + proposer: NameType + proposal_name: NameType + level: Type.permission_level + proposal_hash?: Checksum256Type + } + export interface cancel { + proposer: NameType + proposal_name: NameType + canceler: NameType + } + export interface exec { + proposer: NameType + proposal_name: NameType + executer: NameType + } + export interface invalidate { + account: NameType + } + export interface propose { + proposer: NameType + proposal_name: NameType + requested: Type.permission_level[] + trx: Type.transaction + } + export interface unapprove { + proposer: NameType + proposal_name: NameType + level: Type.permission_level + } +} +export interface ActionNameParams { + approve: ActionParams.approve + cancel: ActionParams.cancel + exec: ActionParams.exec + invalidate: ActionParams.invalidate + propose: ActionParams.propose + unapprove: ActionParams.unapprove +} +export type ActionNames = keyof ActionNameParams +export class Contract extends BaseContract { + constructor(args: PartialBy) { + super({ + client: args.client, + abi: abi, + account: args.account || Name.from('eosio.msig'), + }) + } + action( + name: T, + data: ActionNameParams[T], + options?: ActionOptions + ): Action { + return super.action(name, data, options) + } + table(name: T, scope?: NameType): Table> { + return super.table(name, scope, TableMap[name]) + } +} From bc70526d539d6cd5e982f7e779fa6389c8d80e5b Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:55:35 -0800 Subject: [PATCH 09/32] feat: add approve/unapprove/exec actions --- .../msig/[proposer]/[proposal]/+layout.ts | 24 +++- .../msig/[proposer]/[proposal]/+page.svelte | 76 +++++++------ .../msig/[proposer]/[proposal]/+page.ts | 20 ---- .../[proposer]/[proposal]/manager.svelte.ts | 106 ++++++++++++++++++ 4 files changed, 172 insertions(+), 54 deletions(-) delete mode 100644 src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts create mode 100644 src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/manager.svelte.ts diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts index f6008f10..7f104786 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts @@ -1,22 +1,42 @@ -import { PackedTransaction } from '@wharfkit/antelope'; +import { Name, PackedTransaction, PermissionLevel } from '@wharfkit/antelope'; import type { LayoutLoad } from './$types'; +import { error } from '@sveltejs/kit'; export const load: LayoutLoad = async ({ fetch, params, parent }) => { const { network } = await parent(); const response = await fetch(`/${params.network}/api/msig/${params.proposer}/${params.proposal}`); const json = await response.json(); + + if ('error' in json) { + error(404, json.error); + } + const packed = PackedTransaction.from({ compression: false, signatures: [], packed_trx: json.proposal.packed_transaction, packed_context_free_data: [] }); + const transaction = packed.getTransaction(); + + const proposal_name = Name.from(json.approvals.proposal_name); + + const version = Number(json.approvals.version); + + const requested_approvals: PermissionLevel[] = json.approvals.requested_approvals.map( + ({ level }: { level?: PermissionLevel }) => (level ? PermissionLevel.from(level) : undefined) + ); + + const provided_approvals: PermissionLevel[] = json.approvals.provided_approvals.map( + ({ level }: { level?: PermissionLevel }) => (level ? PermissionLevel.from(level) : undefined) + ); + return { title: `${params.proposal}`, subtitle: `An MSIG proposed by ${params.proposer} on the ${network.chain.name} Network`, proposal: { - approvals: json.approvals, + approvals: { proposal_name, requested_approvals, provided_approvals, version }, proposer: params.proposer, name: params.proposal, hash: transaction.id, diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte index 278fcd31..42f5a632 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte @@ -4,47 +4,66 @@ import { DL, DLRow } from '$lib/components/descriptionlist/index.js'; import { MultiCard, Stack } from '$lib/components/layout/index.js'; import type { UnicoveContext } from '$lib/state/client.svelte.js'; - import { Name } from '@wharfkit/antelope'; + import { Name, PermissionLevel } from '@wharfkit/antelope'; import { getContext } from 'svelte'; import dayjs from 'dayjs'; - import relativeTime from 'dayjs/plugin/relativeTime'; // ES 2015 + import relativeTime from 'dayjs/plugin/relativeTime'; import Account from '$lib/components/elements/account.svelte'; import { percentString } from '$lib/utils'; - import { Check, UserCheck } from 'lucide-svelte'; + // import { Check, UserCheck } from 'lucide-svelte'; + import { ApprovalManager } from './manager.svelte'; dayjs.extend(relativeTime); let { data } = $props(); let { proposal } = $derived(data); + let { requested_approvals, provided_approvals } = $derived(proposal.approvals); let context = getContext('state'); - let { account } = $derived(context); + let { wharf } = $derived(context); - function nameHasApproved(name: Name) { - return data.provided_names.some((actor) => actor.equals(name)); - } + const manager = $state(new ApprovalManager(data.network, data.proposal)); + $effect(() => { + if (context.account) { + manager.sync(data.network, context.wharf); + } + }); + + const accountHasApproved = (account?: PermissionLevel) => { + if (!account) return false; + return provided_approvals.some((a) => a.equals(account)); + }; let userIsApprover = $derived( - data.requested_names.some((actor) => account?.name && actor.equals(account.name)) + requested_approvals.some((a) => wharf.session && a.equals(wharf.session.permissionLevel)) ); - let userHasApproved = $derived((account?.name && nameHasApproved(account.name)) || false); + let userHasApproved = $derived( + accountHasApproved(wharf.session?.permissionLevel) || !!manager.txid + ); - let userIsProposer = $derived(account?.name?.equals(Name.from(proposal.proposer)) || false); + let userIsProposer = $derived(wharf.session?.actor.equals(Name.from(proposal.proposer)) || false); + // Expiry date let relativeTimeToExpiry = $derived(dayjs(proposal.transaction.expiration.toDate()).fromNow()); - let alreadyExpired = $derived(dayjs(proposal.transaction.expiration.toDate()).isBefore()); + let proposalExpired = $derived(dayjs(proposal.transaction.expiration.toDate()).isBefore()); + + // Approval statistics + let totalRequested = $derived(requested_approvals.length); + let totalApproved = $derived(provided_approvals.length); + let ratioApproved = $derived(totalApproved / totalRequested); - let totalRequested = $derived(data.requested_names.length); - let totalApproved = $derived(data.provided_names.length); - let percentApproved = $derived(totalApproved / totalRequested); + // Actions + const handleApprove = () => manager.approve(); + const handleUnapprove = () => manager.unapprove(); + const handleExecute = () => manager.execute();
@@ -80,12 +99,11 @@ {#each proposal.approvals.requested_approvals as requested} - {@const { actor, permission } = requested.level} - - {permission} + + {requested.permission} - {@render approvalCard(nameHasApproved(Name.from(actor)))} + {@render approvalCard(accountHasApproved(requested))} {/each} @@ -110,28 +128,26 @@ {proposal.name} - + {proposal.transaction.expiration} ({relativeTimeToExpiry}) {proposal.hash} - - - + {#if userIsApprover} {#if userHasApproved} - + {:else} - + {/if} {/if} - {#if userIsProposer && !alreadyExpired} - + {#if userIsProposer && !proposalExpired} + {/if} @@ -154,11 +170,7 @@ background-position: var(--bg-pos, 100%); } #msig-vis > div { - background: linear-gradient( - to right, - theme(colors.green.900) 50%, - theme(colors.mineShaft.300) 50% - ); + background: linear-gradient(to right, theme(colors.green.900) 50%, theme(colors.zinc.400) 50%); background-size: 200% 100%; background-position: var(--bg-pos, 100%); background-clip: text; diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts deleted file mode 100644 index 489162b5..00000000 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Name } from '@wharfkit/antelope'; -import type { PageLoad } from './$types'; -import { PermissionLevel } from '@wharfkit/antelope'; - -export const load: PageLoad = async ({ parent }) => { - const { proposal } = await parent(); - - const requested_names: Name[] = proposal.approvals.requested_approvals.map( - ({ level }: { level: PermissionLevel }) => Name.from(level.actor) - ); - - const provided_names: Name[] = proposal.approvals.provided_approvals.map( - ({ level }: { level: PermissionLevel }) => Name.from(level.actor) - ); - - return { - requested_names, - provided_names - }; -}; diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/manager.svelte.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/manager.svelte.ts new file mode 100644 index 00000000..6776d155 --- /dev/null +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/manager.svelte.ts @@ -0,0 +1,106 @@ +import type { WharfState } from '$lib/state/client/wharf.svelte'; +import type { NetworkState } from '$lib/state/network.svelte'; +import { Name, type Checksum256 } from '@wharfkit/antelope'; + +type Proposal = { + proposer: string; + name: string; + hash: Checksum256; +}; + +export class ApprovalManager { + network: NetworkState | undefined = $state(); + wharf: WharfState | undefined = $state(); + proposal: Proposal; + error?: string = $state(); + txid?: string = $state(); + + constructor(network: NetworkState, proposal: Proposal) { + this.network = network; + this.proposal = proposal; + } + + sync(network: NetworkState, wharf: WharfState) { + let changed = false; + if (network.chain != this.network?.chain) { + this.network = network; + changed = true; + } + + if (changed) { + this.error = ''; + this.txid = ''; + } + + if (wharf !== this.wharf) { + this.wharf = wharf; + } + } + + async approve() { + try { + if (!this.network || !this.wharf || !this.wharf.session) { + throw new Error("Can't sign, data not ready"); + } + const action = this.network.contracts.msig.action('approve', { + proposer: Name.from(this.proposal.proposer), + proposal_name: Name.from(this.proposal.name), + level: this.wharf.session.permissionLevel, + proposal_hash: this.proposal.hash + }); + + const result = await this.wharf.transact({ action }); + + this.txid = result.response?.transaction_id; + if (!this.txid) { + throw Error('No transaction id'); + } + } catch (e) { + this.error = String(e); + } + } + + async unapprove() { + try { + if (!this.network || !this.wharf || !this.wharf.session) { + throw new Error("Can't sign, data not ready"); + } + const action = this.network.contracts.msig.action('unapprove', { + proposer: Name.from(this.proposal.proposer), + proposal_name: Name.from(this.proposal.name), + level: this.wharf.session.permissionLevel + }); + + const result = await this.wharf.transact({ action }); + + this.txid = result.response?.transaction_id; + if (!this.txid) { + throw Error('No transaction id'); + } + } catch (e) { + this.error = String(e); + } + } + + async execute() { + try { + if (!this.network || !this.wharf || !this.wharf.session) { + throw new Error("Can't sign, data not ready"); + } + const action = this.network.contracts.msig.action('exec', { + proposer: Name.from(this.proposal.proposer), + proposal_name: Name.from(this.proposal.name), + executer: this.wharf.session.actor + }); + + const result = await this.wharf.transact({ action }); + + this.txid = result.response?.transaction_id; + if (!this.txid) { + throw Error('No transaction id'); + } + } catch (e) { + this.error = String(e); + } + } +} From 224f84bf5b9f03459d18a378d3e5983b9c6859af Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:36:42 -0800 Subject: [PATCH 10/32] feat: add human readable actions --- src/lib/components/elements/action.svelte | 13 +++++++++++++ .../msig/[proposer]/[proposal]/+layout.ts | 16 ++++++++++++++-- .../msig/[proposer]/[proposal]/+page.svelte | 12 ++++++------ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/lib/components/elements/action.svelte diff --git a/src/lib/components/elements/action.svelte b/src/lib/components/elements/action.svelte new file mode 100644 index 00000000..7648c34f --- /dev/null +++ b/src/lib/components/elements/action.svelte @@ -0,0 +1,13 @@ + + +{#if props.data} + {JSON.stringify(props.data, null, 2)} +{/if} diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts index 7f104786..e04a3eb6 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+layout.ts @@ -1,4 +1,4 @@ -import { Name, PackedTransaction, PermissionLevel } from '@wharfkit/antelope'; +import { Name, PackedTransaction, PermissionLevel, Serializer } from '@wharfkit/antelope'; import type { LayoutLoad } from './$types'; import { error } from '@sveltejs/kit'; @@ -32,6 +32,17 @@ export const load: LayoutLoad = async ({ fetch, params, parent }) => { ({ level }: { level?: PermissionLevel }) => (level ? PermissionLevel.from(level) : undefined) ); + const actions = await Promise.all( + transaction.actions.map(async (a) => { + const { abi } = await network.client.v1.chain.get_abi(String(a.account)); + if (abi) { + const decoded = a.decodeData(abi); + return Serializer.objectify(decoded) as Record; + } + return {}; + }) + ); + return { title: `${params.proposal}`, subtitle: `An MSIG proposed by ${params.proposer} on the ${network.chain.name} Network`, @@ -41,7 +52,8 @@ export const load: LayoutLoad = async ({ fetch, params, parent }) => { name: params.proposal, hash: transaction.id, packed, - transaction + transaction, + actions } }; }; diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte index 42f5a632..acd57f71 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte @@ -1,6 +1,5 @@ diff --git a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte index 6cb9f098..be26a555 100644 --- a/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte +++ b/src/routes/[network]/(explorer)/msig/[proposer]/[proposal]/+page.svelte @@ -3,12 +3,12 @@ import { DL, DLRow } from '$lib/components/descriptionlist/index.js'; import { MultiCard, Stack } from '$lib/components/layout/index.js'; import type { UnicoveContext } from '$lib/state/client.svelte.js'; - import { PermissionLevel } from '@wharfkit/antelope'; import { getContext } from 'svelte'; + import { Name, PermissionLevel } from '@wharfkit/antelope'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import Account from '$lib/components/elements/account.svelte'; - // import { Check, UserCheck } from 'lucide-svelte'; + import { CircleCheck, CircleHelp } from 'lucide-svelte'; import { ApprovalManager } from './manager.svelte'; import ActionCard from '$lib/components/elements/action.svelte'; @@ -58,38 +58,37 @@ -
+

Requested Approvals

+ +
-
-
- - - - {totalApproved} - - Approved -
- -
- - - - {totalRequested} - - Requested + > +
+
+ + + + {totalApproved} + + Approved +
+ +
+ + + + {totalRequested} + + Requested +
-
- - -

Requested Approvals

- @@ -100,11 +99,15 @@ {#each total_approvals as requested} - + {/each} @@ -112,15 +115,8 @@
{requested.permission} - {@render approvalCard(accountHasApproved(requested))} + {#if accountHasApproved(requested)} + Approved + {:else} + Requested + {/if}
- -

Proposed Actions

- {#each proposal.actions as action} - - {/each} -
- -

Details

+

Multisig Details

@@ -136,27 +132,28 @@ {proposal.hash}
-
- {#if userIsApprover} - {#if userHasApproved} - - {:else} - + {#if userIsApprover} + {#if userHasApproved} + + {:else} + + {/if} {/if} - {/if} - - -{#snippet approvalCard(approved?: boolean)} - {#if approved} - Approved - {:else} - Pending - {/if} -{/snippet} + + + + +

Proposed Actions

+ {#each proposal.actions as action} + + {/each} +
+ From 752fe9797f899711e595142e3282df23e42cb7ee Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Fri, 6 Dec 2024 09:43:09 -0800 Subject: [PATCH 22/32] Updating MetaMask plugin --- bun.lockb | Bin 257432 -> 257432 bytes package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bun.lockb b/bun.lockb index 772574f4624a693dc1bd37286d6639763515d692..ce6c98c40386e869cbd5f93b4b102cb591ab91b6 100755 GIT binary patch delta 169 zcmV;a09OB)+YgxA50EY(o4xMqY_^?BRSqHCHA~c*2<>~0iKC_52rfNWQKo~Fu})e; zlV~z9v)Dt8)Ii2ZX~7U3vT6iF24j0l&h|3NZKHWoKf5LZpNq6lMnDP?M;*4oT}Rtf zNIM$4UO4S0e{Mj^MX1rniI07Ra900000m%gzA8JC@@0?G#g XUNJ5)E-<%lssiPd0Wh~zKLbRr`0Gp- diff --git a/package.json b/package.json index 90979b12..038dd73f 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@wharfkit/session": "^1.4.0", "@wharfkit/transact-plugin-resource-provider": "^1.1.1", "@wharfkit/wallet-plugin-anchor": "^1.4.0", - "@wharfkit/wallet-plugin-metamask": "^1.1.0", + "@wharfkit/wallet-plugin-metamask": "^1.1.1", "@wharfkit/wallet-plugin-privatekey": "^1.1.0", "@wharfkit/wallet-plugin-scatter": "^1.5.1", "@wharfkit/wallet-plugin-tokenpocket": "^1.5.1", diff --git a/yarn.lock b/yarn.lock index 336c6fe1..730d1150 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,6 +1,6 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 -# bun ./bun.lockb --hash: ECB05F2A4F6B5A6B-e8c95a7b99cf9889-8602410DB5AD8AB1-91762af158999f06 +# bun ./bun.lockb --hash: 9BBDEEEB6CB69D4A-550e21dc354bd49a-08ED7B8E89A3A5DC-082e3d5751a68393 "@accuser/svelte-plausible-analytics@^1.0.0": @@ -1601,10 +1601,10 @@ isomorphic-ws "^5.0.0" ws "^8.13.0" -"@wharfkit/wallet-plugin-metamask@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@wharfkit/wallet-plugin-metamask/-/wallet-plugin-metamask-1.1.0.tgz" - integrity sha512-ve5GnIX7myxbPrLrGITvHCW6CKyYEMHx0R2FC5QT3ItF2ImPfYRysodnRbv2KfVewrJK/uDvzxIs4VhU9HZjGQ== +"@wharfkit/wallet-plugin-metamask@^1.1.1": + version "1.1.1" + resolved "https://registry.npmjs.org/@wharfkit/wallet-plugin-metamask/-/wallet-plugin-metamask-1.1.1.tgz" + integrity sha512-xkdpwRAdsmoEQwZje0rO9jLJbaN5Uj+7JgKfi7RPRkAKEUcdtsFdR9tTSDsau1447SZ/bkDKRbDBrqibzhckyw== dependencies: "@metamask/providers" "^17.0.0" tslib "^2.1.0" From 397f7621f01e74fb7aca45f62e60c395e8401a22 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Tue, 3 Dec 2024 16:36:59 -0800 Subject: [PATCH 23/32] Initial token page --- .../token/[contract]/[symbol]/+page.svelte | 71 +++++++++++++++++++ .../token/[contract]/[symbol]/+page.ts | 40 +++++++++++ .../api/token/[contract]/[symbol]/+server.ts | 62 ++++++++++++++++ src/routes/[network]/api/tokens/+server.ts | 2 +- 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.svelte create mode 100644 src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.ts create mode 100644 src/routes/[network]/api/token/[contract]/[symbol]/+server.ts diff --git a/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.svelte b/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.svelte new file mode 100644 index 00000000..bc786410 --- /dev/null +++ b/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.svelte @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + +
Total Accounts Holding + {data.numholders.toLocaleString()} +
Supply + +
Max Supply + +
Issuer + +
+ +{#if data.topholders.length} +

Top 100 Accounts

+ + + + + + + + + + {#each data.topholders as holder, idx} + + + + + + {/each} + +
#AccountBalance
{idx + 1} + + + +
+{/if} + +{#if context.settings.data.debugMode} + + {JSON.stringify(data, null, 2)} + +{/if} diff --git a/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.ts b/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.ts new file mode 100644 index 00000000..cc77a0cd --- /dev/null +++ b/src/routes/[network]/(explorer)/token/[contract]/[symbol]/+page.ts @@ -0,0 +1,40 @@ +import { API, Asset, Name, Struct, type AssetType, type NameType } from '@wharfkit/antelope'; +import type { PageLoad } from './$types'; + +interface LightAPIHolder { + account: NameType; + balance: AssetType; +} + +@Struct.type('lightapi_balance') +class LightAPIBalance extends Struct { + @Struct.field(Name) declare account: Name; + @Struct.field(Asset) declare balance: Asset; +} + +export const load: PageLoad = async ({ fetch, params, parent }) => { + const { network } = await parent(); + + const response = await fetch(`/${network}/api/token/${params.contract}/${params.symbol}`); + const json = await response.json(); + + const stats = API.v1.GetCurrencyStatsItemResponse.from(json.stats); + const topholders = json.topholders.map((result: LightAPIHolder) => { + return LightAPIBalance.from({ + account: result.account, + balance: `${result.balance} ${stats.max_supply.symbol.code}` + }); + }); + + return { + numholders: json.numholders, + topholders, + stats, + title: `${stats.supply.symbol.name} Token`, + subtitle: `A token on the ${params.contract} smart contract.`, + pageMetaTags: { + title: `${stats.supply.symbol.name} Token`, + description: `The ${stats.supply.symbol.name} token created by the ${params.contract} smart contract on the ${network.chain.name} network. ${stats.supply.symbol.name} has ${json.numholders} accounts currently holding a balance.` + } + }; +}; diff --git a/src/routes/[network]/api/token/[contract]/[symbol]/+server.ts b/src/routes/[network]/api/token/[contract]/[symbol]/+server.ts new file mode 100644 index 00000000..e7479121 --- /dev/null +++ b/src/routes/[network]/api/token/[contract]/[symbol]/+server.ts @@ -0,0 +1,62 @@ +import { json, type RequestEvent } from '@sveltejs/kit'; + +import { getChainDefinitionFromParams, NetworkState } from '$lib/state/network.svelte'; +import { getCacheHeaders } from '$lib/utils'; +import { getBackendNetwork, getLightAPIURL } from '$lib/wharf/client/ssr'; + +export async function GET({ fetch, params }: RequestEvent) { + const chain = getChainDefinitionFromParams(String(params.network)); + if (!chain) { + return json({ error: 'Invalid chain specified' }, { status: 400 }); + } + const network = getBackendNetwork(chain, fetch, true); + if (!params.contract) { + return json({ error: 'Invalid contract specified' }, { status: 400 }); + } + if (!params.symbol) { + return json({ error: 'Invalid symbol specified' }, { status: 400 }); + } + const contract = params.contract.toLocaleLowerCase(); + const symbol = params.symbol?.toLocaleUpperCase(); + const stats = await network.client.v1.chain.get_currency_stats(contract, symbol); + const topholders = await getTopHolders(network, contract, symbol); + const numholders = await getNumHolders(network, contract, symbol); + + return json( + { + ts: new Date(), + numholders, + topholders, + stats: { + supply: stats[symbol].supply, + max_supply: stats[symbol].max_supply, + issuer: stats[symbol].issuer + } + }, + { + headers: getCacheHeaders(3600) + } + ); +} + +async function getTopHolders( + network: NetworkState, + contract: string, + symbol: string, + number = 100 +) { + const response = await fetch( + `${getLightAPIURL(network.shortname)}/api/topholders/${network}/${contract}/${symbol}/${number}` + ); + return (await response.json()).map((result: string[]) => ({ + account: result[0], + balance: result[1] + })); +} + +async function getNumHolders(network: NetworkState, contract: string, symbol: string) { + const response = await fetch( + `${getLightAPIURL(network.shortname)}/api/holdercount/${network}/${contract}/${symbol}` + ); + return response.json(); +} diff --git a/src/routes/[network]/api/tokens/+server.ts b/src/routes/[network]/api/tokens/+server.ts index 48972432..1924d48b 100644 --- a/src/routes/[network]/api/tokens/+server.ts +++ b/src/routes/[network]/api/tokens/+server.ts @@ -16,7 +16,7 @@ export async function GET({ params }: RequestEvent) { tokens: tokens[params.network as ChainShortName] }, { - headers: getCacheHeaders(300) // 60 min cache + headers: getCacheHeaders(3600) } ); } From 318cef29c8e7af10efc751f792440fcd519f1756 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Wed, 4 Dec 2024 11:12:37 -0800 Subject: [PATCH 24/32] Initial prototype --- src/lib/components/input/publickey.svelte | 77 ++++ .../(account)/create-account/+page.svelte | 349 ++++++++++++++++++ .../(account)/create-account/+page.ts | 14 + 3 files changed, 440 insertions(+) create mode 100644 src/lib/components/input/publickey.svelte create mode 100644 src/routes/[network]/(account)/create-account/+page.svelte create mode 100644 src/routes/[network]/(account)/create-account/+page.ts diff --git a/src/lib/components/input/publickey.svelte b/src/lib/components/input/publickey.svelte new file mode 100644 index 00000000..b7f6688f --- /dev/null +++ b/src/lib/components/input/publickey.svelte @@ -0,0 +1,77 @@ + + + + +{#if debug} +

Component State

+
+input (string):   "{input}"
+Public Key:        {pubkey}
+    
+---
+
+Valid Input:       {satisfies}
+Valid Public Key:  {satisfiesPublicKeyMatch}
+
+{/if} diff --git a/src/routes/[network]/(account)/create-account/+page.svelte b/src/routes/[network]/(account)/create-account/+page.svelte new file mode 100644 index 00000000..67035e1d --- /dev/null +++ b/src/routes/[network]/(account)/create-account/+page.svelte @@ -0,0 +1,349 @@ + + +{#snippet AccountName()} +
+ + +
+{/snippet} + +{#snippet PublicKey()} +
+ + + +
+{/snippet} + +{#snippet Generate()} +
+
+ +
+ + +
+
+

+ This is your new private key. Copy it someplace safe, import it into your wallet, and never + share it with anyone. If you lose this key, you will lose access to your account. +

+
+ + +
+
+{/snippet} + +{#snippet Create()} +
+

Instructions

+

+ Send EOS from an exchange or over a bridge to the account below with the memo provided to + create your account. +

+
+ +
+ {#if cost} + + {/if} + +
+
+ +
+ +
+ {#if cost} + + {/if} + +
+
+ +
+ +
+ + +
+
+ +

+ Once the transfer is complete, use your private key to import your account into the wallet of + your choosing. +

+
+{/snippet} + +{#snippet ButtonGroup()} +
+ {#if f.current === 'account'} + + {:else} + + {/if} + + +
+{/snippet} + + + + {@render AccountName()} + + {@render PublicKey()} + + {@render Generate()} + + {@render Create()} + + {@render ButtonGroup()} + + + +{#if context.settings.data.debugMode} +

{m.common_debugging()}

+ {JSON.stringify( + { + cost, + values: { + accountName, + publicKey, + privateKey + }, + valid: { + accountValid, + publicKeyValid + } + }, + undefined, + 2 + )} +{/if} diff --git a/src/routes/[network]/(account)/create-account/+page.ts b/src/routes/[network]/(account)/create-account/+page.ts new file mode 100644 index 00000000..38b9f11d --- /dev/null +++ b/src/routes/[network]/(account)/create-account/+page.ts @@ -0,0 +1,14 @@ +import type { PageLoad } from './$types'; +import * as m from '$lib/paraglide/messages'; + +export const load: PageLoad = async ({ parent }) => { + const { network } = await parent(); + return { + title: 'Create Account', + subtitle: 'Create an account using a token transfer', + pageMetaTags: { + title: 'Create Account', + description: 'Create an account using a token transfer' + } + }; +}; From d7b2f642f2c2d305f47e37b1fdf950c8463d0ae2 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Wed, 4 Dec 2024 12:15:57 -0800 Subject: [PATCH 25/32] Use legacy public key format --- src/routes/[network]/(account)/create-account/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/[network]/(account)/create-account/+page.svelte b/src/routes/[network]/(account)/create-account/+page.svelte index 67035e1d..2d1f4194 100644 --- a/src/routes/[network]/(account)/create-account/+page.svelte +++ b/src/routes/[network]/(account)/create-account/+page.svelte @@ -39,7 +39,7 @@ let cost: Asset | undefined = $state(); let costAmount: string | undefined = $derived(cost?.quantity); - let memo: string = $derived(`${accountName}:${publicKey}`); + let memo: string = $derived(`${accountName}:${publicKey?.toLegacyString()}`); let sendAccount: string = $state('openaccounts'); From dc769a54de265977561b411efb48f01e3f98edff Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:49:48 -0800 Subject: [PATCH 26/32] fix: pvt key copy button --- .../(account)/create-account/+page.svelte | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/routes/[network]/(account)/create-account/+page.svelte b/src/routes/[network]/(account)/create-account/+page.svelte index 2d1f4194..a6c2d720 100644 --- a/src/routes/[network]/(account)/create-account/+page.svelte +++ b/src/routes/[network]/(account)/create-account/+page.svelte @@ -212,21 +212,16 @@
-
- - -
+ + + +

This is your new private key. Copy it someplace safe, import it into your wallet, and never From 3ecbf788dd7cf6e1f225ad6b1ceda57f47b46d5e Mon Sep 17 00:00:00 2001 From: Dean Sallinen <7519573+deansallinen@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:08:02 -0800 Subject: [PATCH 27/32] fix: label ids --- .../(account)/create-account/+page.svelte | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/routes/[network]/(account)/create-account/+page.svelte b/src/routes/[network]/(account)/create-account/+page.svelte index a6c2d720..5136656e 100644 --- a/src/routes/[network]/(account)/create-account/+page.svelte +++ b/src/routes/[network]/(account)/create-account/+page.svelte @@ -179,7 +179,7 @@ {#snippet AccountName()}

- + - +
- +
- +
{#if cost} - + {/if} -
+ + {/if}
-
- {#if cost} - - {/if} - -
+ + {/if}
-
- - -
+ + + +

From e3889b79daadb7703350661bfbec1326c4347ed8 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Fri, 6 Dec 2024 09:57:23 -0800 Subject: [PATCH 29/32] Linting --- src/lib/components/input/publickey.svelte | 2 +- src/routes/[network]/(account)/create-account/+page.svelte | 2 +- src/routes/[network]/(account)/create-account/+page.ts | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/components/input/publickey.svelte b/src/lib/components/input/publickey.svelte index b7f6688f..587a452b 100644 --- a/src/lib/components/input/publickey.svelte +++ b/src/lib/components/input/publickey.svelte @@ -3,7 +3,7 @@ import type { ComponentProps } from 'svelte'; import TextInput from './text.svelte'; - interface PublicKeyInputProps extends ComponentProps { + interface PublicKeyInputProps extends ComponentProps { valid?: boolean; value: PublicKey | undefined; debug?: boolean; diff --git a/src/routes/[network]/(account)/create-account/+page.svelte b/src/routes/[network]/(account)/create-account/+page.svelte index 25d84999..82261790 100644 --- a/src/routes/[network]/(account)/create-account/+page.svelte +++ b/src/routes/[network]/(account)/create-account/+page.svelte @@ -27,7 +27,7 @@ let accountValid = $state(false); let accountName: Name = $state(Name.from('')); - let publicKeyInput: TextInput | undefined = $state(); + let publicKeyInput: PublicKeyInput | undefined = $state(); let publicKeyRef: HTMLInputElement | undefined = $state(); let publicKeyValid = $state(false); let publicKey: PublicKey | undefined = $state(); diff --git a/src/routes/[network]/(account)/create-account/+page.ts b/src/routes/[network]/(account)/create-account/+page.ts index 38b9f11d..98d4c763 100644 --- a/src/routes/[network]/(account)/create-account/+page.ts +++ b/src/routes/[network]/(account)/create-account/+page.ts @@ -1,8 +1,6 @@ import type { PageLoad } from './$types'; -import * as m from '$lib/paraglide/messages'; -export const load: PageLoad = async ({ parent }) => { - const { network } = await parent(); +export const load: PageLoad = async () => { return { title: 'Create Account', subtitle: 'Create an account using a token transfer', From 7504e2efc3fc8cf07f1baf804940a623f631c484 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Fri, 6 Dec 2024 10:01:29 -0800 Subject: [PATCH 30/32] More linting --- src/lib/components/input/publickey.svelte | 1 + .../signup/wallets/extensions/metamask/+page.svelte | 1 - src/routes/[network]/(account)/staking/+page.svelte | 8 -------- .../[network]/(homepage)/(wallets)/metamask/+page.svelte | 1 - 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/lib/components/input/publickey.svelte b/src/lib/components/input/publickey.svelte index 587a452b..b4ca5a0f 100644 --- a/src/lib/components/input/publickey.svelte +++ b/src/lib/components/input/publickey.svelte @@ -26,6 +26,7 @@ try { return PublicKey.from(input); } catch (e) { + console.warn(e); return; } }); diff --git a/src/routes/[network]/(account)/signup/wallets/extensions/metamask/+page.svelte b/src/routes/[network]/(account)/signup/wallets/extensions/metamask/+page.svelte index 9483606d..a067dfba 100644 --- a/src/routes/[network]/(account)/signup/wallets/extensions/metamask/+page.svelte +++ b/src/routes/[network]/(account)/signup/wallets/extensions/metamask/+page.svelte @@ -9,7 +9,6 @@ import Button from '$lib/components/button/button.svelte'; import Box from '$lib/components/layout/box/box.svelte'; import Card from '$lib/components/layout/box/card.svelte'; - import Grid from '$lib/components/layout/grid.svelte'; import { setSnap, requestSnap } from '$lib/metamask-snap'; import { getChainDefinitionFromParams } from '$lib/state/network.svelte'; import { MetaMaskState } from '$lib/state/metamask.svelte'; diff --git a/src/routes/[network]/(account)/staking/+page.svelte b/src/routes/[network]/(account)/staking/+page.svelte index b86b690c..52c82d84 100644 --- a/src/routes/[network]/(account)/staking/+page.svelte +++ b/src/routes/[network]/(account)/staking/+page.svelte @@ -13,7 +13,6 @@ getStakedBalance, getUnstakingBalances, getAPR, - getStakableBalance, getUnstakableBalance } from '$lib/utils/staking'; import UnstakingBalances from '$lib/components/elements/unstaking.svelte'; @@ -27,7 +26,6 @@ const { data } = $props(); const networkName = String(data.network); - let available: Asset = $derived(getStakableBalance(data.network, context.account)); let total: Asset = $derived(getStakedBalance(data.network, context.account)); let staked: Asset = $derived(getUnstakableBalance(data.network, context.account)); let unstaking: Array = $derived( @@ -57,12 +55,6 @@ let usdValue = $derived( Asset.from(total.value * (data.network.tokenprice ? data.network.tokenprice.value : 0), '2,USD') ); - let usdValueAvailable = $derived( - Asset.from( - available.value * (data.network.tokenprice ? data.network.tokenprice.value : 0), - '2,USD' - ) - ); let activity = $derived( staked.units.gt(UInt64.from(0)) || diff --git a/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte b/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte index eac31177..bd154f68 100644 --- a/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte +++ b/src/routes/[network]/(homepage)/(wallets)/metamask/+page.svelte @@ -12,7 +12,6 @@ import { Cluster, Stack } from '$lib/components/layout/index.js'; import { accountCreationPluginMetamask } from '$lib/state/client/wharf.svelte'; import { chainLogos } from '@wharfkit/common'; - import { getChainDefinitionFromParams } from '$lib/state/network.svelte.js'; const { data } = $props(); const context = getContext('state'); From 9567a46fcfacb118fc60fdc86b8ca304b12aefbc Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Mon, 2 Dec 2024 17:29:26 -0800 Subject: [PATCH 31/32] Initial onramp prototype --- package.json | 1 + .../[network]/(account)/fund/+page.svelte | 87 +++++++++++++++++++ src/routes/[network]/(account)/fund/+page.ts | 12 +++ yarn.lock | 5 ++ 4 files changed, 105 insertions(+) create mode 100644 src/routes/[network]/(account)/fund/+page.svelte create mode 100644 src/routes/[network]/(account)/fund/+page.ts diff --git a/package.json b/package.json index 038dd73f..04ed151c 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "type": "module", "dependencies": { "@accuser/svelte-plausible-analytics": "^1.0.0", + "@coinbase/cbpay-js": "^2.4.0", "@fontsource/jetbrains-mono": "^5.1.0", "@tailwindcss/container-queries": "^0.1.1", "@wharfkit/account": "^1.2.0", diff --git a/src/routes/[network]/(account)/fund/+page.svelte b/src/routes/[network]/(account)/fund/+page.svelte new file mode 100644 index 00000000..34036176 --- /dev/null +++ b/src/routes/[network]/(account)/fund/+page.svelte @@ -0,0 +1,87 @@ + + +{#if !context.account} +

You must be logged in with an account to use this feature.

+{:else if !coinbaseInstance} +

No supported funding methods for this blockchain.

+{:else} + +{/if} + +{#if context.settings.data.debugMode} +

{m.common_debugging()}

+ + + {JSON.stringify(options, null, 2)} + + + + {JSON.stringify(coinbaseInstance, null, 2)} + +{/if} diff --git a/src/routes/[network]/(account)/fund/+page.ts b/src/routes/[network]/(account)/fund/+page.ts new file mode 100644 index 00000000..1b17aa8c --- /dev/null +++ b/src/routes/[network]/(account)/fund/+page.ts @@ -0,0 +1,12 @@ +import type { PageLoad } from './$types'; + +export const load: PageLoad = async () => { + return { + title: 'Fund Account', + subtitle: 'Purchase EOS tokens to fund your account', + pageMetaTags: { + title: 'Fund Account', + description: 'Purchase EOS tokens to fund your account' + } + }; +}; diff --git a/yarn.lock b/yarn.lock index 730d1150..ae26d9f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,6 +58,11 @@ resolved "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240725.0.tgz" integrity sha512-L6T/Bg50zm9IIACQVQ0CdVcQL+2nLkRXdPz6BsXF3SlzgjyWR5ndVctAbfr/HLV7aKYxWnnEZsIORsTWb+FssA== +"@coinbase/cbpay-js@^2.4.0": + version "2.4.0" + resolved "https://registry.npmjs.org/@coinbase/cbpay-js/-/cbpay-js-2.4.0.tgz" + integrity sha512-7Zy1P6v5CTaBuFYowFmvKJ4KyBngVjsPpLkjSi4DWJhVHMgLIkDUINSloRU0Idgt2rFA/PLIm2gXneR3OoQbrA== + "@cspotcode/source-map-support@0.8.1": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" From 9ba1fa0d15e2d63e858e7038f1e70c875a8b564c Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Fri, 6 Dec 2024 10:13:08 -0800 Subject: [PATCH 32/32] Corrected lockfile --- bun.lockb | Bin 257432 -> 257848 bytes yarn.lock | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lockb b/bun.lockb index ce6c98c40386e869cbd5f93b4b102cb591ab91b6..4159f1ecc88841fe59cb1c6d792a1e5bcb7e9ab3 100755 GIT binary patch delta 42962 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 bEg0+Oxxnc$c{1j3wy#J5Xz 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 delta 42961 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 diff --git a/yarn.lock b/yarn.lock index ae26d9f9..dcc29a12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,6 +1,6 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 -# bun ./bun.lockb --hash: 9BBDEEEB6CB69D4A-550e21dc354bd49a-08ED7B8E89A3A5DC-082e3d5751a68393 +# bun ./bun.lockb --hash: 02680FA43BE52E3F-9e1c2b0460f4d634-DFFAE5B7F63C2D78-c85325782d6f62bd "@accuser/svelte-plausible-analytics@^1.0.0":