浏览代码

add signMessage verification to example and FAQ

Jordan Sexton 4 年之前
父节点
当前提交
cccb421236
共有 4 个文件被更改,包括 55 次插入13 次删除
  1. 41 0
      FAQ.md
  2. 1 0
      packages/starter/example/package.json
  3. 12 12
      packages/starter/example/src/SignMessage.tsx
  4. 1 1
      yarn.lock

+ 41 - 0
FAQ.md

@@ -74,3 +74,44 @@ Go to https://developer.tor.us to sign up for your own unique client ID. Then us
         // ...
     ], [network]);
 ```
+
+## How can I sign and verify messages?
+
+Some wallet adapters like Phantom provide a `signMessage` method for signing arbitrary bytes.
+
+The signature string returned by this method can be verified using [tweetnacl-js](https://github.com/dchest/tweetnacl-js/blob/master/README.md#naclsigndetachedverifymessage-signature-publickey) using the public key from the adapter.
+
+This can be used to sign offline -- without sending a transaction -- and prove a user controls a given private key.
+
+```tsx
+import { useWallet } from '@solana/wallet-adapter-react';
+import bs58 from 'bs58';
+import React, { FC, useCallback } from 'react';
+import { sign } from 'tweetnacl';
+
+export const SignMessageButton: FC = () => {
+    const { publicKey, signMessage } = useWallet();
+
+    const onClick = useCallback(async () => {
+        try {
+            // `publicKey` will be null if the wallet isn't connected
+            if (!publicKey) throw new Error('Wallet not connected!');
+            // `signMessage` will be undefined if the wallet doesn't support it
+            if (!signMessage) throw new Error('Wallet does not support message signing!');
+
+            // Encode anything as bytes
+            const message = new TextEncoder().encode('Hello, world!');
+            // Sign the bytes using the wallet
+            const signature = await signMessage(message);
+            // Verify that the bytes were signed using the private key that matches the known public key
+            if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
+
+            alert(`Message signature: ${bs58.encode(signature)}`);
+        } catch (error: any) {
+            alert(`Signing failed: ${error?.message}`);
+        }
+    }, [publicKey, signMessage]);
+
+    return signMessage ? (<button onClick={onClick} disabled={!publicKey}>Sign Message</button>) : null;
+};
+```

+ 1 - 0
packages/starter/example/package.json

@@ -49,6 +49,7 @@
         "react": "^17.0.2",
         "react-dom": "^17.0.2",
         "react-scripts": "^4.0.3",
+        "tweetnacl": "^1.0.3",
         "typescript": "^4.4.3",
         "web-vitals": "^1.0.1",
         "yarn": "^1.22.11"

+ 12 - 12
packages/starter/example/src/SignMessage.tsx

@@ -3,29 +3,29 @@ import { useWallet } from '@solana/wallet-adapter-react';
 import bs58 from 'bs58';
 import React, { FC, useCallback } from 'react';
 import { useNotify } from './notify';
+import { sign } from 'tweetnacl';
 
 const SignMessage: FC = () => {
     const { publicKey, signMessage } = useWallet();
     const notify = useNotify();
 
     const onClick = useCallback(async () => {
-        if (!publicKey) {
-            notify('error', 'Wallet not connected!');
-            return;
-        }
-        if (!signMessage) {
-            notify('error', 'Wallet does not support message signing!');
-            return;
-        }
-
         try {
-            const message = new TextEncoder().encode('Hello, world!');
+            // `publicKey` will be null if the wallet isn't connected
+            if (!publicKey) throw new Error('Wallet not connected!');
+            // `signMessage` will be undefined if the wallet doesn't support it
+            if (!signMessage) throw new Error('Wallet does not support message signing!');
 
+            // Encode anything as bytes
+            const message = new TextEncoder().encode('Hello, world!');
+            // Sign the bytes using the wallet
             const signature = await signMessage(message);
+            // Verify that the bytes were signed using the private key that matches the known public key
+            if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
+
             notify('success', `Message signature: ${bs58.encode(signature)}`);
         } catch (error: any) {
-            notify('error', `Signing failed! ${error?.message}`);
-            return;
+            notify('error', `Signing failed: ${error?.message}`);
         }
     }, [publicKey, notify, signMessage]);
 

+ 1 - 1
yarn.lock

@@ -17283,7 +17283,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
   resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
   integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
 
-tweetnacl@^1.0.0:
+tweetnacl@^1.0.0, tweetnacl@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
   integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==