Skip to content

Commit

Permalink
Added verify owner method, copied code from PR #320
Browse files Browse the repository at this point in the history
  • Loading branch information
kujtimprenkuSQA committed Aug 11, 2022
1 parent 4245a8e commit 97dd9d6
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div>
<button (click)="signOut()">Log out</button>
<button (click)="switchWallet()">Switch Wallet</button>
<button (click)="onVerifyOwner()">Verify Owner</button>
<button *ngIf="accounts.length > 1" (click)="switchAccount()">
Switch Account
</button>
Expand Down
15 changes: 15 additions & 0 deletions examples/angular/src/app/components/content/content.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,21 @@ export class ContentComponent implements OnInit, OnDestroy {
alert("Switched account to " + nextAccountId);
}

async onVerifyOwner() {
const wallet = await this.selector.wallet();
try {
const signature = await wallet.verifyOwner();

if (signature) {
alert(`Signature for verification: ${signature.signature.toString()}`);
}
} catch (err) {
const message =
err instanceof Error ? err.message : "Something went wrong";
alert(message);
}
}

subscribeToEvents() {
this.subscription = this.selector.store.observable
.pipe(
Expand Down
16 changes: 16 additions & 0 deletions examples/react/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,21 @@ const Content: React.FC = () => {
[selector, accountId]
);

const handleVerifyOwner = async () => {
const wallet = await selector.wallet();
try {
const signature = await wallet.verifyOwner();

if (signature) {
alert(`Signature for verification: ${signature.signature.toString()}`);
}
} catch (err) {
const message =
err instanceof Error ? err.message : "Something went wrong";
alert(message);
}
};

const handleSubmit = useCallback(
async (e: SubmitEvent) => {
e.preventDefault();
Expand Down Expand Up @@ -220,6 +235,7 @@ const Content: React.FC = () => {
<div>
<button onClick={handleSignOut}>Log out</button>
<button onClick={handleSwitchWallet}>Switch Wallet</button>
<button onClick={handleVerifyOwner}>Verify Owner</button>
{accounts.length > 1 && (
<button onClick={handleSwitchAccount}>Switch Account</button>
)}
Expand Down
31 changes: 31 additions & 0 deletions packages/core/docs/api/wallet.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,37 @@ Returns one or more accounts when signed in. This method can be useful for walle
})();
```

### `.verifyOwner(params)`

**Parameters**
- `params` (`object`)
- `message` (`string?`): The message requested sign. Defaults to `verify owner` string.
- `signerId` (`string?`): Account ID used to sign the message. Defaults to the first account.
- `publicKey` (`PublicKey?`): Public key used to sign the message. Defaults to the public key of the signed in account.
- `callbackUrl` (`string?`): Applicable to browser wallets (e.g. MyNearWallet). This is the callback url once the signing is approved. Defaults to `window.location.href`.
- `meta` (`string?`): Applicable to browser wallets (e.g. MyNearWallet) extra data that will be passed to the callback url once the signing is approved.

**Returns**
- `Promise<void | utils.key_pair.Signature>`: Browser wallets won't return the signing outcome as they may need to redirect for signing. For MyNearWallet the outcome is passed to the callback url.

**Description**

Signs the message and verifies the owner. Message is not sent to blockchain.

> Note: This feature is currently supported only by MyNearWallet on **testnet**. Sender can sign messages when unlocked.
**Example**

```ts
// MyNearWallet
(async () => {
const wallet = await selector.wallet("my-near-wallet");
await wallet.verifyOwner({
message: "Test message",
});
})();
```


### `.signAndSendTransaction(params)`

**Parameters**
Expand Down
14 changes: 13 additions & 1 deletion packages/core/src/lib/wallet/wallet.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { providers } from "near-api-js";
import { providers, utils } from "near-api-js";

import {
EventEmitterService,
Expand All @@ -10,6 +10,7 @@ import type { Options } from "../options.types";
import type { ReadOnlyStore } from "../store.types";
import type { Transaction, Action } from "./transactions.types";
import type { Modify, Optional } from "../utils.types";
import { PublicKey } from "near-api-js/lib/utils";
import type { FinalExecutionOutcome } from "near-api-js/lib/providers";

interface BaseWalletMetadata {
Expand All @@ -29,6 +30,14 @@ export interface SignInParams {
methodNames?: Array<string>;
}

export interface VerifyOwnerParams {
message?: string;
signerId?: string;
publicKey?: PublicKey;
callbackUrl?: string;
meta?: string;
}

export interface SignAndSendTransactionParams {
signerId?: string;
receiverId?: string;
Expand All @@ -43,6 +52,9 @@ interface BaseWalletBehaviour {
signIn(params: SignInParams): Promise<Array<Account>>;
signOut(): Promise<void>;
getAccounts(): Promise<Array<Account>>;
verifyOwner(
params?: VerifyOwnerParams
): Promise<utils.key_pair.Signature | void>;
signAndSendTransaction(
params: SignAndSendTransactionParams
): Promise<providers.FinalExecutionOutcome>;
Expand Down
36 changes: 36 additions & 0 deletions packages/ledger/src/lib/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const Ledger: WalletBehaviourFactory<HardwareWallet> = async ({
provider,
logger,
storage,
metadata,
}) => {
const _state = await setupLedgerState(storage);

Expand Down Expand Up @@ -219,6 +220,41 @@ const Ledger: WalletBehaviourFactory<HardwareWallet> = async ({
return getAccounts();
},

async verifyOwner({ message = "verify owner", signerId, publicKey } = {}) {
logger.log("Ledger:verifyOwner", { message, signerId, publicKey });

const account = getActiveAccount(store.getState());

if (!account) {
throw new Error("No active account");
}

// Note: Connection must be triggered by user interaction.
await connectLedgerDevice();

const networkId = options.network.networkId;
const accountId = signerId || account.accountId;
const pubKey =
publicKey || (await signer.getPublicKey(accountId, networkId));
const block = await provider.block({ finality: "final" });

const msg = JSON.stringify({
accountId,
message,
blockId: block.header.hash,
publicKey: Buffer.from(pubKey.data).toString("base64"),
keyType: pubKey.keyType,
});

throw new Error(`Method not supported by ${metadata.name}`);

return signer.signMessage(
new Uint8Array(Buffer.from(msg)),
accountId,
networkId
);
},

async signAndSendTransaction({ signerId, receiverId, actions }) {
logger.log("signAndSendTransaction", { signerId, receiverId, actions });

Expand Down
33 changes: 33 additions & 0 deletions packages/math-wallet/src/lib/math-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const setupMathWalletState = (): MathWalletState => {
};

const MathWallet: WalletBehaviourFactory<InjectedWallet> = async ({
metadata,
options,
store,
provider,
Expand Down Expand Up @@ -104,6 +105,38 @@ const MathWallet: WalletBehaviourFactory<InjectedWallet> = async ({
return getAccounts();
},

async verifyOwner({ message = "verify owner", signerId, publicKey } = {}) {
logger.log("MathWallet:verifyOwner", { message, signerId, publicKey });

const account = getActiveAccount(store.getState());

if (!account) {
throw new Error("No active account");
}

const accountId = signerId || account.accountId;
const pubKey =
publicKey || (await _state.wallet.signer.getPublicKey(accountId));
const block = await provider.block({ finality: "final" });

const msg = JSON.stringify({
accountId,
message,
blockId: block.header.hash,
publicKey: Buffer.from(pubKey.data).toString("base64"),
keyType: pubKey.keyType,
});

// Note: Math Wallet currently hangs when calling signMessage.
throw new Error(`Method not supported by ${metadata.name}`);

return _state.wallet.signer.signMessage(
new Uint8Array(Buffer.from(msg)),
accountId,
options.network.networkId
);
},

async signAndSendTransaction({ signerId, receiverId, actions }) {
logger.log("signAndSendTransaction", { signerId, receiverId, actions });
const signedTransactions = await signTransactions(
Expand Down
8 changes: 7 additions & 1 deletion packages/meteor-wallet/src/lib/meteor-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const setupWalletState = async (
const createMeteorWalletInjected: WalletBehaviourFactory<
InjectedWallet,
{ params: MeteorWalletParams_Injected }
> = async ({ options, logger, store, params }) => {
> = async ({ metadata, options, logger, store, params }) => {
const _state = await setupWalletState(params, options.network);

const cleanup = () => {
Expand Down Expand Up @@ -155,6 +155,12 @@ const createMeteorWalletInjected: WalletBehaviourFactory<
return getAccounts();
},

async verifyOwner({ message = "verify owner", signerId, publicKey } = {}) {
logger.log("MeteorWallet:verifyOwner", { message, signerId, publicKey });

throw new Error(`Method not supported by ${metadata.name}`);
},

async signAndSendTransaction({ signerId, receiverId, actions }) {
logger.log("MeteorWallet:signAndSendTransaction", {
signerId,
Expand Down
35 changes: 34 additions & 1 deletion packages/my-near-wallet/src/lib/my-near-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const setupWalletState = async (
const MyNearWallet: WalletBehaviourFactory<
BrowserWallet,
{ params: MyNearWalletExtraOptions }
> = async ({ options, store, params, logger }) => {
> = async ({ metadata, options, store, params, logger }) => {
const _state = await setupWalletState(params, options.network);

const cleanup = () => {
Expand Down Expand Up @@ -155,6 +155,39 @@ const MyNearWallet: WalletBehaviourFactory<
return getAccounts();
},

async verifyOwner({
message = "verify owner",
signerId,
publicKey,
callbackUrl,
meta,
} = {}) {
logger.log("verifyOwner", { message, signerId, publicKey });

const account = _state.wallet.account();

if (!account) {
throw new Error("Wallet not signed in");
}
const locationUrl =
typeof window !== "undefined" ? window.location.href : "";

const url = callbackUrl || locationUrl;

if (!url) {
throw new Error(`The callbackUrl is missing for ${metadata.name}`);
}

const encodedUrl = encodeURIComponent(url);
const extraMeta = meta ? `&meta=${meta}` : "";

window.location.replace(
`${params.walletUrl}/verify-owner?message=${message}&callbackUrl=${encodedUrl}${extraMeta}`
);

return;
},

async signAndSendTransaction({
signerId,
receiverId,
Expand Down
12 changes: 11 additions & 1 deletion packages/nightly-connect/src/lib/nightly-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const setupNightlyConnectState = (): NightlyConnectState => {
const NightlyConnect: WalletBehaviourFactory<
BridgeWallet,
{ params: NightlyConnectParams }
> = async ({ store, params, logger, options, provider, emitter }) => {
> = async ({ metadata, store, params, logger, options, provider, emitter }) => {
const _state = setupNightlyConnectState();

const getAccounts = () => {
Expand Down Expand Up @@ -156,6 +156,16 @@ const NightlyConnect: WalletBehaviourFactory<
return getAccounts().map(({ accountId }) => ({ accountId }));
},

async verifyOwner({ message = "verify owner", signerId, publicKey } = {}) {
logger.log("NightlyConnect:verifyOwner", {
message,
signerId,
publicKey,
});

throw new Error(`Method not supported by ${metadata.name}`);
},

async signAndSendTransaction({ signerId, receiverId, actions }) {
logger.log("signAndSendTransaction", { signerId, receiverId, actions });

Expand Down
7 changes: 7 additions & 0 deletions packages/nightly/src/lib/nightly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const isInstalled = () => {
return waitFor(() => !!window.nightly!.near!).catch(() => false);
};
const Nightly: WalletBehaviourFactory<InjectedWallet> = async ({
metadata,
options,
store,
logger,
Expand Down Expand Up @@ -141,6 +142,12 @@ const Nightly: WalletBehaviourFactory<InjectedWallet> = async ({
return getAccounts().map(({ accountId }) => ({ accountId }));
},

async verifyOwner({ message = "verify owner", signerId, publicKey } = {}) {
logger.log("Nightly:verifyOwner", { message, signerId, publicKey });

throw new Error(`Method not supported by ${metadata.name}`);
},

async signAndSendTransaction({ signerId, receiverId, actions }) {
logger.log("signAndSendTransaction", { signerId, receiverId, actions });

Expand Down
3 changes: 2 additions & 1 deletion packages/sender/src/lib/injected-sender.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Interfaces based on "documentation": https://github.com/SenderWallet/sender-wallet-integration-tutorial

// Empty string if we haven't signed in before.
import { providers } from "near-api-js";
import { Account, providers } from "near-api-js";

interface AccessKey {
publicKey: {
Expand Down Expand Up @@ -114,6 +114,7 @@ export interface InjectedSender {
callbacks: Record<keyof SenderEvents, unknown>;
getAccountId: () => string | null;
getRpc: () => Promise<GetRpcResponse>;
account(): Account | null;
requestSignIn: (
params: RequestSignInParams
) => Promise<RequestSignInResponse>;
Expand Down
Loading

0 comments on commit 97dd9d6

Please sign in to comment.