diff --git a/packages/snap/package.json b/packages/snap/package.json index 7d554fc..edfc354 100644 --- a/packages/snap/package.json +++ b/packages/snap/package.json @@ -54,6 +54,7 @@ "@metamask/snaps-ui": "^3.1.0", "buffer": "^6.0.3", "cosmjs-types": "^0.8.0", + "lodash": "^4.17.21", "osmojs": "^16.5.1", "ses": "^0.18.4" }, diff --git a/packages/snap/snap.config.ts b/packages/snap/snap.config.ts index bfcf619..d97c003 100644 --- a/packages/snap/snap.config.ts +++ b/packages/snap/snap.config.ts @@ -9,6 +9,9 @@ const config: SnapConfig = { stats: { buffer: false, }, + environment: { + DENO_SERVERLESS_URL: process.env.DENO_SERVERLESS_URL, + }, }; export default config; \ No newline at end of file diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 3e18775..df6c948 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -4,10 +4,10 @@ "proposedName": "Cosmos Extension", "repository": { "type": "git", - "url": "https://github.com/cosmos/snap.git" + "url": "git+https://github.com/cosmos/snap.git" }, "source": { - "shasum": "70Y16tDS8kL5RMQhR1coQlID5bwKy0TeCmYgqwTIWlk=", + "shasum": "f6e8RsKUURq4joa44SVbSIIwH8SdkhwOiulSa1bWqpA=", "location": { "npm": { "filePath": "dist/bundle.js", @@ -89,7 +89,8 @@ "endowment:rpc": { "snaps": false, "dapps": true - } + }, + "endowment:page-home": {} }, "manifestVersion": "0.1" } diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 3465f19..f340392 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -1,4 +1,4 @@ -import { OnRpcRequestHandler } from "@metamask/snaps-sdk"; +import { OnHomePageHandler, OnRpcRequestHandler, address, image, row } from "@metamask/snaps-sdk"; import { AccountData } from '@cosmjs/amino'; import { panel, text, heading, divider, copyable } from "@metamask/snaps-ui"; import { initializeChains } from "./initialize"; @@ -14,6 +14,8 @@ import Long from "long"; import { Key } from '@keplr-wallet/types'; import { fromBech32 } from '@cosmjs/encoding'; import { isTxBodyEncodeObject } from "@cosmjs/proto-signing"; +import { getBalances } from "./utils"; +import _ from "lodash"; /** * Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`. @@ -957,3 +959,40 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ throw new Error("Method not found."); } }; + +export const onHomePage: OnHomePageHandler = async () => { + const main: any[] = [ + heading('Metamask Extension'), + text('Manage everything across the Cosmos!'), + divider(), + heading('Accounts'), + divider(), + ] + const addressesP = ChainState.getChainAddresses(); + const chainsP = ChainState.getChains(); + const [addresses, chainsInWallet] = await Promise.all([addressesP, chainsP]); + const chains = _.values(_.merge(_.keyBy(addresses, 'chain_id'), _.keyBy(chainsInWallet.chains, 'chain_id'))) + const balances = await getBalances(chains); + addresses.forEach((address) => { + const chain = balances.find((balance) => balance.chain_id === address.chain_id); + if (!chain) { + throw new Error(`No chain found for ${address.chain_id}`); + } + main.push(heading(chain ? chain.pretty_name : address.chain_id)) + main.push(text("**Balances**")) + chain.balances.forEach((balance) => { + main.push(copyable(`${_.round((Number(balance.amount) / 1_000_000), 2)} ${balance.display}`)) + }) + main.push(text("**Address**")) + main.push(copyable(address.address)) + main.push(divider()) + }) + + // Direct them to the dashboard for more advanced things + main.push( + text('[Manage My Assets](https://metamask.mysticlabs.xyz/)') + ); + return { + content: panel(main), + }; +}; \ No newline at end of file diff --git a/packages/snap/src/utils.ts b/packages/snap/src/utils.ts new file mode 100644 index 0000000..87d83c6 --- /dev/null +++ b/packages/snap/src/utils.ts @@ -0,0 +1,38 @@ +import { Coin } from "@cosmjs/amino"; +import { Chain } from "./types/chains"; + +if (!process.env.DENO_SERVERLESS_URL) { + throw new Error("DENO_SERVERLESS_URL not set..."); +} +export const denoUrl = process.env.DENO_SERVERLESS_URL; + +export interface CoinIBC extends Coin { + ibc: boolean; + ibc_denom?: string; + display: string; +} + +export interface ChainBalances extends Chain { + balances: CoinIBC[]; +} + +export const getBalances = async (chains: Chain[]): Promise => { + try { + const res = await fetch(`${denoUrl}/balances`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-cache' }, + body: JSON.stringify({ chains: chains }) + }); + + if (!res.ok) { + throw new Error(`HTTP error ${res.status}`); + } + + const data = await res.json(); + + return data.balances; + } catch (error) { + console.error(error); + throw error; + } +}; \ No newline at end of file diff --git a/packages/snap/src/wallet.ts b/packages/snap/src/wallet.ts index ee12a51..cab42d5 100644 --- a/packages/snap/src/wallet.ts +++ b/packages/snap/src/wallet.ts @@ -1,6 +1,7 @@ import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"; import { Secp256k1Wallet } from "@cosmjs/amino"; import { Chain } from "./types/chains"; +import { Buffer } from "buffer"; export const getWallet = async (chain: Chain) => { // get signer info diff --git a/yarn.lock b/yarn.lock index 7e04fe2..d8352f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2280,6 +2280,7 @@ __metadata: eslint-plugin-node: ^11.1.0 eslint-plugin-prettier: ^4.2.1 jest: ^29.7.0 + lodash: ^4.17.21 node-fetch: 2 osmojs: ^16.5.1 prettier: ^2.2.1