From cd811a6a51cab1841527ec656680adade41caac5 Mon Sep 17 00:00:00 2001 From: kujtimprenkuSQA <95851345+kujtimprenkuSQA@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:38:26 +0200 Subject: [PATCH] feat: add near_signMessage method to NEAR (#310) Co-authored-by: Ben Kremer --- .gitignore | 3 + wallets/react-wallet-v2/package.json | 1 + wallets/react-wallet-v2/src/data/NEARData.ts | 3 +- .../hooks/useWalletConnectEventsManager.ts | 1 + wallets/react-wallet-v2/src/lib/NearLib.ts | 84 +++++++++++++++++++ .../src/utils/NearRequestHandlerUtil.ts | 18 ++++ wallets/react-wallet-v2/yarn.lock | 5 ++ 7 files changed, 114 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f0e9a19..f69a9de 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ yarn-error.log* # vercel .vercel + +# webstorm ide +.idea diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index e9cea80..4ca55ca 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -31,6 +31,7 @@ "@taquito/signer": "^15.1.0", "@taquito/taquito": "^15.1.0", "@walletconnect/web3wallet": "1.9.1", + "borsh": "^1.0.0", "bs58": "5.0.0", "cosmos-wallet": "1.2.0", "ethers": "5.7.2", diff --git a/wallets/react-wallet-v2/src/data/NEARData.ts b/wallets/react-wallet-v2/src/data/NEARData.ts index bb8ce67..83008f6 100644 --- a/wallets/react-wallet-v2/src/data/NEARData.ts +++ b/wallets/react-wallet-v2/src/data/NEARData.ts @@ -52,5 +52,6 @@ export const NEAR_SIGNING_METHODS = { NEAR_SIGN_AND_SEND_TRANSACTION: 'near_signAndSendTransaction', NEAR_SIGN_TRANSACTIONS: 'near_signTransactions', NEAR_SIGN_AND_SEND_TRANSACTIONS: 'near_signAndSendTransactions', - NEAR_VERIFY_OWNER: 'near_verifyOwner' + NEAR_VERIFY_OWNER: 'near_verifyOwner', + NEAR_SIGN_MESSAGE: 'near_signMessage' } diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index 36b6649..c0c7629 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -79,6 +79,7 @@ export default function useWalletConnectEventsManager(initialized: boolean) { case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTIONS: case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS: case NEAR_SIGNING_METHODS.NEAR_VERIFY_OWNER: + case NEAR_SIGNING_METHODS.NEAR_SIGN_MESSAGE: return ModalStore.open('SessionSignNearModal', { requestEvent, requestSession }) case MULTIVERSX_SIGNING_METHODS.MULTIVERSX_SIGN_MESSAGE: diff --git a/wallets/react-wallet-v2/src/lib/NearLib.ts b/wallets/react-wallet-v2/src/lib/NearLib.ts index 22ddc01..897a983 100644 --- a/wallets/react-wallet-v2/src/lib/NearLib.ts +++ b/wallets/react-wallet-v2/src/lib/NearLib.ts @@ -9,6 +9,7 @@ import { AccessKeyView } from 'near-api-js/lib/providers/provider' import { web3wallet } from '@/utils/WalletConnectUtil' import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData' +import { Schema, serialize } from 'borsh' const MAX_ACCOUNTS = 2 @@ -63,6 +64,58 @@ interface SignAndSendTransactionsParams { transactions: Array } +export interface SignMessageParamsNEP { + message: string + recipient: string + nonce: Buffer + callbackUrl?: string + state?: string +} + +interface SignMessageParams { + chainId: string + messageParams: SignMessageParamsNEP & { + accountId?: string + } +} + +interface SignedMessage { + accountId: string + publicKey: string + signature: string + state?: string +} + +export class MessagePayload { + tag: number + message: string + nonce: Buffer + recipient: string + callbackUrl?: string + + constructor(data: SignMessageParamsNEP) { + // The tag's value is a hardcoded value as per + // defined in the NEP [NEP413](https://github.com/near/NEPs/blob/master/neps/nep-0413.md) + this.tag = 2147484061 + this.message = data.message + this.nonce = data.nonce + this.recipient = data.recipient + if (data.callbackUrl) { + this.callbackUrl = data.callbackUrl + } + } +} + +export const payloadSchema: Schema = { + struct: { + tag: 'u32', + message: 'string', + nonce: { array: { type: 'u8', len: 32 } }, + recipient: 'string', + callbackUrl: { option: 'string' } + } +} + export class NearWallet { private networkId: string private keyStore: nearKeyStores.KeyStore @@ -342,4 +395,35 @@ export class NearWallet { return results } + + async signMessage({ chainId, messageParams }: SignMessageParams): Promise { + const { message, nonce, recipient, callbackUrl, state, accountId } = messageParams + const nonceArray = Buffer.from(nonce) + + if (nonceArray.length !== 32) { + throw Error('Expected nonce to be a 32 bytes buffer') + } + + const accounts = await this.getAllAccounts() + const account = accounts.find(acc => acc.accountId === accountId) + + // If no accountId is provided in params default to the first accountId in accounts. + // in a real wallet it would default to the `active/selected` account + // this is because we should be able to use `signMessage` without `signIn`. + const accId = account ? account.accountId : accounts[0].accountId + + const signer = new InMemorySigner(this.getKeyStore()) + const networkId = chainId.split(':')[1] + + // Create the message payload and sign it + const payload = new MessagePayload({ message, nonce: nonceArray, recipient, callbackUrl }) + const encodedPayload = serialize(payloadSchema, payload) + const signed = await signer.signMessage(encodedPayload, accId, networkId) + + return { + accountId: accId, + publicKey: signed.publicKey.toString(), + signature: Buffer.from(signed.signature).toString('base64') + } + } } diff --git a/wallets/react-wallet-v2/src/utils/NearRequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/NearRequestHandlerUtil.ts index c6a19a5..4e7ba31 100644 --- a/wallets/react-wallet-v2/src/utils/NearRequestHandlerUtil.ts +++ b/wallets/react-wallet-v2/src/utils/NearRequestHandlerUtil.ts @@ -162,6 +162,24 @@ export async function approveNearRequest( keyType: signed.publicKey.keyType }) } + case NEAR_SIGNING_METHODS.NEAR_SIGN_MESSAGE: { + console.log('approve', { id, params }) + + if (!chainId) { + throw new Error('Invalid chain id') + } + + const { accountId, publicKey, signature } = await nearWallet.signMessage({ + chainId, + messageParams: params.request.params + }) + + return formatJsonRpcResult(id, { + accountId, + publicKey, + signature + }) + } case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS: { console.log('approve', { id, params }) diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 0c0175e..cef2f28 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -3189,6 +3189,11 @@ borsh@^0.7.0: bs58 "^4.0.0" text-encoding-utf-8 "^1.0.2" +borsh@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-1.0.0.tgz#b564c8cc8f7a91e3772b9aef9e07f62b84213c1f" + integrity sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"