Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jordaaash committed Jun 22, 2023
1 parent ed952f1 commit b1b7e57
Show file tree
Hide file tree
Showing 17 changed files with 226 additions and 33 deletions.
60 changes: 60 additions & 0 deletions .changeset/clean-bobcats-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
'@solana/wallet-adapter-create-react-app-starter': patch
'@solana/wallet-adapter-material-ui-starter': patch
'@solana/wallet-adapter-react-ui-starter': patch
'@solana/wallet-adapter-nextjs-starter': patch
'@solana/wallet-adapter-unsafe-burner': patch
'@solana/wallet-adapter-walletconnect': patch
'@solana/wallet-adapter-tokenpocket': patch
'@solana/wallet-adapter-mathwallet': patch
'@solana/wallet-adapter-magiceden': patch
'@solana/wallet-adapter-backpack': patch
'@solana/wallet-adapter-coinbase': patch
'@solana/wallet-adapter-hyperpay': patch
'@solana/wallet-adapter-keystone': patch
'@solana/wallet-adapter-particle': patch
'@solana/wallet-adapter-solflare': patch
'@solana/wallet-adapter-tokenary': patch
'@solana/wallet-adapter-example': patch
'@solana/wallet-adapter-bitkeep': patch
'@solana/wallet-adapter-coinhub': patch
'@solana/wallet-adapter-fractal': patch
'@solana/wallet-adapter-krystal': patch
'@solana/wallet-adapter-nightly': patch
'@solana/wallet-adapter-phantom': patch
'@solana/wallet-adapter-safepal': patch
'@solana/wallet-adapter-wallets': patch
'@solana/wallet-adapter-material-ui': patch
'@solana/wallet-adapter-bitpie': patch
'@solana/wallet-adapter-blocto': patch
'@solana/wallet-adapter-clover': patch
'@solana/wallet-adapter-coin98': patch
'@solana/wallet-adapter-exodus': patch
'@solana/wallet-adapter-ledger': patch
'@solana/wallet-adapter-salmon': patch
'@solana/wallet-adapter-sollet': patch
'@solana/wallet-adapter-solong': patch
'@solana/wallet-adapter-strike': patch
'@solana/wallet-adapter-ant-design': patch
'@solana/wallet-adapter-alpha': patch
'@solana/wallet-adapter-avana': patch
'@solana/wallet-adapter-brave': patch
'@solana/wallet-adapter-censo': patch
'@solana/wallet-adapter-huobi': patch
'@solana/wallet-adapter-saifu': patch
'@solana/wallet-adapter-slope': patch
'@solana/wallet-adapter-torus': patch
'@solana/wallet-adapter-trust': patch
'@solana/wallet-adapter-xdefi': patch
'@solana/wallet-adapter-glow': patch
'@solana/wallet-adapter-neko': patch
'@solana/wallet-adapter-nufi': patch
'@solana/wallet-adapter-onto': patch
'@solana/wallet-adapter-spot': patch
'@solana/wallet-adapter-react-ui': patch
'@solana/wallet-adapter-sky': patch
'@solana/wallet-adapter-react': patch
'@solana/wallet-adapter-base': patch
---

Add support for Sign In With Solana
1 change: 1 addition & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export const SignMessageButton: FC = () => {
const message = new TextEncoder().encode('Hello, world!');
// Sign the bytes using the wallet
const signature = await signMessage(message);
// FIXME: replace with `verifySignMessage`
// Verify that the bytes were signed using the private key that matches the known public key
if (!ed25519.verify(signature, message, publicKey.toBytes())) throw new Error('Invalid signature!');

Expand Down
2 changes: 1 addition & 1 deletion packages/core/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@solana/web3.js": "^1.77.3"
},
"dependencies": {
"@solana/wallet-standard-features": "^1.0.1",
"@solana/wallet-standard-features": "1.1.0-alpha.4",
"@wallet-standard/base": "^1.0.1",
"@wallet-standard/features": "^1.0.3",
"eventemitter3": "^4.0.7"
Expand Down
15 changes: 15 additions & 0 deletions packages/core/base/src/signer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { SolanaSignInInput, SolanaSignInOutput } from '@solana/wallet-standard-features';
import type { Connection, TransactionSignature } from '@solana/web3.js';
import {
BaseWalletAdapter,
Expand Down Expand Up @@ -127,3 +128,17 @@ export abstract class BaseMessageSignerWalletAdapter<Name extends string = strin
{
abstract signMessage(message: Uint8Array): Promise<Uint8Array>;
}

export interface SignInMessageSignerWalletAdapterProps<Name extends string = string> extends WalletAdapterProps<Name> {
signIn(input?: SolanaSignInInput): Promise<SolanaSignInOutput>;
}

export type SignInMessageSignerWalletAdapter<Name extends string = string> = WalletAdapter<Name> &
SignInMessageSignerWalletAdapterProps<Name>;

export abstract class BaseSignInMessageSignerWalletAdapter<Name extends string = string>
extends BaseMessageSignerWalletAdapter<Name>
implements SignInMessageSignerWalletAdapter<Name>
{
abstract signIn(input?: SolanaSignInInput): Promise<SolanaSignInOutput>;
}
3 changes: 2 additions & 1 deletion packages/core/base/src/standard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
SolanaSignAndSendTransaction,
type SolanaSignAndSendTransactionFeature,
type SolanaSignInFeature,
type SolanaSignMessageFeature,
SolanaSignTransaction,
type SolanaSignTransactionFeature,
Expand All @@ -19,7 +20,7 @@ export type WalletAdapterCompatibleStandardWallet = StandardWalletWithFeatures<
StandardConnectFeature &
StandardEventsFeature &
(SolanaSignAndSendTransactionFeature | SolanaSignTransactionFeature) &
(StandardDisconnectFeature | SolanaSignMessageFeature | object)
(StandardDisconnectFeature | SolanaSignMessageFeature | SolanaSignInFeature | object)
>;

export interface StandardWalletAdapterProps<Name extends string = string> extends WalletAdapterProps<Name> {
Expand Down
9 changes: 7 additions & 2 deletions packages/core/base/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { WalletAdapter } from './adapter.js';
import type { MessageSignerWalletAdapter, SignerWalletAdapter } from './signer.js';
import type { MessageSignerWalletAdapter, SignerWalletAdapter, SignInMessageSignerWalletAdapter } from './signer.js';
import type { StandardWalletAdapter } from './standard.js';

export type Adapter = WalletAdapter | SignerWalletAdapter | MessageSignerWalletAdapter | StandardWalletAdapter;
export type Adapter =
| WalletAdapter
| SignerWalletAdapter
| MessageSignerWalletAdapter
| SignInMessageSignerWalletAdapter
| StandardWalletAdapter;

export enum WalletAdapterNetwork {
Mainnet = 'mainnet-beta',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"dependencies": {
"@solana-mobile/wallet-adapter-mobile": "^2.0.0",
"@solana/wallet-adapter-base": "workspace:^",
"@solana/wallet-standard-wallet-adapter-react": "^1.0.2"
"@solana/wallet-standard-wallet-adapter-react": "1.0.3-alpha.4"
},
"devDependencies": {
"@solana/web3.js": "^1.77.3",
Expand Down
3 changes: 3 additions & 0 deletions packages/core/react/src/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface WalletProviderProps {
children: ReactNode;
wallets: Adapter[];
autoConnect?: boolean;
autoSignIn?: boolean;
localStorageKey?: string;
onError?: (error: WalletError, adapter?: Adapter) => void;
}
Expand Down Expand Up @@ -47,6 +48,8 @@ export function WalletProvider({
children,
wallets: adapters,
autoConnect,
// FIXME: implement
autoSignIn,
localStorageKey = 'walletName',
onError,
}: WalletProviderProps) {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/react/src/WalletProviderBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type Adapter,
type MessageSignerWalletAdapterProps,
type SignerWalletAdapterProps,
type SignInMessageSignerWalletAdapterProps,
type WalletAdapterProps,
type WalletError,
type WalletName,
Expand Down Expand Up @@ -239,6 +240,17 @@ export function WalletProviderBase({
[adapter, connected]
);

// Sign in if the wallet supports it
const signIn: SignInMessageSignerWalletAdapterProps['signIn'] | undefined = useMemo(
() =>
adapter && 'signIn' in adapter
? async (input) => {
return await adapter.signIn(input);
}
: undefined,
[adapter]
);

const handleConnect = useCallback(async () => {
if (isConnectingRef.current || isDisconnectingRef.current || wallet?.adapter.connected) return;
if (!wallet) throw handleErrorRef.current(new WalletNotSelectedError());
Expand Down Expand Up @@ -288,6 +300,7 @@ export function WalletProviderBase({
signTransaction,
signAllTransactions,
signMessage,
signIn,
}}
>
{children}
Expand Down
5 changes: 5 additions & 0 deletions packages/core/react/src/useWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type Adapter,
type MessageSignerWalletAdapterProps,
type SignerWalletAdapterProps,
type SignInMessageSignerWalletAdapterProps,
type WalletAdapterProps,
type WalletName,
type WalletReadyState,
Expand Down Expand Up @@ -31,6 +32,7 @@ export interface WalletContextState {
signTransaction: SignerWalletAdapterProps['signTransaction'] | undefined;
signAllTransactions: SignerWalletAdapterProps['signAllTransactions'] | undefined;
signMessage: MessageSignerWalletAdapterProps['signMessage'] | undefined;
signIn: SignInMessageSignerWalletAdapterProps['signIn'] | undefined;
}

const EMPTY_ARRAY: ReadonlyArray<never> = [];
Expand Down Expand Up @@ -61,6 +63,9 @@ const DEFAULT_CONTEXT: Partial<WalletContextState> = {
signMessage() {
return Promise.reject(logMissingProviderError('call', 'signMessage'));
},
signIn() {
return Promise.reject(logMissingProviderError('call', 'signIn'));
},
};
Object.defineProperty(DEFAULT_CONTEXT, 'wallets', {
get() {
Expand Down
2 changes: 1 addition & 1 deletion packages/starter/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.5",
"@noble/curves": "^1.1.0",
"@solana/wallet-adapter-ant-design": "workspace:^",
"@solana/wallet-adapter-base": "workspace:^",
"@solana/wallet-adapter-material-ui": "workspace:^",
"@solana/wallet-adapter-react": "workspace:^",
"@solana/wallet-adapter-react-ui": "workspace:^",
"@solana/wallet-adapter-wallets": "workspace:^",
"@solana/wallet-standard-util": "1.1.0-alpha.7",
"@solana/web3.js": "^1.77.3",
"antd": "^4.24.10",
"bs58": "^4.0.1",
Expand Down
32 changes: 32 additions & 0 deletions packages/starter/example/src/components/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Button } from '@mui/material';
import { useWallet } from '@solana/wallet-adapter-react';
import { verifySignIn } from '@solana/wallet-standard-util';
import type { FC } from 'react';
import React, { useCallback } from 'react';
import { useNotify } from './notify';

export const SignIn: FC = () => {
const { signIn } = useWallet();
const notify = useNotify();

const onClick = useCallback(async () => {
try {
if (!signIn) throw new Error('Wallet does not support message signing!');

// FIXME: wrap this for wallet adapter to simplify args
const input = {};
const output = await signIn(input);
if (!verifySignIn(input, output)) throw new Error('Sign in signature invalid!');

notify('success', `Signed in: ${output.account.address}`);
} catch (error: any) {
notify('error', `Sign In failed: ${error?.message}`);
}
}, [signIn, notify]);

return (
<Button variant="contained" color="secondary" onClick={onClick} disabled={!signIn}>
Sign In
</Button>
);
};
22 changes: 20 additions & 2 deletions packages/starter/example/src/components/SignMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button } from '@mui/material';
import { ed25519 } from '@noble/curves/ed25519';
import { useWallet } from '@solana/wallet-adapter-react';
import { verifySignMessage } from '@solana/wallet-standard-util';
import bs58 from 'bs58';
import type { FC } from 'react';
import React, { useCallback } from 'react';
Expand All @@ -17,7 +17,25 @@ export const SignMessage: FC = () => {

const message = new TextEncoder().encode('Hello, world!');
const signature = await signMessage(message);
if (!ed25519.verify(signature, message, publicKey.toBytes())) throw new Error('Message signature invalid!');
if (
// FIXME: wrap this for wallet adapter to simplify args
!verifySignMessage(
{
account: {
address: publicKey.toBase58(),
publicKey: publicKey.toBytes(),
chains: [],
features: [],
},
message,
},
{
signedMessage: message,
signature,
}
)
)
throw new Error('Message signature invalid!');

notify('success', `Message signature: ${bs58.encode(signature)}`);
} catch (error: any) {
Expand Down
5 changes: 4 additions & 1 deletion packages/starter/example/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const SendV0TransactionDynamic = dynamic(
async () => (await import('../components/SendV0Transaction')).SendV0Transaction,
{ ssr: false }
);
const SignInDynamic = dynamic(async () => (await import('../components/SignIn')).SignIn, { ssr: false });
const SignMessageDynamic = dynamic(async () => (await import('../components/SignMessage')).SignMessage, { ssr: false });
const SignTransactionDynamic = dynamic(async () => (await import('../components/SignTransaction')).SignTransaction, {
ssr: false,
Expand Down Expand Up @@ -183,7 +184,9 @@ const Index: NextPage = () => {
<TableCell>
<SignMessageDynamic />
</TableCell>
<TableCell></TableCell>
<TableCell>
<SignInDynamic />
</TableCell>
</TableRow>
<TableRow>
<TableCell></TableCell>
Expand Down
4 changes: 3 additions & 1 deletion packages/wallets/unsafe-burner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
},
"dependencies": {
"@noble/curves": "^1.1.0",
"@solana/wallet-adapter-base": "workspace:^"
"@solana/wallet-adapter-base": "workspace:^",
"@solana/wallet-standard-features": "1.1.0-alpha.4",
"@solana/wallet-standard-util": "1.1.0-alpha.7"
},
"devDependencies": {
"@solana/web3.js": "^1.77.3",
Expand Down
32 changes: 30 additions & 2 deletions packages/wallets/unsafe-burner/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { ed25519 } from '@noble/curves/ed25519';
import type { WalletName } from '@solana/wallet-adapter-base';
import {
BaseMessageSignerWalletAdapter,
BaseSignInMessageSignerWalletAdapter,
isVersionedTransaction,
WalletNotConnectedError,
WalletReadyState,
} from '@solana/wallet-adapter-base';
import { type SolanaSignInInput, type SolanaSignInOutput } from '@solana/wallet-standard-features';
import { createSignInMessage } from '@solana/wallet-standard-util';
import type { Transaction, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
import { Keypair } from '@solana/web3.js';

Expand All @@ -15,7 +17,7 @@ export const UnsafeBurnerWalletName = 'Burner Wallet' as WalletName<'Burner Wall
* This burner wallet adapter is unsafe to use and is only included to provide an easy way for applications to test
* Wallet Adapter without using a third-party wallet.
*/
export class UnsafeBurnerWalletAdapter extends BaseMessageSignerWalletAdapter {
export class UnsafeBurnerWalletAdapter extends BaseSignInMessageSignerWalletAdapter {
name = UnsafeBurnerWalletName;
url = 'https://github.com/solana-labs/wallet-adapter#usage';
icon =
Expand Down Expand Up @@ -77,4 +79,30 @@ export class UnsafeBurnerWalletAdapter extends BaseMessageSignerWalletAdapter {

return ed25519.sign(message, this._keypair.secretKey.slice(0, 32));
}

async signIn(input: SolanaSignInInput = {}): Promise<SolanaSignInOutput> {
const { publicKey, secretKey } = (this._keypair ||= new Keypair());
const domain = input.domain || window.location.host;
const address = input.address || publicKey.toBase58();

const signedMessage = createSignInMessage({
...input,
domain,
address,
});
const signature = ed25519.sign(signedMessage, secretKey.slice(0, 32));

this.emit('connect', publicKey);

return {
account: {
address,
publicKey: publicKey.toBytes(),
chains: [],
features: [],
},
signedMessage,
signature,
};
}
}
Loading

0 comments on commit b1b7e57

Please sign in to comment.