Skip to content

Commit 02376f3

Browse files
Release v11.2.0
Origin-SHA: 12ec70653ffc71110241b58761c01985d9abd5b7 Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 0dd2946 commit 02376f3

25 files changed

Lines changed: 2105 additions & 38 deletions

AGENTS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pnpm run check-types # TypeScript type checking (stricter tsconfig)
2323
| `src/viem.ts` | `OpenSeaViemSDK` — viem entry point |
2424
| `src/types.ts` | Public types: `Chain` enum, `Amount`, order/event types |
2525
| `src/constants.ts` | Math and Ethereum constants (basis points, addresses, etc.) |
26+
| `src/auth/` | `OpenSeaAuth` — SIWE-based wallet authentication (nonce, sign-in, scoped JWTs, auto-refresh) |
27+
| `src/scopes.ts` | `OPENSEA_SCOPES` — OAuth-style API scope string constants |
2628
| `src/sdk/base.ts` | `BaseOpenSeaSDK` — shared logic for both providers |
2729
| `src/sdk/fulfillment.ts` | Order fulfillment (buy, sell, match) via Seaport |
2830
| `src/sdk/orders.ts` | Create and manage listings and offers |
@@ -41,7 +43,7 @@ pnpm run check-types # TypeScript type checking (stricter tsconfig)
4143

4244
When reviewing changes to this package, verify:
4345

44-
1. **Chain enum sync**: The `Chain` enum in `src/types.ts` has a compile-time check (`_AssertAPIChainsCovered`) ensuring every `ChainIdentifier` from `@opensea/api-types` maps to a `Chain` value. When adding a chain, also update `scripts/chain-data.json` at the **monorepo root**, run `pnpm sync-chains` from the monorepo root, and update `getListingPaymentToken` / `getOfferPaymentToken` / `getNativeWrapTokenAddress`.
46+
1. **Chain enum sync**: The `Chain` enum in `src/types.ts` has a compile-time check (`_AssertAPIChainsCovered`) ensuring every `ChainIdentifier` from `@opensea/api-types` maps to a `Chain` value. `getOfferPaymentToken` and `getListingPaymentToken` use exhaustive `switch` statements whose `default` branch assigns `chain` to a `never` binding, so `pnpm check-types` fails if a new `Chain` is added without a payment-token case — either map it to a real token or mark it unsupported explicitly (like `Chain.Solana` / `Chain.Hyperliquid`, which throw a clear "not supported" error). `getNativeWrapTokenAddress` delegates to `getOfferPaymentToken` except for `Chain.Polygon`, so it is covered automatically unless the wrap token differs from the offer token. `test/utils/chain.spec.ts` also iterates every `Chain` value at runtime as a second guard and runs in `pnpm test`. When adding a chain, also update `scripts/chain-data.json` at the **monorepo root** and run `pnpm sync-chains` from the monorepo root.
4547

4648
2. **Dual provider support**: Both `OpenSeaSDK` (ethers) and `OpenSeaViemSDK` (viem) must work. Changes to `BaseOpenSeaSDK` affect both. If adding provider-specific logic, ensure both adapters in `src/provider/` are updated.
4749

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
# @opensea/sdk
22

3+
## 11.2.0
4+
5+
### Minor Changes
6+
7+
- ef89be8: Add SIWE authentication helpers: `OpenSeaAuth` class with authenticate, getValidToken, and revoke methods. Support `authToken` and `authBaseUrl` in `OpenSeaAPIConfig` for wallet-authenticated endpoints.
8+
- e61a57c: Add `OpenSeaOAuth` OAuth 2.1 helper (authorization-code + PKCE, device authorization grant, refresh, and revoke) for keyless login against the OpenSea authorization server. Exposes `OpenSeaOAuthConfig`, `OAuthToken`, and related types, plus a `decodeJwtPayload` utility for reading token claims.
9+
- ef89be8: Add `OPENSEA_SCOPES`, `OpenSeaScope`, and `ALL_SCOPES` exports — scope constants derived from the OpenAPI spec's `AuthScope` schema (via `@opensea/api-types`), with compile-time assertions that fail the build if they drift from the spec.
10+
- c460fc1: Add wallet trading P&L methods to `OpenSeaAPI`: `getWalletPnl`,
11+
`getWalletClosedPositions`, and `getWalletTokenTransfers`, with camelized
12+
`WalletPnlResponse`, `ClosedPositionsResponse`, and
13+
`PositionTokenTransfersResponse` types plus `WalletClosedPositionsArgs` /
14+
`WalletTokenTransfersArgs` query args.
15+
16+
### Patch Changes
17+
18+
- b816727: Add missing chain payment-token mappings for Soneium and AnimeChain, and make Solana/Hyperliquid fail fast with clear unsupported-chain errors for OpenSea Seaport offer/listing helpers. This fixes the chain helper drift tracked in ProjectOpenSea/opensea-js#1975.
19+
- c9d8cb1: Recreate the community fixes from ProjectOpenSea/opensea-js#1974 and ProjectOpenSea/opensea-js#1976: validate `amount` before `parseUnits` in `_getPriceParameters`, and reject `cancelOrders` batches that mix protocol addresses. Also add a runtime chain-helper exhaustiveness guard so new `Chain` values are consciously categorized.
20+
- e59df7f: Sync OpenAPI spec: add tool activity endpoint, `robinhood` chain, `source`/`collection` search filters, `calldata_suffix` on fulfillment, SIWX wallet-link endpoint (`POST /api/v2/accounts/wallets/siwx` with `LinkWalletSiwxRequest`/`WalletLinkResponse`), re-published `GET /api/v2/account/{address}/favorites`, and the new `write:wallets` auth scope (also added to the SDK's `OPENSEA_SCOPES`)
21+
- Updated dependencies [e59df7f]
22+
- Updated dependencies [c460fc1]
23+
- Updated dependencies [ef89be8]
24+
- @opensea/api-types@0.6.0
25+
26+
## 11.1.2
27+
28+
### Patch Changes
29+
30+
- Updated dependencies
31+
- @opensea/api-types@0.5.0
32+
333
## 11.1.1
434

535
### Patch Changes

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opensea/sdk",
3-
"version": "11.1.1",
3+
"version": "11.2.0",
44
"description": "TypeScript SDK for the OpenSea marketplace helps developers build new experiences using NFTs, tokens, and our marketplace data",
55
"license": "MIT",
66
"author": "OpenSea Developers",
@@ -45,7 +45,7 @@
4545
"types": "lib/index.d.ts",
4646
"dependencies": {
4747
"@noble/hashes": "^2.0.1",
48-
"@opensea/api-types": "^0.4.3",
48+
"@opensea/api-types": "^0.6.0",
4949
"@opensea/seaport-js": "^4.1.1",
5050
"ethers": "^6.16.0"
5151
},

src/api/accounts.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ import {
1111
getProfileOffersPath,
1212
getProfileOffersReceivedPath,
1313
getResolveAccountPath,
14+
getWalletClosedPositionsPath,
15+
getWalletPnlPath,
16+
getWalletTokenTransfersPath,
1417
} from "./apiPaths"
1518
import type { Fetcher } from "./fetcher"
1619
import type {
20+
ClosedPositionsResponse,
1721
GetAccountTokensArgs,
1822
GetAccountTokensResponse,
1923
PortfolioArgs,
2024
PortfolioHistoryResponse,
2125
PortfolioStatsResponse,
26+
PositionTokenTransfersResponse,
2227
ProfileCollectionsArgs,
2328
ProfileCollectionsResponse,
2429
ProfileFavoritesArgs,
@@ -27,6 +32,9 @@ import type {
2732
ProfileOffersResponse,
2833
ProfileOrdersArgs,
2934
ResolveAccountResponse,
35+
WalletClosedPositionsArgs,
36+
WalletPnlResponse,
37+
WalletTokenTransfersArgs,
3038
} from "./types"
3139

3240
function joinArray(value: string[] | undefined): string | undefined {
@@ -187,6 +195,39 @@ export class AccountsAPI {
187195
)
188196
}
189197

198+
/**
199+
* Get aggregated trading P&L (realized + unrealized) for an account.
200+
*/
201+
async getWalletPnl(address: string): Promise<WalletPnlResponse> {
202+
return this.fetcher.get<WalletPnlResponse>(getWalletPnlPath(address))
203+
}
204+
205+
/**
206+
* Get closed (realized) trading positions for an account.
207+
*/
208+
async getWalletClosedPositions(
209+
address: string,
210+
args?: WalletClosedPositionsArgs,
211+
): Promise<ClosedPositionsResponse> {
212+
return this.fetcher.get<ClosedPositionsResponse>(
213+
getWalletClosedPositionsPath(address),
214+
args,
215+
)
216+
}
217+
218+
/**
219+
* Get the token transfers contributing to a wallet's position in a currency.
220+
*/
221+
async getWalletTokenTransfers(
222+
address: string,
223+
args: WalletTokenTransfersArgs,
224+
): Promise<PositionTokenTransfersResponse> {
225+
return this.fetcher.get<PositionTokenTransfersResponse>(
226+
getWalletTokenTransfersPath(address),
227+
args,
228+
)
229+
}
230+
190231
/**
191232
* Get collections owned by an account.
192233
*/

src/api/api.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
type BatchTokensRequest,
3939
type BuildOfferResponse,
4040
type CancelOrderResponse,
41+
type ClosedPositionsResponse,
4142
type CollectionBatchResponse,
4243
type CollectionFloorPricesArgs,
4344
type CollectionHoldersArgs,
@@ -98,6 +99,7 @@ import {
9899
type PortfolioArgs,
99100
type PortfolioHistoryResponse,
100101
type PortfolioStatsResponse,
102+
type PositionTokenTransfersResponse,
101103
type PriceHistoryResponse,
102104
type ProfileCollectionsArgs,
103105
type ProfileCollectionsResponse,
@@ -128,6 +130,9 @@ import {
128130
type TransferRequest,
129131
type TransferResponse,
130132
type ValidateMetadataResponse,
133+
type WalletClosedPositionsArgs,
134+
type WalletPnlResponse,
135+
type WalletTokenTransfersArgs,
131136
} from "./types"
132137

133138
/**
@@ -149,6 +154,7 @@ export class OpenSeaAPI {
149154
public logger: (arg: string) => void
150155

151156
private apiKey: string | undefined
157+
private authToken: string | undefined
152158
private chain: Chain
153159

154160
// Specialized API clients
@@ -173,6 +179,7 @@ export class OpenSeaAPI {
173179
*/
174180
constructor(config: OpenSeaAPIConfig, logger?: (arg: string) => void) {
175181
this.apiKey = config.apiKey
182+
this.authToken = config.authToken
176183
this.chain = config.chain ?? Chain.Mainnet
177184

178185
if (config.apiBaseUrl) {
@@ -1284,6 +1291,33 @@ export class OpenSeaAPI {
12841291
return this.accountsAPI.getProfileCollections(address, args)
12851292
}
12861293

1294+
/**
1295+
* Get aggregated trading P&L (realized + unrealized) for an account.
1296+
*/
1297+
public async getWalletPnl(address: string): Promise<WalletPnlResponse> {
1298+
return this.accountsAPI.getWalletPnl(address)
1299+
}
1300+
1301+
/**
1302+
* Get closed (realized) trading positions for an account.
1303+
*/
1304+
public async getWalletClosedPositions(
1305+
address: string,
1306+
args?: WalletClosedPositionsArgs,
1307+
): Promise<ClosedPositionsResponse> {
1308+
return this.accountsAPI.getWalletClosedPositions(address, args)
1309+
}
1310+
1311+
/**
1312+
* Get the token transfers contributing to a wallet's position in a currency.
1313+
*/
1314+
public async getWalletTokenTransfers(
1315+
address: string,
1316+
args: WalletTokenTransfersArgs,
1317+
): Promise<PositionTokenTransfersResponse> {
1318+
return this.accountsAPI.getWalletTokenTransfers(address, args)
1319+
}
1320+
12871321
/**
12881322
* Generic fetch method for any API endpoint with automatic rate limit retry
12891323
* @param apiPath Path to URL endpoint under API
@@ -1382,12 +1416,14 @@ export class OpenSeaAPI {
13821416
// Kept as "opensea-js" for server-side analytics continuity after package rename
13831417
"x-app-id": "opensea-js",
13841418
...(this.apiKey ? { "X-API-KEY": this.apiKey } : {}),
1419+
...(this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}),
13851420
...(body != null ? { "Content-Type": "application/json" } : {}),
13861421
...headers,
13871422
}
13881423

13891424
const sanitizedHeaders = { ...mergedHeaders }
13901425
delete sanitizedHeaders["X-API-KEY"]
1426+
delete sanitizedHeaders.Authorization
13911427
this.logger(
13921428
`Sending request: ${url} ${JSON.stringify({
13931429
method: body != null ? "POST" : "GET",

src/api/apiPaths.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,18 @@ export const getProfileFavoritesPath = (address: string) => {
373373
return `${API_V2_PREFIX}/account/${address}/favorites`
374374
}
375375

376+
export const getWalletPnlPath = (address: string) => {
377+
return `${API_V2_PREFIX}/account/${address}/pnl`
378+
}
379+
380+
export const getWalletClosedPositionsPath = (address: string) => {
381+
return `${API_V2_PREFIX}/account/${address}/pnl/closed-positions`
382+
}
383+
384+
export const getWalletTokenTransfersPath = (address: string) => {
385+
return `${API_V2_PREFIX}/account/${address}/pnl/token-transfers`
386+
}
387+
376388
export const getProfileCollectionsPath = (address: string) => {
377389
return `${API_V2_PREFIX}/account/${address}/collections`
378390
}

src/api/types.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,7 @@ import type {
11731173
BatchCollectionsRequest as ApiBatchCollectionsRequest,
11741174
BatchNftsRequest as ApiBatchNftsRequest,
11751175
BatchTokensRequest as ApiBatchTokensRequest,
1176+
ClosedPositionsResponse as ApiClosedPositionsResponse,
11761177
CollectionBatchResponse as ApiCollectionBatchResponse,
11771178
CollectionHoldersPaginatedResponse as ApiCollectionHoldersPaginatedResponse,
11781179
CollectionOfferAggregatesPaginatedResponse as ApiCollectionOfferAggregatesPaginatedResponse,
@@ -1193,6 +1194,7 @@ import type {
11931194
OwnersPaginatedResponse as ApiOwnersPaginatedResponse,
11941195
PortfolioHistoryResponse as ApiPortfolioHistoryResponse,
11951196
PortfolioStatsResponse as ApiPortfolioStatsResponse,
1197+
PositionTokenTransfersResponse as ApiPositionTokenTransfersResponse,
11961198
PriceHistoryResponse as ApiPriceHistoryResponse,
11971199
ProfileCollectionsResponse as ApiProfileCollectionsResponse,
11981200
SwapTransactionResponse as ApiSwapTransactionResponse,
@@ -1202,6 +1204,7 @@ import type {
12021204
TokenSwapActivityPaginatedResponse as ApiTokenSwapActivityPaginatedResponse,
12031205
TransferRequest as ApiTransferRequest,
12041206
TransferResponse as ApiTransferResponse,
1207+
WalletPnlResponse as ApiWalletPnlResponse,
12051208
} from "@opensea/api-types"
12061209

12071210
// Request types — camelized consumer view. The fetcher snakeizes the body on
@@ -1238,6 +1241,10 @@ export type OhlcvResponse = Camelize<ApiOhlcvResponse>
12381241
export type OwnersPaginatedResponse = Camelize<ApiOwnersPaginatedResponse>
12391242
export type PortfolioHistoryResponse = Camelize<ApiPortfolioHistoryResponse>
12401243
export type PortfolioStatsResponse = Camelize<ApiPortfolioStatsResponse>
1244+
export type WalletPnlResponse = Camelize<ApiWalletPnlResponse>
1245+
export type ClosedPositionsResponse = Camelize<ApiClosedPositionsResponse>
1246+
export type PositionTokenTransfersResponse =
1247+
Camelize<ApiPositionTokenTransfersResponse>
12411248
export type PriceHistoryResponse = Camelize<ApiPriceHistoryResponse>
12421249
export type ProfileCollectionsResponse = Camelize<ApiProfileCollectionsResponse>
12431250
export type SwapTransactionResponse = Camelize<ApiSwapTransactionResponse>
@@ -1368,6 +1375,35 @@ export interface ProfileFavoritesArgs {
13681375
chains?: string[]
13691376
}
13701377

1378+
/**
1379+
* Query args for the wallet closed-positions (realized P&L) endpoint.
1380+
* @category API Query Args
1381+
*/
1382+
export interface WalletClosedPositionsArgs {
1383+
/** Sort field for the returned positions. */
1384+
sortBy?: string
1385+
/** Max number of positions to return (default 20). */
1386+
limit?: number
1387+
/** Cursor for the next page of results. */
1388+
next?: string
1389+
}
1390+
1391+
/**
1392+
* Query args for the wallet position token-transfers endpoint. `contractAddress`
1393+
* and `chain` identify the currency position to inspect and are required.
1394+
* @category API Query Args
1395+
*/
1396+
export interface WalletTokenTransfersArgs {
1397+
/** Contract address of the currency whose position transfers to fetch. */
1398+
contractAddress: string
1399+
/** Chain the currency lives on (e.g. `ethereum`, `base`). */
1400+
chain: string
1401+
/** Max number of transfers to return (default 20). */
1402+
limit?: number
1403+
/** Cursor for the next page of results. */
1404+
next?: string
1405+
}
1406+
13711407
/**
13721408
* Query args for the account profile collections endpoint.
13731409
* @category API Query Args

0 commit comments

Comments
 (0)