Skip to content

Commit e7eb2af

Browse files
authored
feat: add support for custom signer (#71)
* feat: add support for custom signer * typos * Clarification * Fix
1 parent 5952c3c commit e7eb2af

File tree

5 files changed

+106
-19
lines changed

5 files changed

+106
-19
lines changed

README.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,48 @@ npm install --save @opensea/seaport-js
3434

3535
Instantiate your instance of seaport using your ethers provider:
3636

37+
### Examples
38+
39+
#### Through a browser provider (i.e. Metamask)
40+
3741
```js
3842
import { Seaport } from "@opensea/seaport-js";
43+
import { ethers } from "ethers";
3944

40-
const provider = ethers.getDefaultProvider();
45+
const provider = new ethers.providers.Web3Provider(window.ethereum);
4146

4247
const seaport = new Seaport(provider);
4348
```
4449

50+
#### Through a RPC Provider (i.e. Alchemy)
51+
52+
```js
53+
import { Seaport } from "@opensea/seaport-js";
54+
import { ethers } from "ethers";
55+
56+
const provider = new ethers.provider.JsonRpcProvider(
57+
"https://<network>.alchemyapi.io/v2/YOUR-API-KEY"
58+
);
59+
60+
const seaport = new Seaport(provider);
61+
```
62+
63+
#### With custom signer
64+
65+
```js
66+
import { Seaport } from "@opensea/seaport-js";
67+
import { ethers } from "ethers";
68+
69+
// Provider must be provided to the signer when supplying a custom signer
70+
const provider = new ethers.provider.JsonRpcProvider(
71+
"https://<network>.alchemyapi.io/v2/YOUR-API-KEY"
72+
);
73+
74+
const signer = new ethers.Wallet("YOUR_PK", provider);
75+
76+
const seaport = new Seaport(signer);
77+
```
78+
4579
Look at the relevant definitions in `seaport.ts` in order to see the different functionality this library offers.
4680

4781
### Use Cases

src/seaport.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import type {
3636
ContractMethodReturnType,
3737
MatchOrdersFulfillment,
3838
SeaportContract,
39+
Signer,
3940
} from "./types";
4041
import { getApprovalActions } from "./utils/approval";
4142
import {
@@ -65,7 +66,9 @@ export class Seaport {
6566
// Provides the raw interface to the contract for flexibility
6667
public contract: SeaportContract;
6768

68-
private provider: providers.JsonRpcProvider;
69+
private provider: providers.Provider;
70+
71+
private signer?: Signer;
6972

7073
// Use the multicall provider for reads for batching and performance optimisations
7174
// NOTE: Do NOT await between sequential requests if you're intending to batch
@@ -80,11 +83,11 @@ export class Seaport {
8083
readonly OPENSEA_CONDUIT_KEY: string = OPENSEA_CONDUIT_KEY;
8184

8285
/**
83-
* @param provider - The provider to use for web3-related calls
86+
* @param providerOrSigner - The provider or signer to use for web3-related calls
8487
* @param considerationConfig - A config to provide flexibility in the usage of Seaport
8588
*/
8689
public constructor(
87-
provider: providers.JsonRpcProvider,
90+
providerOrSigner: providers.JsonRpcProvider | Signer,
8891
{
8992
overrides,
9093
// Five minute buffer
@@ -93,8 +96,22 @@ export class Seaport {
9396
conduitKeyToConduit,
9497
}: SeaportConfig = {}
9598
) {
99+
const provider =
100+
providerOrSigner instanceof providers.Provider
101+
? providerOrSigner
102+
: providerOrSigner.provider;
103+
104+
if (!provider) {
105+
throw new Error(
106+
"Either a provider or custom signer with provider must be provided"
107+
);
108+
}
109+
96110
this.provider = provider;
97-
this.multicallProvider = new multicallProviders.MulticallProvider(provider);
111+
112+
this.multicallProvider = new multicallProviders.MulticallProvider(
113+
this.provider
114+
);
98115

99116
this.contract = new Contract(
100117
overrides?.contractAddress ?? CROSS_CHAIN_SEAPORT_ADDRESS,
@@ -115,6 +132,18 @@ export class Seaport {
115132
this.defaultConduitKey = overrides?.defaultConduitKey ?? NO_CONDUIT;
116133
}
117134

135+
private _getSigner(accountAddress?: string): Signer {
136+
if (this.signer) {
137+
return this.signer;
138+
}
139+
140+
if (!(this.provider instanceof providers.JsonRpcProvider)) {
141+
throw new Error("Either signer or a JsonRpcProvider must be provided");
142+
}
143+
144+
return this.provider.getSigner(accountAddress);
145+
}
146+
118147
/**
119148
* Returns the corresponding order type based on whether it allows partial fills and is restricted by zone
120149
*
@@ -177,7 +206,7 @@ export class Seaport {
177206
}: CreateOrderInput,
178207
accountAddress?: string
179208
): Promise<OrderUseCase<CreateOrderAction>> {
180-
const signer = await this.provider.getSigner(accountAddress);
209+
const signer = this._getSigner(accountAddress);
181210
const offerer = await signer.getAddress();
182211
const offerItems = offer.map(mapInputItemToOfferItem);
183212
const considerationItems = [
@@ -349,7 +378,7 @@ export class Seaport {
349378
counter: number,
350379
accountAddress?: string
351380
): Promise<string> {
352-
const signer = this.provider.getSigner(accountAddress);
381+
const signer = this._getSigner(accountAddress);
353382

354383
const domainData = await this._getDomainData();
355384

@@ -379,7 +408,7 @@ export class Seaport {
379408
orders: OrderComponents[],
380409
accountAddress?: string
381410
): TransactionMethods<ContractMethodReturnType<SeaportContract, "cancel">> {
382-
const signer = this.provider.getSigner(accountAddress);
411+
const signer = this._getSigner(accountAddress);
383412

384413
return getTransactionMethods(this.contract.connect(signer), "cancel", [
385414
orders,
@@ -396,7 +425,7 @@ export class Seaport {
396425
): TransactionMethods<
397426
ContractMethodReturnType<SeaportContract, "incrementCounter">
398427
> {
399-
const signer = this.provider.getSigner(offerer);
428+
const signer = this._getSigner(offerer);
400429

401430
return getTransactionMethods(
402431
this.contract.connect(signer),
@@ -416,7 +445,7 @@ export class Seaport {
416445
orders: Order[],
417446
accountAddress?: string
418447
): TransactionMethods<ContractMethodReturnType<SeaportContract, "validate">> {
419-
const signer = this.provider.getSigner(accountAddress);
448+
const signer = this._getSigner(accountAddress);
420449

421450
return getTransactionMethods(this.contract.connect(signer), "validate", [
422451
orders,
@@ -610,7 +639,7 @@ export class Seaport {
610639
const { parameters: orderParameters } = order;
611640
const { offerer, offer, consideration } = orderParameters;
612641

613-
const fulfiller = await this.provider.getSigner(accountAddress);
642+
const fulfiller = this._getSigner(accountAddress);
614643

615644
const fulfillerAddress = await fulfiller.getAddress();
616645

@@ -744,7 +773,7 @@ export class Seaport {
744773
conduitKey?: string;
745774
recipientAddress?: string;
746775
}) {
747-
const fulfiller = await this.provider.getSigner(accountAddress);
776+
const fulfiller = this._getSigner(accountAddress);
748777

749778
const fulfillerAddress = await fulfiller.getAddress();
750779

@@ -859,7 +888,7 @@ export class Seaport {
859888
}): TransactionMethods<
860889
ContractMethodReturnType<SeaportContract, "matchOrders">
861890
> {
862-
const signer = this.provider.getSigner(accountAddress);
891+
const signer = this._getSigner(accountAddress);
863892

864893
return getTransactionMethods(this.contract.connect(signer), "matchOrders", [
865894
orders,

src/types.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import type {
55
import {
66
BigNumber,
77
BigNumberish,
8+
BytesLike,
89
Contract,
910
ContractTransaction,
11+
ethers,
1012
Overrides,
1113
PayableOverrides,
1214
PopulatedTransaction,
@@ -32,6 +34,28 @@ export type SeaportConfig = {
3234
};
3335
};
3436

37+
type TypedDataDomain = {
38+
name?: string;
39+
version?: string;
40+
chainId?: BigNumberish;
41+
verifyingContract?: string;
42+
salt?: BytesLike;
43+
};
44+
45+
type TypedDataField = {
46+
name: string;
47+
type: string;
48+
};
49+
50+
// Temporary until TypedDataSigner is added in ethers (in v6)
51+
export type Signer = ethers.Signer & {
52+
_signTypedData(
53+
domain: TypedDataDomain,
54+
types: Record<string, Array<TypedDataField>>,
55+
value: Record<string, any>
56+
): Promise<string>;
57+
};
58+
3559
export type OfferItem = {
3660
itemType: ItemType;
3761
token: string;

src/utils/approval.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { providers as multicallProviders } from "@0xsequence/multicall";
2-
import { BigNumber, Contract, providers } from "ethers";
2+
import { BigNumber, Contract, Signer } from "ethers";
33
import { ERC20ABI } from "../abi/ERC20";
44
import { ERC721ABI } from "../abi/ERC721";
55
import { ItemType, MAX_INT } from "../constants";
@@ -46,7 +46,7 @@ export const approvedItemAmount = async (
4646
*/
4747
export function getApprovalActions(
4848
insufficientApprovals: InsufficientApprovals,
49-
signer: providers.JsonRpcSigner
49+
signer: Signer
5050
): Promise<ApprovalAction[]> {
5151
return Promise.all(
5252
insufficientApprovals

src/utils/fulfill.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
BigNumberish,
44
ContractTransaction,
55
ethers,
6-
providers,
6+
Signer,
77
} from "ethers";
88
import type {
99
Seaport as SeaportContract,
@@ -197,7 +197,7 @@ export async function fulfillBasicOrder({
197197
timeBasedItemParams: TimeBasedItemParams;
198198
offererOperator: string;
199199
fulfillerOperator: string;
200-
signer: providers.JsonRpcSigner;
200+
signer: Signer;
201201
tips?: ConsiderationItem[];
202202
conduitKey: string;
203203
}): Promise<
@@ -340,7 +340,7 @@ export async function fulfillStandardOrder({
340340
conduitKey: string;
341341
recipientAddress: string;
342342
timeBasedItemParams: TimeBasedItemParams;
343-
signer: providers.JsonRpcSigner;
343+
signer: Signer;
344344
}): Promise<
345345
OrderUseCase<
346346
ExchangeAction<
@@ -530,7 +530,7 @@ export async function fulfillAvailableOrders({
530530
currentBlockTimestamp: number;
531531
ascendingAmountTimestampBuffer: number;
532532
conduitKey: string;
533-
signer: providers.JsonRpcSigner;
533+
signer: Signer;
534534
recipientAddress: string;
535535
}): Promise<
536536
OrderUseCase<

0 commit comments

Comments
 (0)