@@ -157,6 +157,7 @@ export interface SolRecoveryOptions extends MPCRecoveryOptions {
157157 // destination address where token should be sent before closing the ATA address
158158 recoveryDestinationAtaAddress ?: string ;
159159 programId ?: string ; // programId of the token
160+ apiKey ?: string ; // API key for node requests
160161}
161162
162163export interface SolConsolidationRecoveryOptions extends MPCConsolidationRecoveryOptions {
@@ -165,6 +166,7 @@ export interface SolConsolidationRecoveryOptions extends MPCConsolidationRecover
165166 secretKey : string ;
166167 } ;
167168 tokenContractAddress ?: string ;
169+ apiKey ?: string ; // API key for node requests
168170}
169171
170172const HEX_REGEX = / ^ [ 0 - 9 a - f A - F ] + $ / ;
@@ -534,16 +536,22 @@ export class Sol extends BaseCoin {
534536 } ) ;
535537 }
536538
537- protected getPublicNodeUrl ( ) : string {
539+ protected getPublicNodeUrl ( apiKey ?: string ) : string {
540+ if ( apiKey ) {
541+ return Environments [ this . bitgo . getEnv ( ) ] . solAlchemyNodeUrl + `/${ apiKey } ` ;
542+ }
538543 return Environments [ this . bitgo . getEnv ( ) ] . solNodeUrl ;
539544 }
540545
541546 /**
542547 * Make a request to one of the public SOL nodes available
543548 * @param params.payload
544549 */
545- protected async getDataFromNode ( params : { payload ?: Record < string , unknown > } ) : Promise < request . Response > {
546- const nodeUrl = this . getPublicNodeUrl ( ) ;
550+ protected async getDataFromNode (
551+ params : { payload ?: Record < string , unknown > } ,
552+ apiKey ?: string
553+ ) : Promise < request . Response > {
554+ const nodeUrl = this . getPublicNodeUrl ( apiKey ) ;
547555 try {
548556 return await request . post ( nodeUrl ) . send ( params . payload ) ;
549557 } catch ( e ) {
@@ -552,92 +560,107 @@ export class Sol extends BaseCoin {
552560 throw new Error ( `Unable to call endpoint: '/' from node: ${ nodeUrl } ` ) ;
553561 }
554562
555- protected async getBlockhash ( ) : Promise < string > {
556- const response = await this . getDataFromNode ( {
557- payload : {
558- id : '1' ,
559- jsonrpc : '2.0' ,
560- method : 'getLatestBlockhash' ,
561- params : [
562- {
563- commitment : 'finalized' ,
564- } ,
565- ] ,
563+ protected async getBlockhash ( apiKey ?: string ) : Promise < string > {
564+ const response = await this . getDataFromNode (
565+ {
566+ payload : {
567+ id : '1' ,
568+ jsonrpc : '2.0' ,
569+ method : 'getLatestBlockhash' ,
570+ params : [
571+ {
572+ commitment : 'finalized' ,
573+ } ,
574+ ] ,
575+ } ,
566576 } ,
567- } ) ;
577+ apiKey
578+ ) ;
568579 if ( response . status !== 200 ) {
569580 throw new Error ( 'Account not found' ) ;
570581 }
571582
572583 return response . body . result . value . blockhash ;
573584 }
574585
575- protected async getFeeForMessage ( message : string ) : Promise < number > {
576- const response = await this . getDataFromNode ( {
577- payload : {
578- id : '1' ,
579- jsonrpc : '2.0' ,
580- method : 'getFeeForMessage' ,
581- params : [
582- message ,
583- {
584- commitment : 'finalized' ,
585- } ,
586- ] ,
586+ protected async getFeeForMessage ( message : string , apiKey ?: string ) : Promise < number > {
587+ const response = await this . getDataFromNode (
588+ {
589+ payload : {
590+ id : '1' ,
591+ jsonrpc : '2.0' ,
592+ method : 'getFeeForMessage' ,
593+ params : [
594+ message ,
595+ {
596+ commitment : 'finalized' ,
597+ } ,
598+ ] ,
599+ } ,
587600 } ,
588- } ) ;
601+ apiKey
602+ ) ;
589603 if ( response . status !== 200 ) {
590604 throw new Error ( 'Account not found' ) ;
591605 }
592606
593607 return response . body . result . value ;
594608 }
595609
596- protected async getRentExemptAmount ( ) : Promise < number > {
597- const response = await this . getDataFromNode ( {
598- payload : {
599- jsonrpc : '2.0' ,
600- id : '1' ,
601- method : 'getMinimumBalanceForRentExemption' ,
602- params : [ 165 ] ,
610+ protected async getRentExemptAmount ( apiKey ?: string ) : Promise < number > {
611+ const response = await this . getDataFromNode (
612+ {
613+ payload : {
614+ jsonrpc : '2.0' ,
615+ id : '1' ,
616+ method : 'getMinimumBalanceForRentExemption' ,
617+ params : [ 165 ] ,
618+ } ,
603619 } ,
604- } ) ;
620+ apiKey
621+ ) ;
605622 if ( response . status !== 200 || response . error ) {
606623 throw new Error ( JSON . stringify ( response . error ) ) ;
607624 }
608625
609626 return response . body . result ;
610627 }
611628
612- protected async getAccountBalance ( pubKey : string ) : Promise < number > {
613- const response = await this . getDataFromNode ( {
614- payload : {
615- id : '1' ,
616- jsonrpc : '2.0' ,
617- method : 'getBalance' ,
618- params : [ pubKey ] ,
629+ protected async getAccountBalance ( pubKey : string , apiKey ?: string ) : Promise < number > {
630+ const response = await this . getDataFromNode (
631+ {
632+ payload : {
633+ id : '1' ,
634+ jsonrpc : '2.0' ,
635+ method : 'getBalance' ,
636+ params : [ pubKey ] ,
637+ } ,
619638 } ,
620- } ) ;
639+ apiKey
640+ ) ;
621641 if ( response . status !== 200 ) {
622642 throw new Error ( 'Account not found' ) ;
623643 }
624644 return response . body . result . value ;
625645 }
626646
627- protected async getAccountInfo ( pubKey : string ) : Promise < SolDurableNonceFromNode > {
628- const response = await this . getDataFromNode ( {
629- payload : {
630- id : '1' ,
631- jsonrpc : '2.0' ,
632- method : 'getAccountInfo' ,
633- params : [
634- pubKey ,
635- {
636- encoding : 'jsonParsed' ,
637- } ,
638- ] ,
647+ protected async getAccountInfo ( pubKey : string , apiKey ?: string ) : Promise < SolDurableNonceFromNode > {
648+ const response = await this . getDataFromNode (
649+ {
650+ payload : {
651+ id : '1' ,
652+ jsonrpc : '2.0' ,
653+ method : 'getAccountInfo' ,
654+ params : [
655+ pubKey ,
656+ {
657+ encoding : 'jsonParsed' ,
658+ } ,
659+ ] ,
660+ } ,
639661 } ,
640- } ) ;
662+ apiKey
663+ ) ;
641664 if ( response . status !== 200 ) {
642665 throw new Error ( 'Account not found' ) ;
643666 }
@@ -647,26 +670,29 @@ export class Sol extends BaseCoin {
647670 } ;
648671 }
649672
650- protected async getTokenAccountsByOwner ( pubKey = '' , programId = '' ) : Promise < [ ] | TokenAccount [ ] > {
651- const response = await this . getDataFromNode ( {
652- payload : {
653- id : '1' ,
654- jsonrpc : '2.0' ,
655- method : 'getTokenAccountsByOwner' ,
656- params : [
657- pubKey ,
658- {
659- programId :
660- programId . toString ( ) . toLowerCase ( ) === TOKEN_2022_PROGRAM_ID . toString ( ) . toLowerCase ( )
661- ? TOKEN_2022_PROGRAM_ID . toString ( )
662- : TOKEN_PROGRAM_ID . toString ( ) ,
663- } ,
664- {
665- encoding : 'jsonParsed' ,
666- } ,
667- ] ,
673+ protected async getTokenAccountsByOwner ( pubKey = '' , programId = '' , apiKey ?: string ) : Promise < [ ] | TokenAccount [ ] > {
674+ const response = await this . getDataFromNode (
675+ {
676+ payload : {
677+ id : '1' ,
678+ jsonrpc : '2.0' ,
679+ method : 'getTokenAccountsByOwner' ,
680+ params : [
681+ pubKey ,
682+ {
683+ programId :
684+ programId . toString ( ) . toLowerCase ( ) === TOKEN_2022_PROGRAM_ID . toString ( ) . toLowerCase ( )
685+ ? TOKEN_2022_PROGRAM_ID . toString ( )
686+ : TOKEN_PROGRAM_ID . toString ( ) ,
687+ } ,
688+ {
689+ encoding : 'jsonParsed' ,
690+ } ,
691+ ] ,
692+ } ,
668693 } ,
669- } ) ;
694+ apiKey
695+ ) ;
670696 if ( response . status !== 200 ) {
671697 throw new Error ( 'Account not found' ) ;
672698 }
@@ -682,20 +708,23 @@ export class Sol extends BaseCoin {
682708 return [ ] ;
683709 }
684710
685- protected async getTokenAccountInfo ( pubKey : string ) : Promise < TokenAccount > {
686- const response = await this . getDataFromNode ( {
687- payload : {
688- id : '1' ,
689- jsonrpc : '2.0' ,
690- method : 'getAccountInfo' ,
691- params : [
692- pubKey ,
693- {
694- encoding : 'jsonParsed' ,
695- } ,
696- ] ,
711+ protected async getTokenAccountInfo ( pubKey : string , apiKey ?: string ) : Promise < TokenAccount > {
712+ const response = await this . getDataFromNode (
713+ {
714+ payload : {
715+ id : '1' ,
716+ jsonrpc : '2.0' ,
717+ method : 'getAccountInfo' ,
718+ params : [
719+ pubKey ,
720+ {
721+ encoding : 'jsonParsed' ,
722+ } ,
723+ ] ,
724+ } ,
697725 } ,
698- } ) ;
726+ apiKey
727+ ) ;
699728 if ( response . status !== 200 ) {
700729 throw new Error ( 'Account not found' ) ;
701730 }
@@ -791,21 +820,21 @@ export class Sol extends BaseCoin {
791820 const accountId = MPC . deriveUnhardened ( bitgoKey , currPath ) . slice ( 0 , 64 ) ;
792821 const bs58EncodedPublicKey = new SolKeyPair ( { pub : accountId } ) . getAddress ( ) ;
793822
794- balance = await this . getAccountBalance ( bs58EncodedPublicKey ) ;
823+ balance = await this . getAccountBalance ( bs58EncodedPublicKey , params . apiKey ) ;
795824
796825 const factory = this . getBuilder ( ) ;
797826 const walletCoin = this . getChain ( ) ;
798827
799828 let txBuilder ;
800- let blockhash = await this . getBlockhash ( ) ;
829+ let blockhash = await this . getBlockhash ( params . apiKey ) ;
801830 let rentExemptAmount ;
802831 let authority = '' ;
803832 let totalFee = new BigNumber ( 0 ) ;
804833 let totalFeeForTokenRecovery = new BigNumber ( 0 ) ;
805834
806835 // check for possible token recovery, recover the token provide by user
807836 if ( params . tokenContractAddress ) {
808- const tokenAccounts = await this . getTokenAccountsByOwner ( bs58EncodedPublicKey , params . programId ) ;
837+ const tokenAccounts = await this . getTokenAccountsByOwner ( bs58EncodedPublicKey , params . programId , params . apiKey ) ;
809838 if ( tokenAccounts . length !== 0 ) {
810839 // there exists token accounts on the given address, but need to check certain conditions:
811840 // 1. if there is a recoverable balance
@@ -826,7 +855,7 @@ export class Sol extends BaseCoin {
826855 }
827856
828857 if ( recovereableTokenAccounts . length !== 0 ) {
829- rentExemptAmount = await this . getRentExemptAmount ( ) ;
858+ rentExemptAmount = await this . getRentExemptAmount ( params . apiKey ) ;
830859
831860 txBuilder = factory
832861 . getTokenTransferBuilder ( )
@@ -838,7 +867,8 @@ export class Sol extends BaseCoin {
838867 // need to get all token accounts of the recipient address and need to create them if they do not exist
839868 const recipientTokenAccounts = await this . getTokenAccountsByOwner (
840869 params . recoveryDestination ,
841- params . programId
870+ params . programId ,
871+ params . apiKey
842872 ) ;
843873
844874 for ( const tokenAccount of recovereableTokenAccounts ) {
@@ -894,7 +924,7 @@ export class Sol extends BaseCoin {
894924 }
895925
896926 if ( params . durableNonce ) {
897- const durableNonceInfo = await this . getAccountInfo ( params . durableNonce . publicKey ) ;
927+ const durableNonceInfo = await this . getAccountInfo ( params . durableNonce . publicKey , params . apiKey ) ;
898928 blockhash = durableNonceInfo . blockhash ;
899929 authority = durableNonceInfo . authority ;
900930
@@ -908,7 +938,7 @@ export class Sol extends BaseCoin {
908938 const unsignedTransactionWithoutFee = ( await txBuilder . build ( ) ) as Transaction ;
909939 const serializedMessage = unsignedTransactionWithoutFee . solTransaction . serializeMessage ( ) . toString ( 'base64' ) ;
910940
911- const baseFee = await this . getFeeForMessage ( serializedMessage ) ;
941+ const baseFee = await this . getFeeForMessage ( serializedMessage , params . apiKey ) ;
912942 const feePerSignature = params . durableNonce ? baseFee / 2 : baseFee ;
913943 totalFee = totalFee . plus ( new BigNumber ( baseFee ) ) ;
914944 totalFeeForTokenRecovery = totalFeeForTokenRecovery . plus ( new BigNumber ( baseFee ) ) ;
@@ -1118,7 +1148,7 @@ export class Sol extends BaseCoin {
11181148 throw new Error ( 'invalid recoveryDestinationAtaAddress' ) ;
11191149 }
11201150
1121- blockhash = await this . getBlockhash ( ) ;
1151+ blockhash = await this . getBlockhash ( params . apiKey ) ;
11221152
11231153 txBuilder = factory
11241154 . getTokenTransferBuilder ( )
@@ -1128,7 +1158,7 @@ export class Sol extends BaseCoin {
11281158 . feePayer ( bs58EncodedPublicKey ) ;
11291159 const unsignedTransaction = ( await txBuilder . build ( ) ) as Transaction ;
11301160 const serializedMessage = unsignedTransaction . solTransaction . serializeMessage ( ) . toString ( 'base64' ) ;
1131- const feePerSignature = await this . getFeeForMessage ( serializedMessage ) ;
1161+ const feePerSignature = await this . getFeeForMessage ( serializedMessage , params . apiKey ) ;
11321162 const baseFee = params . durableNonce ? feePerSignature * 2 : feePerSignature ;
11331163 const totalFee = new BigNumber ( baseFee ) ;
11341164 if ( totalFee . gt ( accountBalance ) ) {
@@ -1159,7 +1189,7 @@ export class Sol extends BaseCoin {
11591189
11601190 // after recovering the token amount, attempting to close the ATA address
11611191 if ( params . closeAtaAddress ) {
1162- blockhash = await this . getBlockhash ( ) ;
1192+ blockhash = await this . getBlockhash ( params . apiKey ) ;
11631193
11641194 const ataCloseBuilder = ( ) => {
11651195 const txBuilder = factory . getCloseAtaInitializationBuilder ( ) ;
@@ -1316,6 +1346,7 @@ export class Sol extends BaseCoin {
13161346 secretKey : params . durableNonces . secretKey ,
13171347 } ,
13181348 tokenContractAddress : params . tokenContractAddress ,
1349+ apiKey : params . apiKey ,
13191350 } ;
13201351
13211352 let recoveryTransaction ;
0 commit comments