From 2e850567c1e823eed1e7f6aed169d0b8651df66e Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Wed, 1 Jun 2022 17:30:43 +0200 Subject: [PATCH 01/12] add Nightly wallet --- examples/angular/project.json | 5 + examples/react/project.json | 5 + examples/react/src/components/Content.tsx | 13 ++ .../src/contexts/WalletSelectorContext.tsx | 4 +- package.json | 2 + .../src/lib/components/WalletOptions.tsx | 8 +- packages/nightly/.babelrc | 3 + packages/nightly/.eslintrc.json | 18 ++ packages/nightly/README.md | 54 ++++++ packages/nightly/assets/nightly.png | Bin 0 -> 9862 bytes packages/nightly/jest.config.js | 14 ++ packages/nightly/package.json | 4 + packages/nightly/project.json | 54 ++++++ packages/nightly/src/index.ts | 2 + packages/nightly/src/lib/injected-nightly.ts | 43 +++++ packages/nightly/src/lib/nightly.ts | 170 ++++++++++++++++++ packages/nightly/tsconfig.json | 19 ++ packages/nightly/tsconfig.lib.json | 10 ++ packages/nightly/tsconfig.spec.json | 19 ++ packages/wallet-connect/package.json | 2 +- tsconfig.base.json | 3 + workspace.json | 1 + 22 files changed, 448 insertions(+), 5 deletions(-) create mode 100644 packages/nightly/.babelrc create mode 100644 packages/nightly/.eslintrc.json create mode 100644 packages/nightly/README.md create mode 100644 packages/nightly/assets/nightly.png create mode 100644 packages/nightly/jest.config.js create mode 100644 packages/nightly/package.json create mode 100644 packages/nightly/project.json create mode 100644 packages/nightly/src/index.ts create mode 100644 packages/nightly/src/lib/injected-nightly.ts create mode 100644 packages/nightly/src/lib/nightly.ts create mode 100644 packages/nightly/tsconfig.json create mode 100644 packages/nightly/tsconfig.lib.json create mode 100644 packages/nightly/tsconfig.spec.json diff --git a/examples/angular/project.json b/examples/angular/project.json index 4c824270a..5916a5d78 100644 --- a/examples/angular/project.json +++ b/examples/angular/project.json @@ -33,6 +33,11 @@ "input": "packages/sender/assets/", "output": "assets/" }, + { + "glob": "**/*", + "input": "packages/nightly/assets/", + "output": "assets/" + }, { "glob": "**/*", "input": "packages/ledger/assets/", diff --git a/examples/react/project.json b/examples/react/project.json index 84763ce89..40b2cdd0a 100644 --- a/examples/react/project.json +++ b/examples/react/project.json @@ -33,6 +33,11 @@ "input": "packages/sender/assets/", "output": "assets/" }, + { + "glob": "**/*", + "input": "packages/nightly/assets/", + "output": "assets/" + }, { "glob": "**/*", "input": "packages/ledger/assets/", diff --git a/examples/react/src/components/Content.tsx b/examples/react/src/components/Content.tsx index 2bbfe09f9..2a1a208d7 100644 --- a/examples/react/src/components/Content.tsx +++ b/examples/react/src/components/Content.tsx @@ -12,6 +12,7 @@ import { CONTRACT_ID } from "../constants"; import SignIn from "./SignIn"; import Form from "./Form"; import Messages from "./Messages"; +import { InjectedWallet } from "@near-wallet-selector/core"; const SUGGESTED_DONATION = "0"; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -24,6 +25,18 @@ const Content: React.FC = () => { const [messages, setMessages] = useState>([]); const [loading, setLoading] = useState(false); + // Try eager connect on app launch + useEffect(() => { + const eagerConnect = async () => { + const state = selector.store.getState(); + if (state.selectedWalletId === "nightly") { + const wallet = (await selector.wallet()) as InjectedWallet; + wallet.signIn({ contractId: CONTRACT_ID }); + } + }; + eagerConnect(); + }, []); + const getAccount = useCallback(async (): Promise => { if (!accountId) { return null; diff --git a/examples/react/src/contexts/WalletSelectorContext.tsx b/examples/react/src/contexts/WalletSelectorContext.tsx index d59e48a57..1359888b6 100644 --- a/examples/react/src/contexts/WalletSelectorContext.tsx +++ b/examples/react/src/contexts/WalletSelectorContext.tsx @@ -9,6 +9,7 @@ import { setupMyNearWallet } from "@near-wallet-selector/my-near-wallet"; import { setupSender } from "@near-wallet-selector/sender"; import { setupMathWallet } from "@near-wallet-selector/math-wallet"; import { setupLedger } from "@near-wallet-selector/ledger"; +import { setupNightly } from "@near-wallet-selector/nightly"; import { setupWalletConnect } from "@near-wallet-selector/wallet-connect"; import { CONTRACT_ID } from "../constants"; @@ -68,6 +69,7 @@ export const WalletSelectorContextProvider: React.FC = ({ children }) => { setupNearWallet(), setupMyNearWallet(), setupSender(), + setupNightly(), setupMathWallet(), setupLedger(), setupWalletConnect({ @@ -81,10 +83,8 @@ export const WalletSelectorContextProvider: React.FC = ({ children }) => { }), ], }); - const _modal = setupModal(_selector, { contractId: CONTRACT_ID }); const state = _selector.store.getState(); - syncAccountState(localStorage.getItem("accountId"), state.accounts); window.selector = _selector; diff --git a/package.json b/package.json index 511e242c7..ed76c6b1e 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "near-wallet", "my-near-wallet", "sender", + "nightly", "math-wallet", "ledger", "wallet-connect" @@ -39,6 +40,7 @@ "build:near-wallet": "nx run-many --target=build --projects=near-wallet --configuration=production", "build:my-near-wallet": "nx run-many --target=build --projects=my-near-wallet --configuration=production", "build:sender": "nx run-many --target=build --projects=sender --configuration=production", + "build:nightly": "nx run-many --target=build --projects=nightly --configuration=production", "build:wallet-connect": "nx run-many --target=build --projects=wallet-connect --configuration=production", "build:wallet-utils": "nx run-many --target=build --projects=wallet-utils --configuration=production", "lint": "nx workspace-lint && nx run-many --target=lint --all --parallel", diff --git a/packages/modal-ui/src/lib/components/WalletOptions.tsx b/packages/modal-ui/src/lib/components/WalletOptions.tsx index dd9a716de..1faef0eb3 100644 --- a/packages/modal-ui/src/lib/components/WalletOptions.tsx +++ b/packages/modal-ui/src/lib/components/WalletOptions.tsx @@ -76,13 +76,17 @@ export const WalletOptions: React.FC = ({ const { selectedWalletId } = selector.store.getState(); const { name, description, iconUrl } = module.metadata; const selected = module.id === selectedWalletId; - result.push(
  • {name} diff --git a/packages/nightly/.babelrc b/packages/nightly/.babelrc new file mode 100644 index 000000000..cf7ddd99c --- /dev/null +++ b/packages/nightly/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] +} diff --git a/packages/nightly/.eslintrc.json b/packages/nightly/.eslintrc.json new file mode 100644 index 000000000..9d9c0db55 --- /dev/null +++ b/packages/nightly/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/packages/nightly/README.md b/packages/nightly/README.md new file mode 100644 index 000000000..83c69234b --- /dev/null +++ b/packages/nightly/README.md @@ -0,0 +1,54 @@ +# @near-wallet-selector/nightly + + +This is the [Nightly](https://chrome.google.com/webstore/detail/nightly/fiikommddbeccaoicoejoniammnalkfa) package for NEAR Wallet Selector. + +## Installation and Usage + +The easiest way to use this package is to install it from the NPM registry: + +```bash +# Using Yarn +yarn add @near-wallet-selector/nightly + +# Using NPM. +npm install @near-wallet-selector/nightly +``` + +Then use it in your dApp: + +```ts +import { setupWalletSelector } from "@near-wallet-selector/core"; +import { setupNightly } from "@near-wallet-selector/nightly"; + +// Nightly for Wallet Selector can be setup without any params or it can take one optional param. +const nightly = setupNightly({ + iconUrl: "https://yourdomain.com/yourwallet-icon.png" //optional +}); + +const selector = await setupWalletSelector({ + network: "testnet", + modules: [nightly], +}); +``` + +## Options + +- `iconUrl`: (`string?`): Image URL for the icon shown in the modal. This can also be a relative path or base64 encoded image. Defaults to `./assets/nightly-icon.png`. + +## Assets + +Assets such as icons can be found in the `/assets` directory of the package. Below is an example using Webpack: + +```ts +import { setupNightly } from "@near-wallet-selector/nightly"; +import nightlyIconUrl from "@near-wallet-selector/nightly/assets/nightly.png"; + +const nightly = setupNightly({ + iconUrl: nightlyIconUrl +}); +``` + +## License + +This repository is distributed under the terms of both the MIT license and the Apache License (Version 2.0). diff --git a/packages/nightly/assets/nightly.png b/packages/nightly/assets/nightly.png new file mode 100644 index 0000000000000000000000000000000000000000..bd3e873873ec6d24e8fffec7b1fbe456721923e3 GIT binary patch literal 9862 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 s>p(kRG@&hWRX{n~17`<%3U|`*|87@=4;/tsconfig.spec.json", + }, + }, + transform: { + "^.+\\.[tj]sx?$": "ts-jest", + }, + moduleFileExtensions: ["ts", "tsx", "js", "jsx"], + coverageDirectory: "../../coverage/packages/nightly", +}; diff --git a/packages/nightly/package.json b/packages/nightly/package.json new file mode 100644 index 000000000..5c540e7de --- /dev/null +++ b/packages/nightly/package.json @@ -0,0 +1,4 @@ +{ + "name": "@near-wallet-selector/nightly", + "version": "4.0.0" +} diff --git a/packages/nightly/project.json b/packages/nightly/project.json new file mode 100644 index 000000000..051e93334 --- /dev/null +++ b/packages/nightly/project.json @@ -0,0 +1,54 @@ +{ + "root": "packages/nightly", + "sourceRoot": "packages/nightly/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nrwl/web:rollup", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/nightly", + "tsConfig": "packages/nightly/tsconfig.lib.json", + "project": "packages/nightly/package.json", + "entryFile": "packages/nightly/src/index.ts", + "buildableProjectDepsInPackageJsonType": "dependencies", + "compiler": "babel", + "format": ["esm", "umd", "cjs"], + "assets": [ + { + "glob": "packages/nightly/README.md", + "input": ".", + "output": "." + }, + { + "glob": "packages/nightly/assets/*", + "input": ".", + "output": "assets" + } + ] + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["packages/nightly/**/*.ts"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/packages/nightly"], + "options": { + "jestConfig": "packages/nightly/jest.config.js", + "passWithNoTests": true + } + }, + "deploy": { + "executor": "ngx-deploy-npm:deploy", + "options": { + "access": "public" + } + } + }, + "tags": ["injected-wallet"] +} diff --git a/packages/nightly/src/index.ts b/packages/nightly/src/index.ts new file mode 100644 index 000000000..2bff821e3 --- /dev/null +++ b/packages/nightly/src/index.ts @@ -0,0 +1,2 @@ +export { setupNightly } from "./lib/nightly"; +export type { NightlyWalletParams } from "./lib/nightly"; diff --git a/packages/nightly/src/lib/injected-nightly.ts b/packages/nightly/src/lib/injected-nightly.ts new file mode 100644 index 000000000..af2b16a27 --- /dev/null +++ b/packages/nightly/src/lib/injected-nightly.ts @@ -0,0 +1,43 @@ +import { + SignedTransaction as NearSignedTransaction, + Transaction as NearTransaction, +} from "near-api-js/lib/transaction"; +import { PublicKey as NearPublicKey } from "near-api-js/lib/utils"; +export interface NearAccount { + accountId: string; + publicKey: NearPublicKey; +} +export interface WalletAdapter { + account: NearAccount; + connected: boolean; + signTransaction: ( + transaction: NearTransaction + ) => Promise; + signAllTransactions: ( + transaction: Array + ) => Promise>; + connect: (onDisconnect?: () => void) => Promise; + disconnect: () => Promise; +} + +export declare class NightlyInjected { + near: NearNightly; + private readonly _nightlyEventsMap; + constructor(); + invalidate(): void; +} + +export declare class NearNightly { + account: NearAccount; + _onDisconnect: () => void; + private readonly _nightlyEventsMap; + constructor(eventMap: Map unknown>); + connect(onDisconnect?: () => void): Promise; + disconnect(): Promise; + signTransaction: ( + transaction: NearTransaction + ) => Promise; + signAllTransactions: ( + transaction: Array + ) => Promise>; +} diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts new file mode 100644 index 000000000..36ce1c764 --- /dev/null +++ b/packages/nightly/src/lib/nightly.ts @@ -0,0 +1,170 @@ +import type { + InjectedWallet, + InjectedWalletMetadata, + WalletBehaviourFactory, + WalletModuleFactory, +} from "@near-wallet-selector/core"; +import { createAction } from "@near-wallet-selector/wallet-utils"; +import { isMobile } from "is-mobile"; +import { utils } from "near-api-js"; +import { JsonRpcProvider } from "near-api-js/lib/providers"; +import { createTransaction } from "near-api-js/lib/transaction"; +import { Account, waitFor } from "@near-wallet-selector/core"; +import type { NearNightly, NightlyInjected } from "./injected-nightly"; +import { PublicKey } from "near-api-js/lib/utils"; + +declare global { + interface Window { + nightly: NightlyInjected | undefined; + } +} + +interface NightlyState { + wallet: NearNightly; +} + +const setupNightlyState = (meta: InjectedWalletMetadata): NightlyState => { + const wallet = window.nightly?.near; + if (!wallet) { + window.location.href = meta.downloadUrl; + throw new Error("Redirecting to download"); + } + return { + wallet: wallet, + }; +}; + +const Nightly: WalletBehaviourFactory = async ({ + options, + store, + logger, + metadata, +}) => { + const _state = setupNightlyState(metadata); + const provider = new JsonRpcProvider({ url: options.network.nodeUrl }); + return { + // nightly does not support delegating signing right now + async signIn() { + const existingAccount = _state.wallet.account.accountId; + + if (existingAccount) { + const nearAccount: Account = { + accountId: _state.wallet.account.accountId, + }; + return [nearAccount]; + } + + const { accountId } = await _state.wallet.connect(); + const nearAccount: Account = { accountId }; + return [nearAccount]; + }, + + async signOut() { + await _state.wallet.disconnect(); + }, + + async getAccounts() { + const nearAccount: Account = { + accountId: _state.wallet.account.accountId, + }; + return [nearAccount]; + }, + + async signAndSendTransaction({ signerId, receiverId, actions }) { + logger.log("signAndSendTransaction", { signerId, receiverId, actions }); + const { contract } = store.getState(); + + if (!receiverId && !contract) { + throw new Error("Recipient not found"); + } + const blockInfo = await provider.query( + `access_key/${_state.wallet.account.accountId}/${ + _state.wallet.account.publicKey.toString().split(":")[1] + }`, + "" + ); + const blockHash = utils.serialize.base_decode(blockInfo.block_hash); + const tx = createTransaction( + signerId || _state.wallet.account.accountId, + new PublicKey(_state.wallet.account.publicKey), + receiverId || contract!.contractId, + // @ts-expect-error + ++blockInfo.nonce, + actions.map((a) => createAction(a)), + blockHash + ); + const signedTransactions = await _state.wallet.signTransaction(tx); + const result = await provider.sendTransaction(signedTransactions); + return result; + }, + + async signAndSendTransactions({ transactions }) { + logger.log("signAndSendTransactions", { transactions }); + const { contract } = store.getState(); + const blockInfo = await provider.query( + `access_key/${_state.wallet.account.accountId}/${ + _state.wallet.account.publicKey.toString().split(":")[1] + }`, + "" + ); + + const blockHash = utils.serialize.base_decode(blockInfo.block_hash); + const txs = transactions.map((txData) => { + if (!contract && txData.receiverId) { + throw new Error("Recipient not found"); + } + const tx = createTransaction( + txData.signerId || _state.wallet.account.accountId, + new PublicKey(_state.wallet.account.publicKey), + txData.receiverId || contract!.contractId, + // @ts-expect-error + ++blockInfo.nonce, + txData.actions.map((a) => createAction(a)), + blockHash + ); + return tx; + }); + const signedTransactions = await _state.wallet.signAllTransactions(txs); + logger.log( + "signAndSendTransactions:signedTransactions", + signedTransactions + ); + return Promise.all( + signedTransactions.map((tx) => provider.sendTransaction(tx)) + ); + }, + }; +}; + +export interface NightlyWalletParams { + iconUrl?: string; +} +export function setupNightly({ + iconUrl = "./assets/nightly.png", +}: NightlyWalletParams = {}): WalletModuleFactory { + return async () => { + const mobile = isMobile(); + + if (mobile) { + return null; + } + + await waitFor(() => !!window.nightly?.near, { + timeout: 300, + }).catch(() => false); + + return { + id: "nightly", + type: "injected", + metadata: { + name: "Nightly", + description: null, + iconUrl, + // Will replace we open beta with stable version + downloadUrl: "https://www.nightly.app", + deprecated: false, + }, + init: Nightly, + }; + }; +} diff --git a/packages/nightly/tsconfig.json b/packages/nightly/tsconfig.json new file mode 100644 index 000000000..e258886ff --- /dev/null +++ b/packages/nightly/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/packages/nightly/tsconfig.lib.json b/packages/nightly/tsconfig.lib.json new file mode 100644 index 000000000..a8b9431f9 --- /dev/null +++ b/packages/nightly/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": [] + }, + "include": ["**/*.ts"], + "exclude": ["**/*.spec.ts"] +} diff --git a/packages/nightly/tsconfig.spec.json b/packages/nightly/tsconfig.spec.json new file mode 100644 index 000000000..67f149c4c --- /dev/null +++ b/packages/nightly/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.test.tsx", + "**/*.spec.tsx", + "**/*.test.js", + "**/*.spec.js", + "**/*.test.jsx", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/packages/wallet-connect/package.json b/packages/wallet-connect/package.json index 300c7d4bc..cb140f20c 100644 --- a/packages/wallet-connect/package.json +++ b/packages/wallet-connect/package.json @@ -1,4 +1,4 @@ { "name": "@near-wallet-selector/wallet-connect", - "version": "4.0.0" + "version": "4.0.0" } diff --git a/tsconfig.base.json b/tsconfig.base.json index 825f720aa..312f8e30b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -33,6 +33,9 @@ "@near-wallet-selector/sender": [ "packages/sender/src/index.ts" ], + "@near-wallet-selector/nightly": [ + "packages/nightly/src/index.ts" + ], "@near-wallet-selector/wallet-connect": [ "packages/wallet-connect/src/index.ts" ], diff --git a/workspace.json b/workspace.json index c8c3b2dc1..3dd52f59d 100644 --- a/workspace.json +++ b/workspace.json @@ -8,6 +8,7 @@ "near-wallet": "packages/near-wallet", "my-near-wallet": "packages/my-near-wallet", "sender": "packages/sender", + "nightly": "packages/nightly", "wallet-connect": "packages/wallet-connect", "angular": "examples/angular", "react": "examples/react", From 6633aeee402136f4c35cd8c9d693fed71e6389a5 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Fri, 3 Jun 2022 13:35:42 +0200 Subject: [PATCH 02/12] move eager connect to internal part of wallet --- examples/react/src/components/Content.tsx | 12 ------------ packages/nightly/src/lib/nightly.ts | 5 +++++ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/react/src/components/Content.tsx b/examples/react/src/components/Content.tsx index 2a1a208d7..7455df28d 100644 --- a/examples/react/src/components/Content.tsx +++ b/examples/react/src/components/Content.tsx @@ -25,18 +25,6 @@ const Content: React.FC = () => { const [messages, setMessages] = useState>([]); const [loading, setLoading] = useState(false); - // Try eager connect on app launch - useEffect(() => { - const eagerConnect = async () => { - const state = selector.store.getState(); - if (state.selectedWalletId === "nightly") { - const wallet = (await selector.wallet()) as InjectedWallet; - wallet.signIn({ contractId: CONTRACT_ID }); - } - }; - eagerConnect(); - }, []); - const getAccount = useCallback(async (): Promise => { if (!accountId) { return null; diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index 36ce1c764..acdbf17f5 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -42,6 +42,11 @@ const Nightly: WalletBehaviourFactory = async ({ }) => { const _state = setupNightlyState(metadata); const provider = new JsonRpcProvider({ url: options.network.nodeUrl }); + const state = store.getState(); + + if (state.selectedWalletId === "nightly") { + await _state.wallet.connect(); + } return { // nightly does not support delegating signing right now async signIn() { From 90a14ee85c9c22e70e183f20140154b8304e4331 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Fri, 3 Jun 2022 13:53:57 +0200 Subject: [PATCH 03/12] fix unused import --- examples/react/src/components/Content.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/react/src/components/Content.tsx b/examples/react/src/components/Content.tsx index 7455df28d..2bbfe09f9 100644 --- a/examples/react/src/components/Content.tsx +++ b/examples/react/src/components/Content.tsx @@ -12,7 +12,6 @@ import { CONTRACT_ID } from "../constants"; import SignIn from "./SignIn"; import Form from "./Form"; import Messages from "./Messages"; -import { InjectedWallet } from "@near-wallet-selector/core"; const SUGGESTED_DONATION = "0"; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion From 064e995002ca8b4aeff9e5fb9354829c0d758140 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Mon, 6 Jun 2022 17:14:01 +0200 Subject: [PATCH 04/12] fix getAccounts method --- packages/nightly/src/lib/nightly.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index acdbf17f5..b4db93e2f 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -47,6 +47,15 @@ const Nightly: WalletBehaviourFactory = async ({ if (state.selectedWalletId === "nightly") { await _state.wallet.connect(); } + const getAccounts = async () => { + if (_state.wallet.account.accountId === "") { + return []; + } + const nearAccount: Account = { + accountId: _state.wallet.account.accountId, + }; + return [nearAccount]; + }; return { // nightly does not support delegating signing right now async signIn() { @@ -58,10 +67,7 @@ const Nightly: WalletBehaviourFactory = async ({ }; return [nearAccount]; } - - const { accountId } = await _state.wallet.connect(); - const nearAccount: Account = { accountId }; - return [nearAccount]; + return await getAccounts(); }, async signOut() { @@ -69,10 +75,7 @@ const Nightly: WalletBehaviourFactory = async ({ }, async getAccounts() { - const nearAccount: Account = { - accountId: _state.wallet.account.accountId, - }; - return [nearAccount]; + return await getAccounts(); }, async signAndSendTransaction({ signerId, receiverId, actions }) { From 9045fcce8e08112e2fd792bf46416f7981c5e75c Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Mon, 6 Jun 2022 17:15:37 +0200 Subject: [PATCH 05/12] add nightly to Readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 30d8c05d8..3150d9989 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ yarn add \ @near-wallet-selector/math-wallet \ @near-wallet-selector/ledger \ @near-wallet-selector/wallet-connect + @near-wallet-selector/nightly # Using NPM. npm install \ @@ -47,6 +48,7 @@ npm install \ @near-wallet-selector/math-wallet \ @near-wallet-selector/ledger \ @near-wallet-selector/wallet-connect + @near-wallet-selector/nightly ``` Optionally, you can install our [`modal-ui`](https://www.npmjs.com/package/@near-wallet-selector/modal-ui) package for a pre-built interface that wraps the `core` API and presents the supported wallets: @@ -70,6 +72,7 @@ import { setupSender } from "@near-wallet-selector/sender"; import { setupMathWallet } from "@near-wallet-selector/math-wallet"; import { setupLedger } from "@near-wallet-selector/ledger"; import { setupWalletConnect } from "@near-wallet-selector/wallet-connect"; +import { setupNightly } from "@near-wallet-selector/nightly"; const selector = await setupWalletSelector({ network: "testnet", @@ -79,6 +82,7 @@ const selector = await setupWalletSelector({ setupSender(), setupLedger(), setupMathWallet(), + setupNightly(), setupWalletConnect({ projectId: "c4f79cc...", metadata: { From 922a791fa1c25a8b31172d131bd9eede2d86c1a9 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Mon, 6 Jun 2022 17:42:57 +0200 Subject: [PATCH 06/12] use injected provider --- packages/nightly/src/lib/nightly.ts | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index b4db93e2f..a717f1502 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -7,11 +7,11 @@ import type { import { createAction } from "@near-wallet-selector/wallet-utils"; import { isMobile } from "is-mobile"; import { utils } from "near-api-js"; -import { JsonRpcProvider } from "near-api-js/lib/providers"; import { createTransaction } from "near-api-js/lib/transaction"; import { Account, waitFor } from "@near-wallet-selector/core"; import type { NearNightly, NightlyInjected } from "./injected-nightly"; import { PublicKey } from "near-api-js/lib/utils"; +import { AccessKeyView } from "near-api-js/lib/providers/provider"; declare global { interface Window { @@ -35,13 +35,12 @@ const setupNightlyState = (meta: InjectedWalletMetadata): NightlyState => { }; const Nightly: WalletBehaviourFactory = async ({ - options, store, logger, metadata, + provider, }) => { const _state = setupNightlyState(metadata); - const provider = new JsonRpcProvider({ url: options.network.nodeUrl }); const state = store.getState(); if (state.selectedWalletId === "nightly") { @@ -67,6 +66,8 @@ const Nightly: WalletBehaviourFactory = async ({ }; return [nearAccount]; } + await _state.wallet.connect(); + return await getAccounts(); }, @@ -85,18 +86,18 @@ const Nightly: WalletBehaviourFactory = async ({ if (!receiverId && !contract) { throw new Error("Recipient not found"); } - const blockInfo = await provider.query( - `access_key/${_state.wallet.account.accountId}/${ - _state.wallet.account.publicKey.toString().split(":")[1] - }`, - "" - ); + + const blockInfo = await provider.query({ + account_id: _state.wallet.account.accountId, + public_key: _state.wallet.account.publicKey.toString(), + request_type: "view_access_key", + finality: "final", + }); const blockHash = utils.serialize.base_decode(blockInfo.block_hash); const tx = createTransaction( signerId || _state.wallet.account.accountId, new PublicKey(_state.wallet.account.publicKey), receiverId || contract!.contractId, - // @ts-expect-error ++blockInfo.nonce, actions.map((a) => createAction(a)), blockHash @@ -109,12 +110,12 @@ const Nightly: WalletBehaviourFactory = async ({ async signAndSendTransactions({ transactions }) { logger.log("signAndSendTransactions", { transactions }); const { contract } = store.getState(); - const blockInfo = await provider.query( - `access_key/${_state.wallet.account.accountId}/${ - _state.wallet.account.publicKey.toString().split(":")[1] - }`, - "" - ); + const blockInfo = await provider.query({ + account_id: _state.wallet.account.accountId, + public_key: _state.wallet.account.publicKey.toString(), + request_type: "view_access_key", + finality: "final", + }); const blockHash = utils.serialize.base_decode(blockInfo.block_hash); const txs = transactions.map((txData) => { @@ -125,7 +126,6 @@ const Nightly: WalletBehaviourFactory = async ({ txData.signerId || _state.wallet.account.accountId, new PublicKey(_state.wallet.account.publicKey), txData.receiverId || contract!.contractId, - // @ts-expect-error ++blockInfo.nonce, txData.actions.map((a) => createAction(a)), blockHash From 829537da8a2c1445440509222d51edd5978e5d51 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Mon, 6 Jun 2022 17:55:57 +0200 Subject: [PATCH 07/12] refactor wallet setup --- packages/nightly/src/lib/nightly.ts | 69 +++++++++++++---------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index a717f1502..4dbdb72b6 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -1,17 +1,16 @@ import type { InjectedWallet, - InjectedWalletMetadata, WalletBehaviourFactory, WalletModuleFactory, } from "@near-wallet-selector/core"; +import { Account, waitFor } from "@near-wallet-selector/core"; import { createAction } from "@near-wallet-selector/wallet-utils"; import { isMobile } from "is-mobile"; import { utils } from "near-api-js"; +import { AccessKeyView } from "near-api-js/lib/providers/provider"; import { createTransaction } from "near-api-js/lib/transaction"; -import { Account, waitFor } from "@near-wallet-selector/core"; -import type { NearNightly, NightlyInjected } from "./injected-nightly"; import { PublicKey } from "near-api-js/lib/utils"; -import { AccessKeyView } from "near-api-js/lib/providers/provider"; +import type { NearNightly, NightlyInjected } from "./injected-nightly"; declare global { interface Window { @@ -19,60 +18,54 @@ declare global { } } -interface NightlyState { - wallet: NearNightly; -} - -const setupNightlyState = (meta: InjectedWalletMetadata): NightlyState => { - const wallet = window.nightly?.near; - if (!wallet) { - window.location.href = meta.downloadUrl; - throw new Error("Redirecting to download"); - } - return { - wallet: wallet, - }; +const setupNightlyState = (): NearNightly | undefined => { + return window.nightly?.near; }; const Nightly: WalletBehaviourFactory = async ({ + metadata, store, logger, - metadata, provider, }) => { - const _state = setupNightlyState(metadata); - const state = store.getState(); + const _state = setupNightlyState(); + const currentState = store.getState(); - if (state.selectedWalletId === "nightly") { - await _state.wallet.connect(); + if (currentState.selectedWalletId === "nightly") { + await _state?.connect(); } const getAccounts = async () => { - if (_state.wallet.account.accountId === "") { + if (!_state || _state.account.accountId === "") { return []; } const nearAccount: Account = { - accountId: _state.wallet.account.accountId, + accountId: _state.account.accountId, }; return [nearAccount]; }; return { // nightly does not support delegating signing right now async signIn() { - const existingAccount = _state.wallet.account.accountId; + // If wallet does not exist user will be redirected to download page + if (!_state) { + window.location.href = metadata.downloadUrl; + throw new Error("Redirecting to download"); + } + const existingAccount = _state.account.accountId; if (existingAccount) { const nearAccount: Account = { - accountId: _state.wallet.account.accountId, + accountId: _state.account.accountId, }; return [nearAccount]; } - await _state.wallet.connect(); + await _state.connect(); return await getAccounts(); }, async signOut() { - await _state.wallet.disconnect(); + await _state!.disconnect(); }, async getAccounts() { @@ -88,21 +81,21 @@ const Nightly: WalletBehaviourFactory = async ({ } const blockInfo = await provider.query({ - account_id: _state.wallet.account.accountId, - public_key: _state.wallet.account.publicKey.toString(), + account_id: _state!.account.accountId, + public_key: _state!.account.publicKey.toString(), request_type: "view_access_key", finality: "final", }); const blockHash = utils.serialize.base_decode(blockInfo.block_hash); const tx = createTransaction( - signerId || _state.wallet.account.accountId, - new PublicKey(_state.wallet.account.publicKey), + signerId || _state!.account.accountId, + new PublicKey(_state!.account.publicKey), receiverId || contract!.contractId, ++blockInfo.nonce, actions.map((a) => createAction(a)), blockHash ); - const signedTransactions = await _state.wallet.signTransaction(tx); + const signedTransactions = await _state!.signTransaction(tx); const result = await provider.sendTransaction(signedTransactions); return result; }, @@ -111,8 +104,8 @@ const Nightly: WalletBehaviourFactory = async ({ logger.log("signAndSendTransactions", { transactions }); const { contract } = store.getState(); const blockInfo = await provider.query({ - account_id: _state.wallet.account.accountId, - public_key: _state.wallet.account.publicKey.toString(), + account_id: _state!.account.accountId, + public_key: _state!.account.publicKey.toString(), request_type: "view_access_key", finality: "final", }); @@ -123,8 +116,8 @@ const Nightly: WalletBehaviourFactory = async ({ throw new Error("Recipient not found"); } const tx = createTransaction( - txData.signerId || _state.wallet.account.accountId, - new PublicKey(_state.wallet.account.publicKey), + txData.signerId || _state!.account.accountId, + new PublicKey(_state!.account.publicKey), txData.receiverId || contract!.contractId, ++blockInfo.nonce, txData.actions.map((a) => createAction(a)), @@ -132,7 +125,7 @@ const Nightly: WalletBehaviourFactory = async ({ ); return tx; }); - const signedTransactions = await _state.wallet.signAllTransactions(txs); + const signedTransactions = await _state!.signAllTransactions(txs); logger.log( "signAndSendTransactions:signedTransactions", signedTransactions From 5786021d2e8532b3af80a1195cf71f95f1e7e40b Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Mon, 6 Jun 2022 18:11:21 +0200 Subject: [PATCH 08/12] add eagerConnect option --- packages/nightly/src/lib/injected-nightly.ts | 5 ++++- packages/nightly/src/lib/nightly.ts | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/nightly/src/lib/injected-nightly.ts b/packages/nightly/src/lib/injected-nightly.ts index af2b16a27..27488bc65 100644 --- a/packages/nightly/src/lib/injected-nightly.ts +++ b/packages/nightly/src/lib/injected-nightly.ts @@ -32,7 +32,10 @@ export declare class NearNightly { _onDisconnect: () => void; private readonly _nightlyEventsMap; constructor(eventMap: Map unknown>); - connect(onDisconnect?: () => void): Promise; + connect( + onDisconnect?: () => void, + eagerConnect?: boolean + ): Promise; disconnect(): Promise; signTransaction: ( transaction: NearTransaction diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index 4dbdb72b6..f2b55ad2b 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -30,9 +30,13 @@ const Nightly: WalletBehaviourFactory = async ({ }) => { const _state = setupNightlyState(); const currentState = store.getState(); - if (currentState.selectedWalletId === "nightly") { - await _state?.connect(); + try { + // eager connect to the wallet + await _state?.connect(undefined, true); + } catch { + // ignore + } } const getAccounts = async () => { if (!_state || _state.account.accountId === "") { From 55b918ebf6991e08b32220b4197d9443c6ae760d Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Tue, 14 Jun 2022 14:38:37 +0200 Subject: [PATCH 09/12] use interfaces instead of classes --- packages/nightly/src/lib/injected-nightly.ts | 31 ++++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/nightly/src/lib/injected-nightly.ts b/packages/nightly/src/lib/injected-nightly.ts index 27488bc65..9480fbf3b 100644 --- a/packages/nightly/src/lib/injected-nightly.ts +++ b/packages/nightly/src/lib/injected-nightly.ts @@ -20,27 +20,26 @@ export interface WalletAdapter { disconnect: () => Promise; } -export declare class NightlyInjected { - near: NearNightly; - private readonly _nightlyEventsMap; - constructor(); - invalidate(): void; +export interface NightlyAccount { + accountId: string; + publicKey: NearPublicKey; } - -export declare class NearNightly { - account: NearAccount; - _onDisconnect: () => void; - private readonly _nightlyEventsMap; - constructor(eventMap: Map unknown>); - connect( - onDisconnect?: () => void, - eagerConnect?: boolean - ): Promise; - disconnect(): Promise; +export interface NearNightly { + account: NightlyAccount; + connected: boolean; signTransaction: ( transaction: NearTransaction ) => Promise; signAllTransactions: ( transaction: Array ) => Promise>; + connect: ( + onDisconnect?: () => void, + eagerConnect?: boolean + ) => Promise; + disconnect: () => Promise; +} +export interface NightlyInjected { + near: NearNightly; + invalidate: () => void; } From 33bb3202b47ffc3f0fe2dbc2fc8460ab56816baf Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Tue, 14 Jun 2022 14:51:03 +0200 Subject: [PATCH 10/12] enforce installed extension --- packages/nightly/src/lib/injected-nightly.ts | 2 +- packages/nightly/src/lib/nightly.ts | 67 +++++++++++++------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/packages/nightly/src/lib/injected-nightly.ts b/packages/nightly/src/lib/injected-nightly.ts index 9480fbf3b..cacf669a0 100644 --- a/packages/nightly/src/lib/injected-nightly.ts +++ b/packages/nightly/src/lib/injected-nightly.ts @@ -39,7 +39,7 @@ export interface NearNightly { ) => Promise; disconnect: () => Promise; } -export interface NightlyInjected { +export interface InjectedNightly { near: NearNightly; invalidate: () => void; } diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index f2b55ad2b..855292692 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -2,6 +2,7 @@ import type { InjectedWallet, WalletBehaviourFactory, WalletModuleFactory, + WalletSelectorStore, } from "@near-wallet-selector/core"; import { Account, waitFor } from "@near-wallet-selector/core"; import { createAction } from "@near-wallet-selector/wallet-utils"; @@ -10,40 +11,57 @@ import { utils } from "near-api-js"; import { AccessKeyView } from "near-api-js/lib/providers/provider"; import { createTransaction } from "near-api-js/lib/transaction"; import { PublicKey } from "near-api-js/lib/utils"; -import type { NearNightly, NightlyInjected } from "./injected-nightly"; +import type { NearNightly, InjectedNightly } from "./injected-nightly"; declare global { interface Window { - nightly: NightlyInjected | undefined; + nightly: InjectedNightly | undefined; } } -const setupNightlyState = (): NearNightly | undefined => { - return window.nightly?.near; -}; +interface NightlyState { + wallet: NearNightly; +} +const setupNightlyState = async ( + store: WalletSelectorStore +): Promise => { + const { selectedWalletId } = store.getState(); + const wallet = window.nightly!.near!; + // Attempt to reconnect wallet if previously selected. + if (selectedWalletId === "nightly") { + await wallet.connect(undefined, true).catch(() => null); + } + return { + wallet, + }; +}; +const isInstalled = () => { + return waitFor(() => !!window.nightly!.near!).catch(() => false); +}; const Nightly: WalletBehaviourFactory = async ({ metadata, store, logger, provider, }) => { - const _state = setupNightlyState(); + const _state = await setupNightlyState(store); + const currentState = store.getState(); if (currentState.selectedWalletId === "nightly") { try { // eager connect to the wallet - await _state?.connect(undefined, true); + await _state.wallet.connect(undefined, true); } catch { // ignore } } const getAccounts = async () => { - if (!_state || _state.account.accountId === "") { + if (!_state || _state.wallet.account.accountId === "") { return []; } const nearAccount: Account = { - accountId: _state.account.accountId, + accountId: _state.wallet.account.accountId, }; return [nearAccount]; }; @@ -55,21 +73,21 @@ const Nightly: WalletBehaviourFactory = async ({ window.location.href = metadata.downloadUrl; throw new Error("Redirecting to download"); } - const existingAccount = _state.account.accountId; + const existingAccount = _state.wallet.account.accountId; if (existingAccount) { const nearAccount: Account = { - accountId: _state.account.accountId, + accountId: _state.wallet.account.accountId, }; return [nearAccount]; } - await _state.connect(); + await _state.wallet.connect(); return await getAccounts(); }, async signOut() { - await _state!.disconnect(); + await _state.wallet.disconnect(); }, async getAccounts() { @@ -85,21 +103,21 @@ const Nightly: WalletBehaviourFactory = async ({ } const blockInfo = await provider.query({ - account_id: _state!.account.accountId, - public_key: _state!.account.publicKey.toString(), + account_id: _state.wallet.account.accountId, + public_key: _state.wallet.account.publicKey.toString(), request_type: "view_access_key", finality: "final", }); const blockHash = utils.serialize.base_decode(blockInfo.block_hash); const tx = createTransaction( - signerId || _state!.account.accountId, - new PublicKey(_state!.account.publicKey), + signerId || _state.wallet.account.accountId, + new PublicKey(_state.wallet.account.publicKey), receiverId || contract!.contractId, ++blockInfo.nonce, actions.map((a) => createAction(a)), blockHash ); - const signedTransactions = await _state!.signTransaction(tx); + const signedTransactions = await _state.wallet.signTransaction(tx); const result = await provider.sendTransaction(signedTransactions); return result; }, @@ -108,8 +126,8 @@ const Nightly: WalletBehaviourFactory = async ({ logger.log("signAndSendTransactions", { transactions }); const { contract } = store.getState(); const blockInfo = await provider.query({ - account_id: _state!.account.accountId, - public_key: _state!.account.publicKey.toString(), + account_id: _state.wallet.account.accountId, + public_key: _state.wallet.account.publicKey.toString(), request_type: "view_access_key", finality: "final", }); @@ -120,8 +138,8 @@ const Nightly: WalletBehaviourFactory = async ({ throw new Error("Recipient not found"); } const tx = createTransaction( - txData.signerId || _state!.account.accountId, - new PublicKey(_state!.account.publicKey), + txData.signerId || _state.wallet.account.accountId, + new PublicKey(_state.wallet.account.publicKey), txData.receiverId || contract!.contractId, ++blockInfo.nonce, txData.actions.map((a) => createAction(a)), @@ -129,7 +147,7 @@ const Nightly: WalletBehaviourFactory = async ({ ); return tx; }); - const signedTransactions = await _state!.signAllTransactions(txs); + const signedTransactions = await _state.wallet.signAllTransactions(txs); logger.log( "signAndSendTransactions:signedTransactions", signedTransactions @@ -149,8 +167,9 @@ export function setupNightly({ }: NightlyWalletParams = {}): WalletModuleFactory { return async () => { const mobile = isMobile(); + const installed = await isInstalled(); - if (mobile) { + if (mobile || !installed) { return null; } From 8f6e442f69ce3dc255e67516ab10bd3ae4460440 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Tue, 14 Jun 2022 15:47:39 +0200 Subject: [PATCH 11/12] revert change in WalletOptions --- packages/modal-ui/src/lib/components/WalletOptions.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/modal-ui/src/lib/components/WalletOptions.tsx b/packages/modal-ui/src/lib/components/WalletOptions.tsx index 1faef0eb3..dbff173dd 100644 --- a/packages/modal-ui/src/lib/components/WalletOptions.tsx +++ b/packages/modal-ui/src/lib/components/WalletOptions.tsx @@ -81,12 +81,7 @@ export const WalletOptions: React.FC = ({ key={module.id} id={module.id} className={selected ? "selected-wallet" : ""} - onClick={ - selected - ? // This kinda broke for me if we dont have eager connect - handleWalletClick(module) - : handleWalletClick(module) - } + onClick={selected ? undefined : handleWalletClick(module)} >
    {name} From 45125a100f0dc1944e462a92180be28072cea983 Mon Sep 17 00:00:00 2001 From: Norbert Bodziony Date: Tue, 14 Jun 2022 15:49:51 +0200 Subject: [PATCH 12/12] CR refactor --- packages/nightly/src/lib/nightly.ts | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index 855292692..10dd4838a 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -40,22 +40,12 @@ const isInstalled = () => { return waitFor(() => !!window.nightly!.near!).catch(() => false); }; const Nightly: WalletBehaviourFactory = async ({ - metadata, store, logger, provider, }) => { const _state = await setupNightlyState(store); - const currentState = store.getState(); - if (currentState.selectedWalletId === "nightly") { - try { - // eager connect to the wallet - await _state.wallet.connect(undefined, true); - } catch { - // ignore - } - } const getAccounts = async () => { if (!_state || _state.wallet.account.accountId === "") { return []; @@ -68,19 +58,12 @@ const Nightly: WalletBehaviourFactory = async ({ return { // nightly does not support delegating signing right now async signIn() { - // If wallet does not exist user will be redirected to download page - if (!_state) { - window.location.href = metadata.downloadUrl; - throw new Error("Redirecting to download"); - } const existingAccount = _state.wallet.account.accountId; if (existingAccount) { - const nearAccount: Account = { - accountId: _state.wallet.account.accountId, - }; - return [nearAccount]; + return await getAccounts(); } + await _state.wallet.connect(); return await getAccounts();