-
Notifications
You must be signed in to change notification settings - Fork 771
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Functions you can use to assert that a group of wallet accounts suppo…
…rt a given feature
- Loading branch information
1 parent
d40efc0
commit 14e378f
Showing
6 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { address } from '@solana/addresses'; | ||
import { | ||
SOLANA_ERROR__WALLET_ACCOUNT_DOES_NOT_SUPPORT_FEATURE, | ||
SOLANA_ERROR__WALLET_DOES_NOT_SUPPORT_FEATURE, | ||
SolanaError, | ||
} from '@solana/errors'; | ||
|
||
import { assertWalletAccountSupportsFeatures, assertWalletSupportsFeatures } from '../assertions'; | ||
|
||
describe('assertWalletAccountSupportsFeatures', () => { | ||
it('does not fatal when a wallet account supports all features', () => { | ||
const mockAccount = { | ||
address: address('3kjLdPpu1ayfyxRzGFLX352NfKTFL8b4wb8GA8aFxaR3'), | ||
features: ['solana:signTransaction', 'solana:signAndSendTransaction', 'solana:signIn'] as const, | ||
}; | ||
expect(() => { | ||
assertWalletAccountSupportsFeatures(['solana:signAndSendTransaction', 'solana:signIn'], mockAccount); | ||
}).not.toThrow(); | ||
}); | ||
it('fatals when a wallet account does not support a feature', () => { | ||
const mockAccount = { | ||
address: address('3kjLdPpu1ayfyxRzGFLX352NfKTFL8b4wb8GA8aFxaR3'), | ||
features: ['solana:signTransaction'] as const, | ||
}; | ||
expect(() => { | ||
assertWalletAccountSupportsFeatures( | ||
['solana:signTransaction', 'solana:signAndSendTransaction'], | ||
mockAccount, | ||
); | ||
}).toThrow( | ||
new SolanaError(SOLANA_ERROR__WALLET_ACCOUNT_DOES_NOT_SUPPORT_FEATURE, { | ||
accountAddress: mockAccount.address, | ||
featureNames: ['solana:signAndSendTransaction'], | ||
}), | ||
); | ||
}); | ||
}); | ||
|
||
describe('assertWalletSupportsFeatures', () => { | ||
it('does not fatal when a wallet supports all features', () => { | ||
const mockWallet = { | ||
features: { 'solana:signAndSendTransaction': {}, 'solana:signIn': {}, 'solana:signTransaction': {} }, | ||
name: 'Mock Wallet', | ||
}; | ||
expect(() => { | ||
assertWalletSupportsFeatures(['solana:signAndSendTransaction', 'solana:signIn'], mockWallet); | ||
}).not.toThrow(); | ||
}); | ||
it('fatals when a wallet does not support a feature', () => { | ||
const mockWallet = { | ||
features: { 'solana:signTransaction': {} }, | ||
name: 'Mock Wallet', | ||
}; | ||
expect(() => { | ||
assertWalletSupportsFeatures(['solana:signTransaction', 'solana:signAndSendTransaction'], mockWallet); | ||
}).toThrow( | ||
new SolanaError(SOLANA_ERROR__WALLET_DOES_NOT_SUPPORT_FEATURE, { | ||
featureNames: ['solana:signAndSendTransaction'], | ||
walletName: 'Mock Wallet', | ||
}), | ||
); | ||
}); | ||
}); |
30 changes: 30 additions & 0 deletions
30
packages/react/src/__typetests__/assertWalletSupportsFeatures-typetest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { | ||
SolanaSignAndSendTransaction, | ||
SolanaSignAndSendTransactionFeature, | ||
SolanaSignIn, | ||
SolanaSignInFeature, | ||
SolanaSignMessage, | ||
SolanaSignMessageFeature, | ||
SolanaSignTransaction, | ||
SolanaSignTransactionFeature, | ||
} from '@solana/wallet-standard-features'; | ||
import { Wallet } from '@wallet-standard/base'; | ||
|
||
import { assertWalletSupportsFeatures } from '../assertions'; | ||
|
||
const wallet = null as unknown as Wallet; | ||
|
||
assertWalletSupportsFeatures([SolanaSignMessage], wallet); | ||
assertWalletSupportsFeatures([SolanaSignIn], wallet); | ||
wallet.features satisfies SolanaSignMessageFeature; | ||
wallet.features satisfies SolanaSignInFeature; | ||
|
||
// @ts-expect-error Not one of the features asserted on | ||
wallet.features satisfies SolanaSignTransactionFeature; | ||
|
||
// @ts-expect-error Not one of the features asserted on | ||
wallet.features satisfies SolanaSignAndSendTransactionFeature; | ||
|
||
assertWalletSupportsFeatures([SolanaSignTransaction, SolanaSignAndSendTransaction], wallet); | ||
wallet.features satisfies SolanaSignTransactionFeature; | ||
wallet.features satisfies SolanaSignAndSendTransactionFeature; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { | ||
SOLANA_ERROR__WALLET_ACCOUNT_DOES_NOT_SUPPORT_FEATURE, | ||
SOLANA_ERROR__WALLET_DOES_NOT_SUPPORT_FEATURE, | ||
SolanaError, | ||
} from '@solana/errors'; | ||
import { SolanaFeatures } from '@solana/wallet-standard-features'; | ||
import { Wallet, WalletAccount, WalletWithFeatures } from '@wallet-standard/base'; | ||
|
||
type AllSolanaWalletFeatures = UnionToIntersection<SolanaFeatures>; | ||
|
||
type FilterKeys<V, K> = { [P in keyof V]: P extends K ? P : never }[keyof V]; | ||
|
||
type UnionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) extends (x: infer R) => unknown | ||
? R | ||
: never; | ||
|
||
export function assertWalletAccountSupportsFeatures( | ||
featureNames: (keyof AllSolanaWalletFeatures)[], | ||
account: Pick<WalletAccount, 'address' | 'features'>, | ||
): void { | ||
const unsupportedFeatures = featureNames.filter(featureName => !account.features.includes(featureName)); | ||
if (unsupportedFeatures.length) { | ||
throw new SolanaError(SOLANA_ERROR__WALLET_ACCOUNT_DOES_NOT_SUPPORT_FEATURE, { | ||
accountAddress: account.address, | ||
featureNames: unsupportedFeatures, | ||
}); | ||
} | ||
} | ||
|
||
export function assertWalletSupportsFeatures<TFeatureNames extends (keyof AllSolanaWalletFeatures)[]>( | ||
featureNames: TFeatureNames, | ||
wallet: Pick<Wallet, 'features' | 'name'>, | ||
): asserts wallet is WalletWithFeatures<{ | ||
[P in FilterKeys<AllSolanaWalletFeatures, TFeatureNames[number]>]: AllSolanaWalletFeatures[P]; | ||
}> { | ||
const unsupportedFeatures = featureNames.filter(featureName => !(featureName in wallet.features)); | ||
if (unsupportedFeatures.length) { | ||
throw new SolanaError(SOLANA_ERROR__WALLET_DOES_NOT_SUPPORT_FEATURE, { | ||
featureNames: unsupportedFeatures, | ||
walletName: wallet.name, | ||
}); | ||
} | ||
} |