@@ -32,54 +32,6 @@ export const CipMethodsMapping: Record<number, WalletMethod[]> = {
3232} ;
3333export const WalletApiMethodNames : WalletMethod [ ] = Object . values ( CipMethodsMapping ) . flat ( ) ;
3434
35- /**
36- * Wrap the proxy API object with a regular javascript object to avoid interop issues with some dApps.
37- *
38- * Only return the allowed API methods.
39- */
40- const wrapAndEnableApi = (
41- walletApi : WalletApi ,
42- enabledExtensions ?: WalletApiExtension [ ]
43- ) : Cip30WalletApiWithPossibleExtensions => {
44- const baseApi : Cip30WalletApiWithPossibleExtensions = {
45- // Add experimental.getCollateral to CIP-30 API
46- experimental : {
47- getCollateral : ( params ?: { amount ?: Cbor } ) => walletApi . getCollateral ( params )
48- } ,
49- getBalance : ( ) => walletApi . getBalance ( ) ,
50- getChangeAddress : ( ) => walletApi . getChangeAddress ( ) ,
51- getCollateral : ( params ?: { amount ?: Cbor } ) => walletApi . getCollateral ( params ) ,
52- getExtensions : ( ) => Promise . resolve ( enabledExtensions || [ ] ) ,
53- getNetworkId : ( ) => walletApi . getNetworkId ( ) ,
54- getRewardAddresses : ( ) => walletApi . getRewardAddresses ( ) ,
55- getUnusedAddresses : ( ) => walletApi . getUnusedAddresses ( ) ,
56- getUsedAddresses : ( paginate ?: Paginate ) => walletApi . getUsedAddresses ( paginate ) ,
57- getUtxos : ( amount ?: Cbor , paginate ?: Paginate ) => walletApi . getUtxos ( amount , paginate ) ,
58- signData : ( addr : Cardano . PaymentAddress | Bytes , payload : Bytes ) => walletApi . signData ( addr , payload ) ,
59- signTx : ( tx : Cbor , partialSign ?: Boolean ) => walletApi . signTx ( tx , partialSign ) ,
60- submitTx : ( tx : Cbor ) => walletApi . submitTx ( tx )
61- } ;
62-
63- const additionalCipApis : CipExtensionApis = {
64- cip95 : {
65- getPubDRepKey : ( ) => walletApi . getPubDRepKey ( ) ,
66- getRegisteredPubStakeKeys : ( ) => walletApi . getRegisteredPubStakeKeys ( ) ,
67- getUnregisteredPubStakeKeys : ( ) => walletApi . getUnregisteredPubStakeKeys ( )
68- }
69- } ;
70-
71- if ( enabledExtensions ) {
72- for ( const extension of enabledExtensions ) {
73- const cipName = `cip${ extension . cip } ` as keyof CipExtensionApis ;
74- if ( additionalCipApis [ cipName ] ) {
75- baseApi [ cipName ] = additionalCipApis [ cipName ] ;
76- }
77- }
78- }
79-
80- return baseApi ;
81- } ;
82-
8335/** CIP30 API version */
8436export type ApiVersion = string ;
8537
@@ -93,7 +45,19 @@ export type WalletName = string;
9345 */
9446export type WalletIcon = string ;
9547
96- export type WalletProperties = { icon : WalletIcon ; walletName : WalletName } ;
48+ export type WalletProperties = {
49+ icon : WalletIcon ;
50+ walletName : WalletName ;
51+ supportedExtensions ?: WalletApiExtension [ ] ;
52+ /** Deviations from the CIP30 spec */
53+ cip30ApiDeviations ?: {
54+ /**
55+ * Instead of throwing an error when no collateral is found, return empty array.
56+ * This is the way the Nami wallet works and some DApps rely on it (i.e. https://app.indigoprotocol.io/)
57+ */
58+ getCollateralEmptyArray ?: boolean ;
59+ } ;
60+ } ;
9761
9862export type WalletDependencies = {
9963 logger : Logger ;
@@ -108,20 +72,26 @@ export class Cip30Wallet {
10872 readonly apiVersion : ApiVersion = '0.1.0' ;
10973 readonly name : WalletName ;
11074 readonly icon : WalletIcon ;
75+ /** Support the full api by default */
11176 readonly supportedExtensions : WalletApiExtension [ ] = [ { cip : 95 } ] ;
11277
11378 readonly #logger: Logger ;
11479 readonly #api: WalletApi ;
11580 readonly #authenticator: RemoteAuthenticator ;
81+ readonly #deviations: WalletProperties [ 'cip30ApiDeviations' ] ;
11682
11783 constructor ( properties : WalletProperties , { api, authenticator, logger } : WalletDependencies ) {
11884 this . icon = properties . icon ;
11985 this . name = properties . walletName ;
12086 this . #api = api ;
12187 this . #logger = logger ;
12288 this . #authenticator = authenticator ;
89+ this . #deviations = properties . cip30ApiDeviations ;
12390 this . enable = this . enable . bind ( this ) ;
12491 this . isEnabled = this . isEnabled . bind ( this ) ;
92+ if ( properties . supportedExtensions ) {
93+ this . supportedExtensions = properties . supportedExtensions ;
94+ }
12595 }
12696
12797 #validateExtensions( extensions : WalletApiExtension [ ] = [ ] ) : void {
@@ -173,9 +143,60 @@ export class Cip30Wallet {
173143 const extensions = options ?. extensions ?. filter ( ( { cip : requestedCip } ) =>
174144 this . supportedExtensions . some ( ( { cip : supportedCip } ) => supportedCip === requestedCip )
175145 ) ;
176- return wrapAndEnableApi ( this . #api , extensions ) ;
146+ return this . #wrapAndEnableApi ( extensions ) ;
177147 }
178148 this . #logger. debug ( `${ location . origin } not authorized to access wallet api` ) ;
179149 throw new ApiError ( APIErrorCode . Refused , 'wallet not authorized.' ) ;
180150 }
151+
152+ async #wrapGetCollateral( params ?: { amount ?: Cbor } ) {
153+ const collateral = await this . #api. getCollateral ( params ) ;
154+ return this . #deviations?. getCollateralEmptyArray ? collateral ?? [ ] : collateral ;
155+ }
156+
157+ /**
158+ * Wrap the proxy API object with a regular javascript object to avoid interop issues with some dApps.
159+ *
160+ * Only return the allowed API methods.
161+ */
162+ #wrapAndEnableApi( enabledExtensions ?: WalletApiExtension [ ] ) : Cip30WalletApiWithPossibleExtensions {
163+ const walletApi = this . #api;
164+ const baseApi : Cip30WalletApiWithPossibleExtensions = {
165+ // Add experimental.getCollateral to CIP-30 API
166+ experimental : {
167+ getCollateral : async ( params ?: { amount ?: Cbor } ) => this . #wrapGetCollateral( params )
168+ } ,
169+ getBalance : ( ) => walletApi . getBalance ( ) ,
170+ getChangeAddress : ( ) => walletApi . getChangeAddress ( ) ,
171+ getCollateral : ( params ?: { amount ?: Cbor } ) => this . #wrapGetCollateral( params ) ,
172+ getExtensions : ( ) => Promise . resolve ( enabledExtensions || [ ] ) ,
173+ getNetworkId : ( ) => walletApi . getNetworkId ( ) ,
174+ getRewardAddresses : ( ) => walletApi . getRewardAddresses ( ) ,
175+ getUnusedAddresses : ( ) => walletApi . getUnusedAddresses ( ) ,
176+ getUsedAddresses : ( paginate ?: Paginate ) => walletApi . getUsedAddresses ( paginate ) ,
177+ getUtxos : ( amount ?: Cbor , paginate ?: Paginate ) => walletApi . getUtxos ( amount , paginate ) ,
178+ signData : ( addr : Cardano . PaymentAddress | Bytes , payload : Bytes ) => walletApi . signData ( addr , payload ) ,
179+ signTx : ( tx : Cbor , partialSign ?: Boolean ) => walletApi . signTx ( tx , partialSign ) ,
180+ submitTx : ( tx : Cbor ) => walletApi . submitTx ( tx )
181+ } ;
182+
183+ const additionalCipApis : CipExtensionApis = {
184+ cip95 : {
185+ getPubDRepKey : ( ) => walletApi . getPubDRepKey ( ) ,
186+ getRegisteredPubStakeKeys : ( ) => walletApi . getRegisteredPubStakeKeys ( ) ,
187+ getUnregisteredPubStakeKeys : ( ) => walletApi . getUnregisteredPubStakeKeys ( )
188+ }
189+ } ;
190+
191+ if ( enabledExtensions ) {
192+ for ( const extension of enabledExtensions ) {
193+ const cipName = `cip${ extension . cip } ` as keyof CipExtensionApis ;
194+ if ( additionalCipApis [ cipName ] ) {
195+ baseApi [ cipName ] = additionalCipApis [ cipName ] ;
196+ }
197+ }
198+ }
199+
200+ return baseApi ;
201+ }
181202}
0 commit comments