11import { assertDigestCapabilityIsAvailable } from '@solana/assertions' ;
2+ import {
3+ isSolanaError ,
4+ SOLANA_ERROR__COULD_NOT_FIND_VIABLE_PDA_BUMP_SEED ,
5+ SOLANA_ERROR__INVALID_SEEDS_POINT_ON_CURVE ,
6+ SOLANA_ERROR__MALFORMED_PROGRAM_DERIVED_ADDRESS ,
7+ SOLANA_ERROR__MAX_NUMBER_OF_PDA_SEEDS_EXCEEDED ,
8+ SOLANA_ERROR__MAX_PDA_SEED_LENGTH_EXCEEDED ,
9+ SOLANA_ERROR__PROGRAM_ADDRESS_ENDS_WITH_PDA_MARKER ,
10+ SOLANA_ERROR__PROGRAM_DERIVED_ADDRESS_BUMP_SEED_OUT_OF_RANGE ,
11+ SolanaError ,
12+ } from '@solana/errors' ;
213
314import { Address , assertIsAddress , getAddressCodec , isAddress } from './address' ;
415import { compressedPointBytesAreOnCurve } from './curve' ;
@@ -45,14 +56,12 @@ export function assertIsProgramDerivedAddress<TAddress extends string = string>(
4556 const validFormat =
4657 Array . isArray ( value ) && value . length === 2 && typeof value [ 0 ] === 'string' && typeof value [ 1 ] === 'number' ;
4758 if ( ! validFormat ) {
48- // TODO: Coded error.
49- throw new Error (
50- `Expected given program derived address to have the following format: [Address, ProgramDerivedAddressBump].` ,
51- ) ;
59+ throw new SolanaError ( SOLANA_ERROR__MALFORMED_PROGRAM_DERIVED_ADDRESS ) ;
5260 }
5361 if ( value [ 1 ] < 0 || value [ 1 ] > 255 ) {
54- // TODO: Coded error.
55- throw new Error ( `Expected program derived address bump to be in the range [0, 255], got: ${ value [ 1 ] } .` ) ;
62+ throw new SolanaError ( SOLANA_ERROR__PROGRAM_DERIVED_ADDRESS_BUMP_SEED_OUT_OF_RANGE , {
63+ bump : value [ 1 ] ,
64+ } ) ;
5665 }
5766 assertIsAddress ( value [ 0 ] ) ;
5867}
@@ -77,21 +86,23 @@ const PDA_MARKER_BYTES = [
7786 80 , 114 , 111 , 103 , 114 , 97 , 109 , 68 , 101 , 114 , 105 , 118 , 101 , 100 , 65 , 100 , 100 , 114 , 101 , 115 , 115 ,
7887] as const ;
7988
80- // TODO: Coded error.
81- class PointOnCurveError extends Error { }
82-
8389async function createProgramDerivedAddress ( { programAddress, seeds } : ProgramDerivedAddressInput ) : Promise < Address > {
8490 await assertDigestCapabilityIsAvailable ( ) ;
8591 if ( seeds . length > MAX_SEEDS ) {
86- // TODO: Coded error.
87- throw new Error ( `A maximum of ${ MAX_SEEDS } seeds may be supplied when creating an address` ) ;
92+ throw new SolanaError ( SOLANA_ERROR__MAX_NUMBER_OF_PDA_SEEDS_EXCEEDED , {
93+ actual : seeds . length ,
94+ maxSeeds : MAX_SEEDS ,
95+ } ) ;
8896 }
8997 let textEncoder : TextEncoder ;
9098 const seedBytes = seeds . reduce ( ( acc , seed , ii ) => {
9199 const bytes = typeof seed === 'string' ? ( textEncoder ||= new TextEncoder ( ) ) . encode ( seed ) : seed ;
92100 if ( bytes . byteLength > MAX_SEED_LENGTH ) {
93- // TODO: Coded error.
94- throw new Error ( `The seed at index ${ ii } exceeds the maximum length of 32 bytes` ) ;
101+ throw new SolanaError ( SOLANA_ERROR__MAX_PDA_SEED_LENGTH_EXCEEDED , {
102+ actual : bytes . byteLength ,
103+ index : ii ,
104+ maxSeedLength : MAX_SEED_LENGTH ,
105+ } ) ;
95106 }
96107 acc . push ( ...bytes ) ;
97108 return acc ;
@@ -104,8 +115,7 @@ async function createProgramDerivedAddress({ programAddress, seeds }: ProgramDer
104115 ) ;
105116 const addressBytes = new Uint8Array ( addressBytesBuffer ) ;
106117 if ( await compressedPointBytesAreOnCurve ( addressBytes ) ) {
107- // TODO: Coded error.
108- throw new PointOnCurveError ( 'Invalid seeds; point must fall off the Ed25519 curve' ) ;
118+ throw new SolanaError ( SOLANA_ERROR__INVALID_SEEDS_POINT_ON_CURVE ) ;
109119 }
110120 return base58EncodedAddressCodec . decode ( addressBytes ) ;
111121}
@@ -123,33 +133,34 @@ export async function getProgramDerivedAddress({
123133 } ) ;
124134 return [ address , bumpSeed as ProgramDerivedAddressBump ] ;
125135 } catch ( e ) {
126- if ( e instanceof PointOnCurveError ) {
136+ if ( isSolanaError ( e , SOLANA_ERROR__INVALID_SEEDS_POINT_ON_CURVE ) ) {
127137 bumpSeed -- ;
128138 } else {
129139 throw e ;
130140 }
131141 }
132142 }
133- // TODO: Coded error.
134- throw new Error ( 'Unable to find a viable program address bump seed' ) ;
143+ throw new SolanaError ( SOLANA_ERROR__COULD_NOT_FIND_VIABLE_PDA_BUMP_SEED ) ;
135144}
136145
137146export async function createAddressWithSeed ( { baseAddress, programAddress, seed } : SeedInput ) : Promise < Address > {
138147 const { encode, decode } = getAddressCodec ( ) ;
139148
140149 const seedBytes = typeof seed === 'string' ? new TextEncoder ( ) . encode ( seed ) : seed ;
141150 if ( seedBytes . byteLength > MAX_SEED_LENGTH ) {
142- // TODO: Coded error.
143- throw new Error ( `The seed exceeds the maximum length of 32 bytes` ) ;
151+ throw new SolanaError ( SOLANA_ERROR__MAX_PDA_SEED_LENGTH_EXCEEDED , {
152+ actual : seedBytes . byteLength ,
153+ index : 0 ,
154+ maxSeedLength : MAX_SEED_LENGTH ,
155+ } ) ;
144156 }
145157
146158 const programAddressBytes = encode ( programAddress ) ;
147159 if (
148160 programAddressBytes . length >= PDA_MARKER_BYTES . length &&
149161 programAddressBytes . slice ( - PDA_MARKER_BYTES . length ) . every ( ( byte , index ) => byte === PDA_MARKER_BYTES [ index ] )
150162 ) {
151- // TODO: Coded error.
152- throw new Error ( `programAddress cannot end with the PDA marker` ) ;
163+ throw new SolanaError ( SOLANA_ERROR__PROGRAM_ADDRESS_ENDS_WITH_PDA_MARKER ) ;
153164 }
154165
155166 const addressBytesBuffer = await crypto . subtle . digest (
0 commit comments