diff --git a/README.md b/README.md index e23f52a..8856f48 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,24 @@ const client = new RelayClient(relayerUrl, chainId, wallet, builderConfig); const proxyClient = new RelayClient(relayerUrl, chainId, wallet, builderConfig, RelayerTxType.PROXY); ``` +### With Relayer API-Key Authentication + +The simplest auth path — uses the `RELAYER_API_KEY` + `RELAYER_API_KEY_ADDRESS` HTTP headers documented at [docs.polymarket.com/trading/gasless](https://docs.polymarket.com/trading/gasless). Obtain the key from polymarket.com's Settings > API Keys; the address is the EOA that owns the key. + +```typescript +import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client"; + +const apiKeyCreds = { + apiKey: process.env.RELAYER_API_KEY!, + apiKeyAddress: process.env.RELAYER_API_KEY_ADDRESS!, +}; + +// Pass `apiKeyCreds` as the 6th constructor argument. The 4th (`builderConfig`) +// can stay `undefined` — when `apiKeyCreds` is set it takes precedence over +// any HMAC `BuilderConfig` for authenticated requests. +const client = new RelayClient(relayerUrl, chainId, wallet, undefined, RelayerTxType.SAFE, apiKeyCreds); +``` + ## Examples ### Execute ERC20 Approval Transaction diff --git a/package.json b/package.json index b5257a1..33a18be 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ "test": "make test" }, "devDependencies": { + "@ethersproject/providers": "5.8.0", + "@ethersproject/wallet": "5.8.0", "@types/chai": "5.2.2", "@types/mocha": "10.0.10", "@types/node": "^18.7.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79f6c6b..8df1e33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,12 @@ importers: specifier: ^2.31.4 version: 2.38.5(typescript@5.9.3) devDependencies: + '@ethersproject/providers': + specifier: 5.8.0 + version: 5.8.0 + '@ethersproject/wallet': + specifier: 5.8.0 + version: 5.8.0 '@types/chai': specifier: 5.2.2 version: 5.2.2 diff --git a/src/client.ts b/src/client.ts index 32b8603..235cf86 100644 --- a/src/client.ts +++ b/src/client.ts @@ -17,6 +17,7 @@ import { OperationType, ProxyTransaction, ProxyTransactionArgs, + RelayerApiKeyCreds, RelayerTransaction, RelayerTransactionResponse, RelayerTxType, @@ -67,12 +68,15 @@ export class RelayClient { readonly builderConfig?: BuilderConfig; + readonly apiKeyCreds?: RelayerApiKeyCreds; + constructor( relayerUrl: string, chainId: number, signer?: Wallet | JsonRpcSigner | WalletClient, builderConfig?: BuilderConfig, relayTxType?: RelayerTxType, + apiKeyCreds?: RelayerApiKeyCreds, ) { this.relayerUrl = relayerUrl.endsWith("/") ? relayerUrl.slice(0, -1) : relayerUrl; this.chainId = chainId; @@ -82,7 +86,7 @@ export class RelayClient { this.relayTxType = relayTxType; this.contractConfig = getContractConfig(chainId); this.httpClient = new HttpClient(); - + if (signer != undefined) { this.signer = createAbstractSigner(chainId, signer); } @@ -90,6 +94,10 @@ export class RelayClient { if (builderConfig !== undefined) { this.builderConfig = builderConfig; } + + if (apiKeyCreds !== undefined) { + this.apiKeyCreds = apiKeyCreds; + } } public async getNonce(signerAddress: string, signerType: string): Promise { @@ -431,16 +439,35 @@ export class RelayClient { method: string, path: string, body?: string - ): Promise { + ): Promise { + // API-key auth (preferred when configured) — see + // https://docs.polymarket.com/trading/gasless. Empirically required + // for CTF `mergePositions` on post-V2-cutover SAFEs: HMAC builder + // auth round-trips into STATE_FAILED at gas estimation, while the + // API-key path is accepted by the relayer. + if (this.canApiKeyAuth()) { + return this.send( + path, + method, + { + headers: { + RELAYER_API_KEY: this.apiKeyCreds!.apiKey, + RELAYER_API_KEY_ADDRESS: this.apiKeyCreds!.apiKeyAddress, + }, + data: body, + } + ); + } + // builders auth if (this.canBuilderAuth()) { const builderHeaders = await this._generateBuilderHeaders(method, path, body); if (builderHeaders !== undefined) { return this.send( path, - method, + method, { headers: builderHeaders, data: body } - ); + ); } } @@ -475,6 +502,14 @@ export class RelayClient { return (this.builderConfig != undefined && this.builderConfig.isValid()); } + private canApiKeyAuth(): boolean { + return ( + this.apiKeyCreds != undefined + && !!this.apiKeyCreds.apiKey + && !!this.apiKeyCreds.apiKeyAddress + ); + } + private async send( endpoint: string, method: string, diff --git a/src/types.ts b/src/types.ts index daa09af..b2a269c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -157,6 +157,16 @@ export interface GetDeployedResponse { deployed: boolean; } +// Auth: simple API-key header path (per +// https://docs.polymarket.com/trading/gasless). Alternative to HMAC +// `BuilderConfig` — pass an instance of these to the `RelayClient` constructor +// to authenticate via `RELAYER_API_KEY` + `RELAYER_API_KEY_ADDRESS` headers. +// Obtained from polymarket.com Settings > API Keys. +export interface RelayerApiKeyCreds { + apiKey: string; + apiKeyAddress: string; +} + // Deposit Wallet types export interface DepositWalletCall {