diff --git a/packages/snap/package.json b/packages/snap/package.json index 73fc3e8..87186ea 100644 --- a/packages/snap/package.json +++ b/packages/snap/package.json @@ -1,11 +1,10 @@ { "name": "@cosmsnap/snap", - "version": "0.1.22", + "version": "0.1.23", "description": "The Cosmos extension for your Metamask wallet.", "repository": { "type": "git", "url": "git+https://github.com/cosmos/snap.git" - "url": "git+https://github.com/cosmos/snap.git" }, "license": "MIT", "author": "Mystic Labs, Inc", @@ -17,7 +16,7 @@ "README.md" ], "scripts": { - "build": "mm-snap build", + "build": "NODE_OPTIONS=--max-old-space-size=4096 mm-snap build", "build:clean": "yarn clean && yarn build", "clean": "rimraf dist", "lint": "yarn lint:eslint && yarn lint:misc --check", @@ -29,13 +28,8 @@ "start": "mm-snap watch", "test": "npx ava tests/*", "test:e2e": "jest" - "test:e2e": "jest" }, "ava": { - "timeout": "60s", - "files": [ - "**/*-test.js" - ], "timeout": "60s", "files": [ "**/*-test.js" @@ -48,11 +42,8 @@ ] }, "dependencies": { - "@agoric/cosmic-proto": "^0.3.0", - "@cosmjs/amino": "^0.31.1", - "@cosmjs/crypto": "^0.31.1", - "@cosmjs/encoding": "^0.31.1", - "@agoric/cosmic-proto": "^0.3.0", + "@agoric/cosmic-proto": "^0.4.1-u16.0", + "@akashnetwork/akashjs": "^0.10.0", "@cosmjs/amino": "^0.31.1", "@cosmjs/crypto": "^0.31.1", "@cosmjs/encoding": "^0.31.1", @@ -64,14 +55,10 @@ "buffer": "^6.0.3", "cosmjs-types": "^0.8.0", "lodash": "^4.17.21", - "lodash": "^4.17.21", "osmojs": "^16.5.1", "ses": "^0.18.4" }, "devDependencies": { - "@babel/core": "^7.24.0", - "@babel/preset-env": "^7.24.0", - "@babel/preset-typescript": "^7.23.3", "@babel/core": "^7.24.0", "@babel/preset-env": "^7.24.0", "@babel/preset-typescript": "^7.23.3", @@ -91,7 +78,6 @@ "@typescript-eslint/parser": "^5.33.0", "ava": "^5.3.0", "babel-jest": "^29.7.0", - "babel-jest": "^29.7.0", "eslint": "^8.21.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-import": "^2.26.0", @@ -100,14 +86,12 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.7.0", - "jest": "^29.7.0", "node-fetch": "2", "prettier": "^2.2.1", "prettier-plugin-packagejson": "^2.2.11", "rimraf": "^3.0.2", "through2": "^4.0.2", "ts-jest": "^29.1.2", - "ts-jest": "^29.1.2", "ts-node": "^10.9.1", "typescript": "^5.4.5" }, diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 6648f1c..4e63e55 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -1,14 +1,13 @@ { - "version": "0.1.22", + "version": "0.1.23", "description": "Cosmos Extension that adds Cosmos support to Metamask.", "proposedName": "Cosmos Extension", "repository": { "type": "git", "url": "git+https://github.com/cosmos/snap.git" - "url": "git+https://github.com/cosmos/snap.git" }, "source": { - "shasum": "iy7sFNnki+rvhkmOaWGfKE5ZiaEqOYkuE1AVb5dEiN0=", + "shasum": "IWERZuFb2xO0t8RLmZz6O4hhsapa2MjU8Lqr39IDGw0=", "location": { "npm": { "filePath": "dist/bundle.js", @@ -97,7 +96,7 @@ "endowment:cronjob": { "jobs": [ { - "expression": "*/30 * * * *", + "expression": "*/5 * * * *", "request": { "method": "notification", "params": {} diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 4f8defe..164da7d 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -2,7 +2,6 @@ import { OnHomePageHandler, OnRpcRequestHandler, panel, text, heading, divider, import { AccountData } from '@cosmjs/amino'; import { initializeChains } from "./initialize"; import { Chain, Chains, Fees, Msg, UpdateChainParams } from "./types/chains"; -import { Chain, Chains, Fees, Msg, UpdateChainParams } from "./types/chains"; import { Address } from "./types/address"; import { ChainState, AddressState } from "./state"; import { sendTx, signAmino, signDirect, submitTransaction } from "./transaction"; @@ -10,7 +9,6 @@ import { COIN_TYPES, DEFAULT_FEES } from "./constants"; import { SignDoc, TxBody, AuthInfo } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { StdSignDoc } from "@cosmjs/amino"; import { bigintReplacer, decodeProtoMessage, decodeTxBodyIntoMessages } from "./parser"; -import { bigintReplacer, decodeProtoMessage, decodeTxBodyIntoMessages } from "./parser"; import Long from "long"; import { Key } from '@keplr-wallet/types'; import { fromBech32 } from '@cosmjs/encoding'; @@ -29,7 +27,6 @@ import { snapNotify } from "./notification"; */ export const onRpcRequest: OnRpcRequestHandler = async ({ request, -}) => { }) => { let res: Object = {}; switch (request.method) { @@ -100,7 +97,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ method: "snap_manageState", params: { operation: "update", - newState: { chains: chains.string(), addresses: JSON.stringify([]), initialized: true, hd: (request.params && request.params.hd) ? request.params.hd : true }, + newState: { chains: chains.string(), addresses: JSON.stringify([]), initialized: true }, }, }); @@ -217,7 +214,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ }); return { - data: JSON.stringify(result), data: JSON.stringify(result), success: true, statusCode: 201, @@ -236,7 +232,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ }); return { - data: JSON.stringify(result), data: JSON.stringify(result), success: false, statusCode: 500, @@ -303,7 +298,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ }); return { - data: JSON.stringify(txResponse), data: JSON.stringify(txResponse), success: false, statusCode: 500, @@ -337,16 +331,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ let txBody = TxBody.decode(signDocNew.bodyBytes); const msgs = []; - for (const msg of txBody.messages) { - if (isTxBodyEncodeObject(msg)) { - const messages = await decodeTxBodyIntoMessages(msg.typeUrl, msg.value); - for (const message of messages) { - let decMsgTxBody = await decodeProtoMessage(message.typeUrl, message.value); - msgs.push(decMsgTxBody); - } - continue; - } if (isTxBodyEncodeObject(msg)) { const messages = await decodeTxBodyIntoMessages(msg.typeUrl, msg.value); for (const message of messages) { @@ -366,7 +351,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ let ui = [ heading("Confirm Transaction"), divider(), - divider(), heading("Chain"), text(`${request.params.chain_id}`), divider(), @@ -671,77 +655,6 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ }, }); - return { - data: request.params, - success: true, - statusCode: 201, - }; - case "changeChain": - if ( - !( - request.params != null && - typeof request.params == "object" && - "chain_id" in request.params && - typeof request.params.chain_id == "string" - ) - ) { - throw new Error("Invalid changeChain request"); - } - - // We only allow changing the rpc and the slip44 for now. So if we do not have these alert. - if (!request.params.rpc && !request.params.slip44) { - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Error Occured"), - text(`No RPC or Coin Type changes provided. Please provide "rpc" or "slip44".`), - ]), - }, - }); - } - const changes: UpdateChainParams = { - slip44: request.params.slip44, - rpc: request.params.rpc, - }; - - // Ensure user confirms changeChain - let confirmChangeChain = await snap.request({ - method: "snap_dialog", - params: { - type: "confirmation", - content: panel([ - heading(`Confirm Change for Chain ${request.params.chain_id}`), - divider(), - heading("Chain Info"), - text(`${JSON.stringify(JSON.stringify(changes), null, 4)}`), - divider(), - text("Note: this is an advanced, experimental feature so handle it with care."), - ]), - }, - }); - if (!confirmChangeChain) { - throw new Error("Chain change was denied."); - } - - // Update the chain in wallet state - await ChainState.updateChain(request.params.chain_id, changes); - - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Chain Changed"), - text( - `Successfully changed the following for chain ${request.params.chain_id}.` - ), - text(JSON.stringify(changes, null, 4)), - ]), - }, - }); - return { data: request.params, success: true, diff --git a/packages/snap/src/notification.ts b/packages/snap/src/notification.ts index b6decfc..00032cf 100644 --- a/packages/snap/src/notification.ts +++ b/packages/snap/src/notification.ts @@ -75,28 +75,34 @@ export class Notifications { } } +// IMPORTANT: The notification cannot have characters larger than 50 characters export const snapNotify = async (akash_address: string) => { - const notifications = new Notifications(); - // Update the notifications in Appwrite database - await notifications.updateAkashNotifications(akash_address); - // Get the notifications that are unread in Appwrite database - const notifs = await notifications.getAkashNotifications(akash_address); - if (!Array.isArray(notifs)) { - throw new Error("Expected an array of notifications, received:", notifs); - } - // Post notifications to Metamask after filtering for unread - const filtered = notifs.filter((notif) => !notif.read); - for (const notif of filtered) { - await snap.request({ - method: "snap_notify", - params: { - type: "inApp", - message: notif.notification, - }, - }); - // Update notification as read - await notifications.markNotificationRead( - notif.$id - ); - } + try { + const notifications = new Notifications(); + // Update the notifications in Appwrite database + await notifications.updateAkashNotifications(akash_address); + // Get the notifications that are unread in Appwrite database + const notifs = await notifications.getAkashNotifications(akash_address); + if (!Array.isArray(notifs)) { + throw new Error("Expected an array of notifications, received:", notifs); + } + // Post notifications to Metamask after filtering for unread + const filtered = notifs.filter((notif) => !notif.read); + for (const notif of filtered) { + await snap.request({ + method: "snap_notify", + params: { + type: "inApp", + message: notif.notification, + }, + }); + // Update notification as read + await notifications.markNotificationRead( + notif.$id + ); + } + } catch (err) { + console.error(err); + throw new Error(`${err}`); + } }; \ No newline at end of file diff --git a/packages/snap/src/parser.ts b/packages/snap/src/parser.ts index e2e4069..fa6e1ae 100644 --- a/packages/snap/src/parser.ts +++ b/packages/snap/src/parser.ts @@ -8,6 +8,13 @@ import { osmosisProtoRegistry } from 'osmojs'; +import { getAkashTypeRegistry } from "@akashnetwork/akashjs/build/stargate/index"; + +import { + MsgProvision, + MsgWalletSpendAction, +} from '@agoric/cosmic-proto/swingset/msgs.js'; + export const bigintReplacer = (value: any): any => { if (typeof value === 'bigint') { return value.toString(); @@ -36,15 +43,23 @@ export const bigintReplacerObject = (value: any): any => { export const decodeProtoMessage = async (typeUrl: string, value: Uint8Array) => { + const akashRegistryTypes = getAkashTypeRegistry(); + + const agoricRegistryTypes: [string, GeneratedType][] = [ + ['/agoric.swingset.MsgWalletSpendAction', MsgWalletSpendAction as any], + ['/agoric.swingset.MsgProvision', MsgProvision as any], + ]; - const protoRegistry: ReadonlyArray<[string, GeneratedType]> = [ + const protoRegistry = [ ...cosmosProtoRegistry, ...cosmwasmProtoRegistry, ...ibcProtoRegistry, - ...osmosisProtoRegistry + ...osmosisProtoRegistry, + ...akashRegistryTypes, + ...agoricRegistryTypes, ]; - const registry = new Registry(protoRegistry); + const registry = new Registry(protoRegistry as Iterable<[string, GeneratedType]>); // Get the proto type from the registry let protoType = registry.lookupType(typeUrl); diff --git a/packages/snap/src/rpc.test.ts b/packages/snap/src/rpc.test.ts index 1e59938..5dae04a 100644 --- a/packages/snap/src/rpc.test.ts +++ b/packages/snap/src/rpc.test.ts @@ -5,9 +5,11 @@ import { Chain } from './types/chains'; describe('Snap Calls', () => { let request: (request: RequestOptions) => SnapRequest; + let onCronjob : (request: RequestOptions) => SnapRequest; beforeEach(async () => { const install = await installSnap(); request = install.request; + onCronjob = install.onCronjob; const response = request({ method: 'initialize', }); @@ -118,4 +120,21 @@ describe('Snap Calls', () => { const chain = chains.find(c => c.chain_id === params.chain_id); expect(chain?.slip44).toBe(Number(params.slip44)); }, 50000) + + test('notification cron job', async () => { + // NOTE: for this test to pass we need a test notification assigned to akash1fwxt2qmvtgvn6gkvxum50wxhgf63dvetvlts60 thats read=false in the DB + const response = await request({ + method: 'getChainAddress', + params: { + chain_id: "akashnet-2" + } + }) + const res = response.response as any; + console.log(res['result']['data']['address']['address']); + const response2 = await onCronjob({ + method: 'notification', + params: {} + }); + expect(response2).toSendNotification("This is a test notification.", "inApp"); + }, 50000) }); \ No newline at end of file diff --git a/packages/snap/tsconfig.json b/packages/snap/tsconfig.json index 2eed86c..e6107d5 100644 --- a/packages/snap/tsconfig.json +++ b/packages/snap/tsconfig.json @@ -3,8 +3,11 @@ "compilerOptions": { "target": "ESNext", "module": "NodeNext", + "moduleResolution": "NodeNext", "strict": true, "esModuleInterop": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true } -} +} \ No newline at end of file