11import type { ApiKeyCreds } from '@polymarket/bindings/clob' ;
22import { expectEvmAddress , expectSignature } from '@polymarket/types' ;
3- import { createOrDeriveApiKey } from './actions/auth' ;
3+ import { createOrDeriveApiKey , fetchApiKeys } from './actions/auth' ;
44import {
55 type AuthenticationWorkflow ,
66 createL2AuthTypedDataPayload ,
77} from './authentication' ;
88import { type EnvironmentConfig , production } from './environments' ;
9+ import { RequestRejectedError } from './errors' ;
910import { ServiceClient } from './ServiceClient' ;
1011
1112export type PublicClientConfig = {
@@ -17,6 +18,10 @@ export type PublicClientConfig = {
1718 environment ?: EnvironmentConfig ;
1819} ;
1920
21+ export type BeginAuthenticationOptions =
22+ | { credentials : ApiKeyCreds }
23+ | { nonce : number } ;
24+
2025type Context = {
2126 /** @internal */
2227 environment : EnvironmentConfig ;
@@ -29,6 +34,8 @@ type Context = {
2934} ;
3035
3136type SecureContext = Context & {
37+ /** @internal */
38+ address : string ;
3239 /** @internal */
3340 credentials : ApiKeyCreds ;
3441} ;
@@ -66,40 +73,75 @@ class PublicClient extends AbstractClient<Context> {
6673 throw new Error ( 'resume is not implemented yet' ) ;
6774 }
6875
69- beginAuthentication ( ) : Promise < AuthenticationWorkflow > {
76+ beginAuthentication (
77+ options ?: BeginAuthenticationOptions ,
78+ ) : Promise < AuthenticationWorkflow > {
7079 return Promise . resolve (
7180 async function * ( this : PublicClient ) : AuthenticationWorkflow {
7281 const timestamp = Math . floor ( Date . now ( ) / 1000 ) ;
82+ const nonce =
83+ options !== undefined && 'nonce' in options ? options . nonce : 0 ;
7384 const address = expectEvmAddress ( yield { kind : 'requestAddress' } ) ;
85+
86+ if ( options !== undefined && 'credentials' in options ) {
87+ const client = this . createSecureClient ( options . credentials , address ) ;
88+
89+ try {
90+ if (
91+ ( await fetchApiKeys ( client ) ) . includes ( options . credentials . key )
92+ ) {
93+ return client ;
94+ }
95+ } catch ( error ) {
96+ if (
97+ ! ( error instanceof RequestRejectedError ) ||
98+ error . status !== 401
99+ ) {
100+ throw error ;
101+ }
102+ }
103+ }
104+
74105 const signature = yield {
75106 kind : 'signAuthMessage' ,
76107 payload : createL2AuthTypedDataPayload ( {
77108 address,
78109 chainId : this . environment . chainId ,
110+ nonce,
79111 timestamp,
80112 } ) ,
81113 } ;
82114 const credentials = await createOrDeriveApiKey ( this , {
83115 address,
84- nonce : 0 ,
116+ nonce,
85117 signature : expectSignature ( signature ) ,
86118 timestamp,
87119 } ) ;
88120
89- return new SecureClient ( {
90- ...this . context ,
91- credentials,
92- } ) ;
121+ return this . createSecureClient ( credentials , address ) ;
93122 } . call ( this ) ,
94123 ) ;
95124 }
125+
126+ createSecureClient ( credentials : ApiKeyCreds , address : string ) : SecureClient {
127+ return new SecureClient ( {
128+ ...this . context ,
129+ address,
130+ credentials,
131+ } ) ;
132+ }
96133}
97134
98135class SecureClient extends AbstractClient < SecureContext > {
99136 /** @internal */
100137 get credentials ( ) : ApiKeyCreds {
101138 return this . context . credentials ;
102139 }
140+
141+ /** @internal */
142+ get address ( ) : string {
143+ return this . context . address ;
144+ }
103145}
104146
105147export type { PublicClient , SecureClient } ;
0 commit comments