diff --git a/examples/angular/src/app/components/content/content.component.ts b/examples/angular/src/app/components/content/content.component.ts index 31b010090..90653ba53 100644 --- a/examples/angular/src/app/components/content/content.component.ts +++ b/examples/angular/src/app/components/content/content.component.ts @@ -292,7 +292,6 @@ export class ContentComponent implements OnInit, OnDestroy { } async addMessages(message: string, donation: string, multiple: boolean) { - const { contract } = this.selector.store.getState(); const wallet = await this.selector.wallet(); if (!multiple) { @@ -300,6 +299,7 @@ export class ContentComponent implements OnInit, OnDestroy { .signAndSendTransaction({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion signerId: this.accountId!, + receiverId: CONTRACT_ID, actions: [ { type: "FunctionCall", @@ -328,7 +328,7 @@ export class ContentComponent implements OnInit, OnDestroy { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion signerId: this.accountId!, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - receiverId: contract!.contractId, + receiverId: CONTRACT_ID, actions: [ { type: "FunctionCall", diff --git a/examples/angular/src/app/pages/wallet-selector/wallet-selector.component.ts b/examples/angular/src/app/pages/wallet-selector/wallet-selector.component.ts index 0b7b8be43..9c99176c3 100644 --- a/examples/angular/src/app/pages/wallet-selector/wallet-selector.component.ts +++ b/examples/angular/src/app/pages/wallet-selector/wallet-selector.component.ts @@ -88,7 +88,7 @@ export class WalletSelectorComponent implements OnInit { }); const _modal = setupModal(_selector, { - contractId: CONTRACT_ID, + contracts: [{ receiverId: CONTRACT_ID, methodNames: [] }], }); const state = _selector.store.getState(); diff --git a/examples/react/components/Content.tsx b/examples/react/components/Content.tsx index 271442fa9..79e54b88d 100644 --- a/examples/react/components/Content.tsx +++ b/examples/react/components/Content.tsx @@ -161,12 +161,12 @@ const Content: React.FC = () => { const addMessages = useCallback( async (message: string, donation: string, multiple: boolean) => { - const { contract } = selector.store.getState(); const wallet = await selector.wallet(); if (!multiple) { return wallet .signAndSendTransaction({ signerId: accountId!, + receiverId: CONTRACT_ID, actions: [ { type: "FunctionCall", @@ -192,7 +192,7 @@ const Content: React.FC = () => { for (let i = 0; i < 2; i += 1) { transactions.push({ signerId: accountId!, - receiverId: contract!.contractId, + receiverId: CONTRACT_ID, actions: [ { type: "FunctionCall", diff --git a/examples/react/contexts/WalletSelectorContext.tsx b/examples/react/contexts/WalletSelectorContext.tsx index 158ea3817..abae79d9a 100644 --- a/examples/react/contexts/WalletSelectorContext.tsx +++ b/examples/react/contexts/WalletSelectorContext.tsx @@ -98,7 +98,7 @@ export const WalletSelectorContextProvider: React.FC<{ ], }); const _modal = setupModal(_selector, { - contractId: CONTRACT_ID, + contracts: [{ receiverId: CONTRACT_ID, methodNames: [] }], }); const state = _selector.store.getState(); setAccounts(state.accounts); diff --git a/packages/bitget-wallet/src/lib/bitget-wallet.ts b/packages/bitget-wallet/src/lib/bitget-wallet.ts index 69fa693b3..c9cf3c016 100644 --- a/packages/bitget-wallet/src/lib/bitget-wallet.ts +++ b/packages/bitget-wallet/src/lib/bitget-wallet.ts @@ -191,15 +191,15 @@ const BitgetWallet: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.wallet.isSignedIn() || !contract) { + if (!_state.wallet.isSignedIn() || contracts.length < 1) { throw new Error("Wallet not signed in"); } return _state.wallet .signAndSendTransaction({ - receiverId: receiverId || contract.contractId, + receiverId: receiverId, actions: actions, }) .then((res) => { diff --git a/packages/coin98-wallet/src/lib/coin98-wallet.ts b/packages/coin98-wallet/src/lib/coin98-wallet.ts index 5ce20c3a5..9cf090ccc 100644 --- a/packages/coin98-wallet/src/lib/coin98-wallet.ts +++ b/packages/coin98-wallet/src/lib/coin98-wallet.ts @@ -70,11 +70,11 @@ const Coin98Wallet: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!contract) { + if (contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -87,7 +87,7 @@ const Coin98Wallet: WalletBehaviourFactory = async ({ return transactions.map((transaction) => { return { signerId: transaction.signerId || account.accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); diff --git a/packages/core/docs/api/state.md b/packages/core/docs/api/state.md index 2fe39d8c7..9a5a393cd 100644 --- a/packages/core/docs/api/state.md +++ b/packages/core/docs/api/state.md @@ -1,28 +1,9 @@ ## API Reference (State) - -### `.contract` - -**Returns** - -- `ContractState | null` - - `contractId` (`string`): Account ID of the Smart Contract. - - `methodNames` (`Array`): List of methods that can only be invoked on the Smart Contract. Empty list means no restriction. - -**Description** - -Returns the signed in contract. - -**Example** - -```ts -const { contract } = selector.store.getState(); -console.log(contract); // { contractId: "test.testnet", methodNames: [] } -``` ### `.contracts` **Returns** -- `MultiContractState | null` +- `MultiContractState` - `contractId` (`string`): Account ID of the Smart Contract. - `methodNames` (`Array`): List of methods that can only be invoked on the Smart Contract. Empty list means no restriction. diff --git a/packages/core/docs/api/wallet.md b/packages/core/docs/api/wallet.md index 652fde001..4e57933f6 100644 --- a/packages/core/docs/api/wallet.md +++ b/packages/core/docs/api/wallet.md @@ -309,7 +309,7 @@ Signs the message and verifies the owner. Message is not sent to blockchain. - `params` (`object`) - `signerId` (`string?`): Account ID used to sign the transaction. Defaults to the first account. - - `receiverId` (`string?`): Account ID to receive the transaction. Defaults to `contractId` defined in `.init`. + - `receiverId` (`string`): Account ID to receive the transaction. Defaults to `contractId` defined in `.init`. - `actions` (`Array`): NEAR Action(s) to sign and send to the network (e.g. `FunctionCall`). You can find more information on `Action` [here](./transactions.md). - `callbackUrl` (`string?`): Applicable to browser wallets (e.g. MyNearWallet). This the callback url once the transaction is approved. diff --git a/packages/core/src/lib/services/wallet-modules/wallet-modules.service.ts b/packages/core/src/lib/services/wallet-modules/wallet-modules.service.ts index 362268af3..72eb97eae 100644 --- a/packages/core/src/lib/services/wallet-modules/wallet-modules.service.ts +++ b/packages/core/src/lib/services/wallet-modules/wallet-modules.service.ts @@ -12,19 +12,13 @@ import type { } from "../../wallet"; import type { StorageService } from "../storage/storage.service.types"; import type { Options } from "../../options.types"; -import type { - ContractState, - ModuleState, - Store, - MultiContractState, -} from "../../store.types"; +import type { ModuleState, Store, MultiContractState } from "../../store.types"; import { EventEmitter } from "../event-emitter/event-emitter.service"; import type { WalletSelectorEvents } from "../../wallet-selector.types"; import { Logger, logger } from "../logger/logger.service"; import { RECENTLY_SIGNED_IN_WALLETS, PACKAGE_NAME, - PENDING_CONTRACT, PENDING_SELECTED_WALLET_ID, PENDING_CONTRACTS, } from "../../constants"; @@ -85,23 +79,15 @@ export class WalletModules { const pendingSelectedWalletId = await jsonStorage.getItem( PENDING_SELECTED_WALLET_ID ); - const pendingContract = await jsonStorage.getItem( - PENDING_CONTRACT - ); - const pendingContracts = await jsonStorage.getItem( - PENDING_CONTRACTS - ); + const pendingContracts = + (await jsonStorage.getItem(PENDING_CONTRACTS)) || []; - if (pendingSelectedWalletId && pendingContract) { + if (pendingSelectedWalletId && pendingContracts) { const accounts = await this.validateWallet(pendingSelectedWalletId); await jsonStorage.removeItem(PENDING_SELECTED_WALLET_ID); - await jsonStorage.removeItem(PENDING_CONTRACT); - - if (pendingContracts) { - await jsonStorage.removeItem(PENDING_CONTRACTS); - } + await jsonStorage.removeItem(PENDING_CONTRACTS); if (accounts.length) { const { selectedWalletId } = this.store.getState(); @@ -119,7 +105,6 @@ export class WalletModules { return { accounts, - contract: pendingContract, selectedWalletId: pendingSelectedWalletId, recentlySignedInWallets: recentlySignedInWalletsFromPending, contracts: pendingContracts, @@ -127,7 +112,7 @@ export class WalletModules { } } - const { contract, selectedWalletId, contracts } = this.store.getState(); + const { selectedWalletId, contracts } = this.store.getState(); const accounts = await this.validateWallet(selectedWalletId); const recentlySignedInWallets = await jsonStorage.getItem>( @@ -137,16 +122,14 @@ export class WalletModules { if (!accounts.length) { return { accounts: [], - contract: null, selectedWalletId: null, recentlySignedInWallets: recentlySignedInWallets || [], - contracts: null, + contracts: [], }; } return { accounts, - contract, selectedWalletId, recentlySignedInWallets: recentlySignedInWallets || [], contracts, @@ -190,11 +173,10 @@ export class WalletModules { private async onWalletSignedIn( walletId: string, - { accounts, contractId, methodNames, contracts }: WalletEvents["signedIn"] + { accounts, contracts }: WalletEvents["signedIn"] ) { const { selectedWalletId } = this.store.getState(); const jsonStorage = new JsonStorage(this.storage, PACKAGE_NAME); - const contract = { contractId, methodNames }; if (!accounts.length) { const module = this.getModule(walletId)!; @@ -202,14 +184,10 @@ export class WalletModules { // Best we can do is set in storage and validate on init. if (module.type === "browser") { await jsonStorage.setItem(PENDING_SELECTED_WALLET_ID, walletId); - await jsonStorage.setItem(PENDING_CONTRACT, contract); - - if (contracts) { - await jsonStorage.setItem( - PENDING_CONTRACTS, - contracts - ); - } + await jsonStorage.setItem( + PENDING_CONTRACTS, + contracts + ); } return; @@ -227,7 +205,6 @@ export class WalletModules { type: "WALLET_CONNECTED", payload: { walletId, - contract, accounts, recentlySignedInWallets, contracts, @@ -236,8 +213,6 @@ export class WalletModules { this.emitter.emit("signedIn", { walletId, - contractId, - methodNames, accounts, contracts, }); @@ -319,9 +294,7 @@ export class WalletModules { const { contractId, methodNames = [] } = params as SignInParams; await this.onWalletSignedIn(wallet.id, { accounts, - contractId, - methodNames, - contracts: null, + contracts: [{ contractId, methodNames }], }); return accounts; @@ -341,8 +314,6 @@ export class WalletModules { })); await this.onWalletSignedIn(wallet.id, { accounts, - contractId: contracts[0].contractId, - methodNames: contracts[0].methodNames, contracts, }); @@ -467,20 +438,14 @@ export class WalletModules { this.modules = modules; - const { - accounts, - contract, - selectedWalletId, - recentlySignedInWallets, - contracts, - } = await this.resolveStorageState(); + const { accounts, selectedWalletId, recentlySignedInWallets, contracts } = + await this.resolveStorageState(); this.store.dispatch({ type: "SETUP_WALLET_MODULES", payload: { modules, accounts, - contract, selectedWalletId, recentlySignedInWallets, contracts, diff --git a/packages/core/src/lib/store.ts b/packages/core/src/lib/store.ts index 908e8810a..534a88c27 100644 --- a/packages/core/src/lib/store.ts +++ b/packages/core/src/lib/store.ts @@ -9,10 +9,10 @@ import type { } from "./store.types"; import { PACKAGE_NAME, - CONTRACT, SELECTED_WALLET_ID, RECENTLY_SIGNED_IN_WALLETS, CONTRACTS, + CONTRACT, } from "./constants"; const reducer = ( @@ -26,7 +26,6 @@ const reducer = ( const { modules, accounts, - contract, selectedWalletId, recentlySignedInWallets, contracts, @@ -43,20 +42,14 @@ const reducer = ( ...state, modules, accounts: accountStates, - contract, selectedWalletId, recentlySignedInWallets, contracts, }; } case "WALLET_CONNECTED": { - const { - walletId, - contract, - accounts, - recentlySignedInWallets, - contracts, - } = action.payload; + const { walletId, accounts, recentlySignedInWallets, contracts } = + action.payload; if (!accounts.length) { return state; @@ -75,7 +68,6 @@ const reducer = ( return { ...state, - contract, accounts: accountStates, selectedWalletId: walletId, recentlySignedInWallets, @@ -91,10 +83,9 @@ const reducer = ( return { ...state, - contract: null, accounts: [], selectedWalletId: null, - contracts: null, + contracts: [], }; } case "ACCOUNTS_CHANGED": { @@ -144,16 +135,27 @@ const reducer = ( } }; +const updateOldContractState = async (storage: JsonStorage) => { + const oldState = await storage.getItem(CONTRACT); + + if (oldState) { + await storage.setItem(CONTRACTS, [oldState]); + await storage.removeItem(CONTRACT); + } +}; + export const createStore = async (storage: StorageService): Promise => { const jsonStorage = new JsonStorage(storage, PACKAGE_NAME); + + await updateOldContractState(jsonStorage); + const initialState: WalletSelectorState = { modules: [], accounts: [], - contract: await jsonStorage.getItem(CONTRACT), selectedWalletId: await jsonStorage.getItem(SELECTED_WALLET_ID), recentlySignedInWallets: (await jsonStorage.getItem(RECENTLY_SIGNED_IN_WALLETS)) || [], - contracts: await jsonStorage.getItem(CONTRACTS), + contracts: (await jsonStorage.getItem(CONTRACTS)) || [], }; const state$ = new BehaviorSubject(initialState); @@ -182,7 +184,6 @@ export const createStore = async (storage: StorageService): Promise => { let prevState = state$.getValue(); state$.subscribe((state) => { syncStorage(prevState, state, SELECTED_WALLET_ID, "selectedWalletId"); - syncStorage(prevState, state, CONTRACT, "contract"); syncStorage( prevState, state, diff --git a/packages/core/src/lib/store.types.ts b/packages/core/src/lib/store.types.ts index 6db761b31..f09edf359 100644 --- a/packages/core/src/lib/store.types.ts +++ b/packages/core/src/lib/store.types.ts @@ -43,10 +43,6 @@ export type AccountState = Account & { }; export interface WalletSelectorState { - /** - * Returns the signed in contract. - */ - contract: ContractState | null; /** * Returns the list of available modules. */ @@ -64,9 +60,9 @@ export interface WalletSelectorState { */ recentlySignedInWallets: Array; /** - * The list of contracts when SignInMulti is supported. + * The list of contracts for SignIn and SignInMulti. */ - contracts: MultiContractState | null; + contracts: MultiContractState; } export type WalletSelectorAction = @@ -75,20 +71,18 @@ export type WalletSelectorAction = payload: { modules: Array; accounts: Array; - contract: ContractState | null; selectedWalletId: string | null; recentlySignedInWallets: Array; - contracts: MultiContractState | null; + contracts: MultiContractState; }; } | { type: "WALLET_CONNECTED"; payload: { walletId: string; - contract: ContractState; accounts: Array; recentlySignedInWallets: Array; - contracts: MultiContractState | null; + contracts: MultiContractState; }; } | { diff --git a/packages/core/src/lib/wallet-selector.types.ts b/packages/core/src/lib/wallet-selector.types.ts index 74d5fda69..9fcda0e76 100644 --- a/packages/core/src/lib/wallet-selector.types.ts +++ b/packages/core/src/lib/wallet-selector.types.ts @@ -54,10 +54,8 @@ export type WalletSelectorStore = ReadOnlyStore; export type WalletSelectorEvents = { signedIn: { walletId: string; - contractId: string; - methodNames: Array; accounts: Array; - contracts: MultiContractState | null; + contracts: MultiContractState; }; signedOut: { walletId: string; diff --git a/packages/core/src/lib/wallet/wallet.types.ts b/packages/core/src/lib/wallet/wallet.types.ts index c450dc81b..fd9dbf559 100644 --- a/packages/core/src/lib/wallet/wallet.types.ts +++ b/packages/core/src/lib/wallet/wallet.types.ts @@ -113,9 +113,9 @@ interface SignAndSendTransactionParams { */ signerId?: string; /** - * Account ID to receive the transaction. Defaults to `contractId` defined in `init`. + * Account ID to receive the transaction. */ - receiverId?: string; + receiverId: string; /** * NEAR Action(s) to sign and send to the network (e.g. `FunctionCall`). You can find more information on `Action` {@link https://github.com/near/wallet-selector/blob/main/packages/core/docs/api/transactions.md | here}. */ @@ -191,10 +191,8 @@ type BaseWallet< export type WalletEvents = { signedIn: { - contractId: string; - methodNames: Array; accounts: Array; - contracts: MultiContractState | null; + contracts: MultiContractState; }; signedOut: null; accountsChanged: { accounts: Array }; diff --git a/packages/here-wallet/src/lib/selector.ts b/packages/here-wallet/src/lib/selector.ts index d66cdaa07..220748f53 100644 --- a/packages/here-wallet/src/lib/selector.ts +++ b/packages/here-wallet/src/lib/selector.ts @@ -70,10 +70,10 @@ export const initHereWallet: SelectorInit = async (config) => { await here.signIn({ ...data, contractId: contractId }); emitter.emit("signedIn", { - contractId: data.contractId, - methodNames: data.methodNames ?? [], accounts: await getAccounts(), - contracts: null, + contracts: [ + { methodNames: data.methodNames || [], contractId: data.contractId }, + ], }); return await getAccounts(); @@ -101,15 +101,12 @@ export const initHereWallet: SelectorInit = async (config) => { async signAndSendTransaction(data) { logger.log("HereWallet:signAndSendTransaction", data); - const { contract } = store.getState(); - if (!here.isSignedIn || !contract) { + const { contracts } = store.getState(); + if (!here.isSignedIn || contracts.length < 1) { throw new Error("Wallet not signed in"); } - return await here.signAndSendTransaction({ - receiverId: contract.contractId, - ...data, - }); + return await here.signAndSendTransaction(data); }, async verifyOwner() { diff --git a/packages/ledger/src/lib/ledger.ts b/packages/ledger/src/lib/ledger.ts index 69fb7b86a..8766c5486 100644 --- a/packages/ledger/src/lib/ledger.ts +++ b/packages/ledger/src/lib/ledger.ts @@ -159,11 +159,11 @@ const Ledger: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!contract) { + if (contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -176,7 +176,7 @@ const Ledger: WalletBehaviourFactory = async ({ return transactions.map((transaction) => { return { signerId: transaction.signerId || account.accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); diff --git a/packages/math-wallet/src/lib/math-wallet.ts b/packages/math-wallet/src/lib/math-wallet.ts index 5dc75e7d0..9edb7216d 100644 --- a/packages/math-wallet/src/lib/math-wallet.ts +++ b/packages/math-wallet/src/lib/math-wallet.ts @@ -65,11 +65,11 @@ const MathWallet: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!contract) { + if (contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -82,7 +82,7 @@ const MathWallet: WalletBehaviourFactory = async ({ return transactions.map((transaction) => { return { signerId: transaction.signerId || account.accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); diff --git a/packages/meteor-wallet/src/lib/meteor-wallet.ts b/packages/meteor-wallet/src/lib/meteor-wallet.ts index f0c7f0b15..c4d54659d 100644 --- a/packages/meteor-wallet/src/lib/meteor-wallet.ts +++ b/packages/meteor-wallet/src/lib/meteor-wallet.ts @@ -157,20 +157,20 @@ const createMeteorWalletInjected: WalletBehaviourFactory< actions, }); - const { contract } = store.getState(); + const { contracts } = store.getState(); if (!_state.wallet.isSignedIn()) { throw new Error("Wallet not signed in"); } - if (!receiverId && !contract) { + if (!receiverId && contracts.length < 1) { throw new Error("No receiver found to send the transaction to"); } const account = _state.wallet.account()!; return account["signAndSendTransaction_direct"]({ - receiverId: receiverId ?? contract!.contractId, + receiverId: receiverId, actions, }); }, diff --git a/packages/modal-ui-js/README.md b/packages/modal-ui-js/README.md index 930202988..f5123d4f0 100644 --- a/packages/modal-ui-js/README.md +++ b/packages/modal-ui-js/README.md @@ -27,7 +27,7 @@ const selector = await setupWalletSelector({ }); const modal = setupModal(selector, { - contractId: "test.testnet", + contracts: [{ receiverId: "test.testnet", methodNames: [] }] }); modal.show(); @@ -35,8 +35,6 @@ modal.show(); ## Options -- `contractId` (`string`): Account ID of the Smart Contract used for sign in and signing transactions. -- `methodNames` (`Array?`): Specify limited access to particular methods on the Smart Contract. - `theme` (`Theme?`): Specify light/dark theme for UI. Defaults to the browser configuration when omitted or set to 'auto'. This can be either `light`, `dark` or `auto`. - `description` (`string?`): Define a custom description in the UI. - `contracts` (`Array<{allowance?: BN, receiverId: string, methodNames: Array}>?`): List of the Smart Contracts and the limited access to particular methods on the Smart Contract for signing in with multiple contracts. When the list of contracts is provided the `signInMulti` method of the wallets is used by default to sign-in. diff --git a/packages/modal-ui-js/src/lib/components/LedgerAccountsOverviewList.ts b/packages/modal-ui-js/src/lib/components/LedgerAccountsOverviewList.ts index d5f7b6bed..1ea3519d6 100644 --- a/packages/modal-ui-js/src/lib/components/LedgerAccountsOverviewList.ts +++ b/packages/modal-ui-js/src/lib/components/LedgerAccountsOverviewList.ts @@ -69,11 +69,19 @@ export async function renderLedgerAccountsOverviewList( } const wallet = await module.wallet(); - wallet.signIn({ - contractId: modalState.options.contractId, - methodNames: modalState.options.methodNames, - accounts: selectedAccounts, - }); + + if (modalState.options.contracts.length > 1) { + await wallet.signInMulti!({ + permissions: modalState.options.contracts, + accounts: selectedAccounts, + }); + } else { + await wallet.signIn({ + contractId: modalState.options.contracts[0].receiverId, + methodNames: modalState.options.contracts[0].methodNames, + accounts: selectedAccounts, + }); + } modalState.container.children[0].classList.remove("open"); modalState.emitter.emit("onHide", { hideReason: "wallet-navigation" }); diff --git a/packages/modal-ui-js/src/lib/modal.types.ts b/packages/modal-ui-js/src/lib/modal.types.ts index b09d02c86..001b26f55 100644 --- a/packages/modal-ui-js/src/lib/modal.types.ts +++ b/packages/modal-ui-js/src/lib/modal.types.ts @@ -6,11 +6,9 @@ import type { transactions } from "near-api-js"; export type Theme = "dark" | "light" | "auto"; export interface ModalOptions { - contractId: string; - methodNames?: Array; theme?: Theme; description?: string; - contracts?: Array; + contracts: Array; } export type ModalHideReason = "user-triggered" | "wallet-navigation"; diff --git a/packages/modal-ui-js/src/lib/render-modal.ts b/packages/modal-ui-js/src/lib/render-modal.ts index 3c4863021..8befe4d92 100644 --- a/packages/modal-ui-js/src/lib/render-modal.ts +++ b/packages/modal-ui-js/src/lib/render-modal.ts @@ -86,6 +86,10 @@ export async function connectToWallet( } try { + if (modalState.options.contracts.length < 1) { + throw new Error("No contract provided"); + } + if (module.type === "injected" && !module.metadata.available) { return renderWalletNotInstalled(module); } @@ -125,15 +129,15 @@ export async function connectToWallet( }); }); - if (modalState.options.contracts) { + if (modalState.options.contracts.length > 1) { await wallet.signInMulti!({ permissions: modalState.options.contracts, qrCodeModal, }); } else { await wallet.signIn({ - contractId: modalState.options.contractId, - methodNames: modalState.options.methodNames, + contractId: modalState.options.contracts[0].receiverId, + methodNames: modalState.options.contracts[0].methodNames, qrCodeModal, }); } @@ -145,7 +149,7 @@ export async function connectToWallet( } if (wallet.type === "browser") { - if (modalState.options.contracts) { + if (modalState.options.contracts.length > 1) { await wallet.signInMulti!({ permissions: modalState.options.contracts, successUrl: wallet.metadata.successUrl, @@ -153,8 +157,8 @@ export async function connectToWallet( }); } else { await wallet.signIn({ - contractId: modalState.options.contractId, - methodNames: modalState.options.methodNames, + contractId: modalState.options.contracts[0].receiverId, + methodNames: modalState.options.contracts[0].methodNames, successUrl: wallet.metadata.successUrl, failureUrl: wallet.metadata.failureUrl, }); @@ -166,14 +170,14 @@ export async function connectToWallet( return; } - if (modalState.options.contracts) { + if (modalState.options.contracts.length > 1) { await wallet.signInMulti!({ permissions: modalState.options.contracts, }); } else { await wallet.signIn({ - contractId: modalState.options.contractId, - methodNames: modalState.options.methodNames, + contractId: modalState.options.contracts[0].receiverId, + methodNames: modalState.options.contracts[0].methodNames, }); } diff --git a/packages/modal-ui/README.md b/packages/modal-ui/README.md index c3a78314c..85de77194 100644 --- a/packages/modal-ui/README.md +++ b/packages/modal-ui/README.md @@ -27,7 +27,7 @@ const selector = await setupWalletSelector({ }); const modal = setupModal(selector, { - contractId: "test.testnet", + contracts: [{ receiverId: "test.testnet", methodNames: [] }] }); modal.show(); @@ -35,8 +35,6 @@ modal.show(); ## Options -- `contractId` (`string`): Account ID of the Smart Contract used for sign in and signing transactions. -- `methodNames` (`Array?`): Specify limited access to particular methods on the Smart Contract. - `theme` (`Theme?`): Specify light/dark theme for UI. Defaults to the browser configuration when omitted or set to 'auto'. This can be either `light`, `dark` or `auto`. - `description` (`string?`): Define a custom description in the UI. - `contracts` (`Array<{allowance?: BN, receiverId: string, methodNames: Array}>?`): List of the Smart Contracts and the limited access to particular methods on the Smart Contract for signing in with multiple contracts. When the list of contracts is provided the `signInMulti` method of the wallets is used by default to sign-in. diff --git a/packages/modal-ui/src/lib/components/DerivationPath.tsx b/packages/modal-ui/src/lib/components/DerivationPath.tsx index 8aa8bc0ac..b34a54f52 100644 --- a/packages/modal-ui/src/lib/components/DerivationPath.tsx +++ b/packages/modal-ui/src/lib/components/DerivationPath.tsx @@ -192,16 +192,27 @@ export const DerivationPath: React.FC = ({ } ); - return hardwareWallet! - .signIn({ - contractId: options.contractId, - methodNames: options.methodNames, + if (options.contracts.length > 1) { + return hardwareWallet!.signInMulti!({ + permissions: options.contracts, accounts: mapAccounts, }) - .then(() => onConnected()) - .catch((err) => { - onError(`Error: ${err.message}`, hardwareWallet!); - }); + .then(() => onConnected()) + .catch((err) => { + onError(`Error: ${err.message}`, hardwareWallet!); + }); + } else { + return hardwareWallet! + .signIn({ + contractId: options.contracts[0].receiverId, + methodNames: options.contracts[0].methodNames, + accounts: mapAccounts, + }) + .then(() => onConnected()) + .catch((err) => { + onError(`Error: ${err.message}`, hardwareWallet!); + }); + } }; const handleOnBackButtonClick = () => { diff --git a/packages/modal-ui/src/lib/components/Modal.tsx b/packages/modal-ui/src/lib/components/Modal.tsx index 7205c7dac..f3c44993f 100644 --- a/packages/modal-ui/src/lib/components/Modal.tsx +++ b/packages/modal-ui/src/lib/components/Modal.tsx @@ -141,6 +141,10 @@ export const Modal: React.FC = ({ } try { + if (options.contracts.length < 1) { + throw new Error("No contract provided"); + } + const { deprecated, available } = module.metadata; if (module.type === "injected" && !available) { @@ -193,15 +197,15 @@ export const Modal: React.FC = ({ }); }); - if (options.contracts) { + if (options.contracts.length > 1) { await wallet.signInMulti!({ permissions: options.contracts, qrCodeModal, }); } else { await wallet.signIn({ - contractId: options.contractId, - methodNames: options.methodNames, + contractId: options.contracts[0].receiverId, + methodNames: options.contracts[0].methodNames, qrCodeModal, }); } @@ -212,7 +216,7 @@ export const Modal: React.FC = ({ } if (wallet.type === "browser") { - if (options.contracts) { + if (options.contracts.length > 1) { await wallet.signInMulti!({ permissions: options.contracts, successUrl: wallet.metadata.successUrl, @@ -220,8 +224,8 @@ export const Modal: React.FC = ({ }); } else { await wallet.signIn({ - contractId: options.contractId, - methodNames: options.methodNames, + contractId: options.contracts[0].receiverId, + methodNames: options.contracts[0].methodNames, successUrl: wallet.metadata.successUrl, failureUrl: wallet.metadata.failureUrl, }); @@ -232,14 +236,14 @@ export const Modal: React.FC = ({ return; } - if (options.contracts) { + if (options.contracts.length > 1) { await wallet.signInMulti!({ permissions: options.contracts, }); } else { await wallet.signIn({ - contractId: options.contractId, - methodNames: options.methodNames, + contractId: options.contracts[0].receiverId, + methodNames: options.contracts[0].methodNames, }); } diff --git a/packages/modal-ui/src/lib/modal.types.ts b/packages/modal-ui/src/lib/modal.types.ts index 508a1716b..edc7a090f 100644 --- a/packages/modal-ui/src/lib/modal.types.ts +++ b/packages/modal-ui/src/lib/modal.types.ts @@ -4,11 +4,9 @@ import type { transactions } from "near-api-js"; export type Theme = "dark" | "light" | "auto"; export interface ModalOptions { - contractId: string; - methodNames?: Array; theme?: Theme; description?: string; - contracts?: Array; + contracts: Array; } export type ModalHideReason = "user-triggered" | "wallet-navigation"; diff --git a/packages/my-near-wallet/src/lib/my-near-wallet.ts b/packages/my-near-wallet/src/lib/my-near-wallet.ts index 5a3721567..5bbe4b02c 100644 --- a/packages/my-near-wallet/src/lib/my-near-wallet.ts +++ b/packages/my-near-wallet/src/lib/my-near-wallet.ts @@ -206,16 +206,16 @@ const MyNearWallet: WalletBehaviourFactory< callbackUrl, }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.wallet.isSignedIn() || !contract) { + if (!_state.wallet.isSignedIn() || contracts.length < 1) { throw new Error("Wallet not signed in"); } const account = _state.wallet.account(); return account["signAndSendTransaction"]({ - receiverId: receiverId || contract.contractId, + receiverId, actions: actions.map((action) => createAction(action)), walletCallbackUrl: callbackUrl, }); diff --git a/packages/narwallets/src/lib/narwallets.ts b/packages/narwallets/src/lib/narwallets.ts index cfae7bdec..f14424f6c 100644 --- a/packages/narwallets/src/lib/narwallets.ts +++ b/packages/narwallets/src/lib/narwallets.ts @@ -236,15 +236,15 @@ const Narwallets: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract, accounts } = store.getState(); + const { contracts, accounts } = store.getState(); - if (!accounts || accounts.length === 0 || !contract) { + if (!accounts || accounts.length === 0 || contracts.length < 1) { throw new Error("Wallet not signed in"); } return callSignAndSendTransaction({ signerId, - receiverId: receiverId || contract.contractId, + receiverId, actions: actions, }) as Promise; }, @@ -252,10 +252,10 @@ const Narwallets: WalletBehaviourFactory = async ({ async signAndSendTransactions({ transactions }) { logger.log("signAndSendTransactions", { transactions }); - const { contract, accounts } = store.getState(); + const { contracts, accounts } = store.getState(); // test: avoid a call to isSignedIn - if (!accounts || accounts.length === 0 || !contract) { + if (!accounts || accounts.length === 0 || contracts.length < 1) { throw new Error("Wallet not signed in"); } diff --git a/packages/near-mobile-wallet/src/lib/init.wallet.ts b/packages/near-mobile-wallet/src/lib/init.wallet.ts index 17565d2de..22447dd07 100644 --- a/packages/near-mobile-wallet/src/lib/init.wallet.ts +++ b/packages/near-mobile-wallet/src/lib/init.wallet.ts @@ -55,13 +55,13 @@ export const initNearMobileWallet: NearMobileWalletInit = async (config) => { async signAndSendTransaction(data) { logger.log("[NearMobileWallet]: signAndSendTransaction", data); - const { contract } = store.getState(); - if (!contract) { + const { contracts } = store.getState(); + if (contracts.length < 1) { throw new Error("Wallet not signed in"); } return await nearMobileWallet.signAndSendTransaction({ - receiverId: contract.contractId, + receiverId: data.receiverId, ...data, }); }, diff --git a/packages/near-snap/src/lib/selector.ts b/packages/near-snap/src/lib/selector.ts index ba49ea261..2ef409465 100644 --- a/packages/near-snap/src/lib/selector.ts +++ b/packages/near-snap/src/lib/selector.ts @@ -44,19 +44,19 @@ export const initNearSnap: WalletBehaviourFactory = async ( async signAndSendTransaction(data) { logger.log("NearSnap:signAndSendTransaction", data); + const { contracts } = store.getState(); - if (account == null) { + if (account === null || contracts.length < 1) { throw new Error("Wallet not signed in"); } - const { contract } = store.getState(); - const receiverId = data.receiverId ?? contract?.contractId; + const receiverId = data.receiverId; if (receiverId == null) { throw new Error("ReceiverId is not defined"); } - return await account.executeTransaction({ receiverId, ...data }); + return await account.executeTransaction({ ...data, receiverId }); }, async signMessage({ message, nonce, recipient }) { diff --git a/packages/nearfi/src/lib/nearfi.ts b/packages/nearfi/src/lib/nearfi.ts index e4fc958c3..0515db461 100644 --- a/packages/nearfi/src/lib/nearfi.ts +++ b/packages/nearfi/src/lib/nearfi.ts @@ -177,15 +177,15 @@ const NearFi: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.wallet.isSignedIn() || !contract) { + if (!_state.wallet.isSignedIn() || contracts.length < 1) { throw new Error("Wallet not signed in"); } return _state.wallet .signAndSendTransaction({ - receiverId: receiverId || contract.contractId, + receiverId, actions: transformActions(actions), }) .then((res) => { diff --git a/packages/neth/src/lib/neth.ts b/packages/neth/src/lib/neth.ts index 3bcce1445..45b684035 100644 --- a/packages/neth/src/lib/neth.ts +++ b/packages/neth/src/lib/neth.ts @@ -90,9 +90,9 @@ const Neth: WalletBehaviourFactory = async ({ const signTransactions = async (transactions) => { logger.log("NETH:signAndSendTransactions", { transactions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!(await isSignedIn()) || !contract) { + if (!(await isSignedIn()) || contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -101,7 +101,7 @@ const Neth: WalletBehaviourFactory = async ({ } const transformedTxs = transactions.map(({ receiverId, actions }) => ({ - receiverId: receiverId || contract.contractId, + receiverId, actions: transformActions(actions), })); diff --git a/packages/nightly/src/lib/nightly.ts b/packages/nightly/src/lib/nightly.ts index 48d7e9056..82a00d3fa 100644 --- a/packages/nightly/src/lib/nightly.ts +++ b/packages/nightly/src/lib/nightly.ts @@ -87,19 +87,19 @@ const Nightly: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { const accounts = getAccounts(); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } return transactions.map((transaction) => { return { signerId: transaction.signerId || accounts[0].accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); @@ -210,10 +210,10 @@ const Nightly: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); const accounts = getAccounts(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } const [signedTx] = await signTransactions( diff --git a/packages/ramper-wallet/src/lib/ramper-wallet.ts b/packages/ramper-wallet/src/lib/ramper-wallet.ts index 655e3f45b..9738d8076 100644 --- a/packages/ramper-wallet/src/lib/ramper-wallet.ts +++ b/packages/ramper-wallet/src/lib/ramper-wallet.ts @@ -73,9 +73,9 @@ const RamperWallet: WalletBehaviourFactory = async ({ transactions: Array> ) => { const accounts = await getAccounts(); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -85,7 +85,7 @@ const RamperWallet: WalletBehaviourFactory = async ({ ); return { - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: parsedActions, }; }); @@ -127,10 +127,10 @@ const RamperWallet: WalletBehaviourFactory = async ({ }: Omit) { logger.log("signAndSendTransaction", { receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); const accounts = await getAccounts(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } diff --git a/packages/sender/src/lib/sender.ts b/packages/sender/src/lib/sender.ts index cd52cf6a1..a474b87e0 100644 --- a/packages/sender/src/lib/sender.ts +++ b/packages/sender/src/lib/sender.ts @@ -113,7 +113,6 @@ const Sender: WalletBehaviourFactory = async ({ } const accountId = _state.wallet.getAccountId(); - if (!accountId) { return []; } @@ -269,15 +268,15 @@ const Sender: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.wallet.isSignedIn() || !contract) { + if (!_state.wallet.isSignedIn() || contracts.length < 1) { throw new Error("Wallet not signed in"); } return _state.wallet .signAndSendTransaction({ - receiverId: receiverId || contract.contractId, + receiverId, actions: transformActions(actions), }) .then((res) => { diff --git a/packages/wallet-connect/src/lib/wallet-connect.ts b/packages/wallet-connect/src/lib/wallet-connect.ts index 5f5351d2f..9339dabe6 100644 --- a/packages/wallet-connect/src/lib/wallet-connect.ts +++ b/packages/wallet-connect/src/lib/wallet-connect.ts @@ -531,8 +531,8 @@ const WalletConnect: WalletBehaviourFactory< return { async signIn({ contractId, methodNames = [], qrCodeModal = true }) { try { - const { contract } = store.getState(); - if (_state.session && !contract) { + const { contracts } = store.getState(); + if (_state.session && !contracts) { await disconnect({ state: _state }); await cleanup(); } @@ -567,9 +567,9 @@ const WalletConnect: WalletBehaviourFactory< async verifyOwner({ message }) { logger.log("WalletConnect:verifyOwner", { message }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.session || !contract) { + if (!_state.session || contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -617,9 +617,9 @@ const WalletConnect: WalletBehaviourFactory< async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.session || !contract) { + if (!_state.session || contracts.length < 1) { throw new Error("Wallet not signed in"); } @@ -631,7 +631,7 @@ const WalletConnect: WalletBehaviourFactory< const resolvedTransaction: Transaction = { signerId: signerId || account.accountId, - receiverId: receiverId || contract.contractId, + receiverId, actions, }; @@ -649,9 +649,9 @@ const WalletConnect: WalletBehaviourFactory< async signAndSendTransactions({ transactions }) { logger.log("signAndSendTransactions", { transactions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!_state.session || !contract) { + if (!_state.session || contracts.length < 1) { throw new Error("Wallet not signed in"); } diff --git a/packages/welldone-wallet/src/lib/welldone.ts b/packages/welldone-wallet/src/lib/welldone.ts index e8831f112..95b0cade6 100644 --- a/packages/welldone-wallet/src/lib/welldone.ts +++ b/packages/welldone-wallet/src/lib/welldone.ts @@ -199,19 +199,19 @@ const WelldoneWallet: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { const accounts = getAccounts(); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } return transactions.map((transaction) => { return { signerId: transaction.signerId || accounts[0].accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); @@ -338,10 +338,10 @@ const WelldoneWallet: WalletBehaviourFactory = async ({ async signAndSendTransaction({ signerId, receiverId, actions }) { logger.log("signAndSendTransaction", { signerId, receiverId, actions }); - const { contract } = store.getState(); + const { contracts } = store.getState(); const accounts = getAccounts(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } diff --git a/packages/xdefi/src/lib/xdefi.ts b/packages/xdefi/src/lib/xdefi.ts index 4a3b711e8..470209316 100644 --- a/packages/xdefi/src/lib/xdefi.ts +++ b/packages/xdefi/src/lib/xdefi.ts @@ -62,19 +62,19 @@ const XDEFI: WalletBehaviourFactory = async ({ }; const transformTransactions = ( - transactions: Array> + transactions: Array> ): Array => { const accounts = getAccounts(); - const { contract } = store.getState(); + const { contracts } = store.getState(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); } return transactions.map((transaction) => { return { signerId: transaction.signerId || accounts[0].accountId, - receiverId: transaction.receiverId || contract.contractId, + receiverId: transaction.receiverId, actions: transaction.actions, }; }); @@ -119,10 +119,10 @@ const XDEFI: WalletBehaviourFactory = async ({ async signAndSendTransaction(transaction: Transaction) { logger.log("signAndSendTransaction", transaction); - const { contract } = store.getState(); + const { contracts } = store.getState(); const accounts = getAccounts(); - if (!accounts.length || !contract) { + if (!accounts.length || contracts.length < 1) { throw new Error("Wallet not signed in"); }