Skip to content

Commit 7f0912e

Browse files
authored
Add option to only request exact amounts in approval actions (ProjectOpenSea#157)
* add exact approval parameter * exact erc 20 approval * switch between approval for erc712 and erc1155 * add exactApproval to fulfill * fix missing param * fix remaining merge errors * bump version in nvmrc * add exactApproval to docs
1 parent f08291b commit 7f0912e

File tree

4 files changed

+176
-128
lines changed

4 files changed

+176
-128
lines changed

Diff for: .nvmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16.11.0
1+
16.15.1

Diff for: src/seaport.ts

+56-32
Original file line numberDiff line numberDiff line change
@@ -183,18 +183,21 @@ export class Seaport {
183183
* @param input.salt Arbitrary salt. If not passed in, a random salt will be generated with the first four bytes being the domain hash or empty.
184184
* @param input.offerer The order's creator address. Defaults to the first address on the provider.
185185
* @param accountAddress Optional address for which to create the order with
186+
* @param exactApproval optional boolean to indicate whether the approval should be exact or not
186187
* @returns a use case containing the list of actions needed to be performed in order to create the order
187188
*/
188189
public async createOrder(
189190
input: CreateOrderInput,
190-
accountAddress?: string
191+
accountAddress?: string,
192+
exactApproval?: boolean
191193
): Promise<OrderUseCase<CreateOrderAction>> {
192194
const signer = this._getSigner(accountAddress);
193195
const offerer = await signer.getAddress();
194196

195197
const { orderComponents, approvalActions } = await this._formatOrder(
196198
signer,
197199
offerer,
200+
Boolean(exactApproval),
198201
input
199202
);
200203

@@ -229,11 +232,13 @@ export class Seaport {
229232
* or a signature request that will then be supplied into the final orders, ready to be fulfilled.
230233
*
231234
* @param input See {@link createOrder} for more details about the input parameters.
235+
* @param exactApproval optional boolean to indicate whether the approval should be exact or not
232236
* @returns a use case containing the list of actions needed to be performed in order to create the orders
233237
*/
234238
public async createBulkOrders(
235239
createOrderInput: CreateOrderInput[],
236-
accountAddress?: string
240+
accountAddress?: string,
241+
exactApproval?: boolean
237242
): Promise<OrderUseCase<CreateBulkOrdersAction>> {
238243
const signer = this._getSigner(accountAddress);
239244
const offerer = await signer.getAddress();
@@ -247,6 +252,7 @@ export class Seaport {
247252
const { orderComponents, approvalActions } = await this._formatOrder(
248253
signer,
249254
offerer,
255+
Boolean(exactApproval),
250256
input
251257
);
252258

@@ -289,6 +295,7 @@ export class Seaport {
289295
private async _formatOrder(
290296
signer: Signer,
291297
offerer: string,
298+
exactApproval: boolean,
292299
{
293300
conduitKey = this.defaultConduitKey,
294301
zone = ethers.constants.AddressZero,
@@ -388,7 +395,11 @@ export class Seaport {
388395
operator,
389396
});
390397

391-
const approvals = await getApprovalActions(insufficientApprovals, signer);
398+
const approvals = await getApprovalActions(
399+
insufficientApprovals,
400+
exactApproval,
401+
signer
402+
);
392403
approvalActions.push(...approvals);
393404
}
394405

@@ -764,6 +775,7 @@ export class Seaport {
764775
* @param input.recipientAddress optional recipient to forward the offer to as opposed to the fulfiller.
765776
* Defaults to the zero address which means the offer goes to the fulfiller
766777
* @param input.domain optional domain to be hashed and appended to calldata
778+
* @param input.exactApproval optional boolean to indicate whether the approval should be exact or not
767779
* @returns a use case containing the set of approval actions and fulfillment action
768780
*/
769781
public async fulfillOrder({
@@ -777,6 +789,7 @@ export class Seaport {
777789
conduitKey = this.defaultConduitKey,
778790
recipientAddress = ethers.constants.AddressZero,
779791
domain = "",
792+
exactApproval = false,
780793
}: {
781794
order: OrderWithCounter;
782795
unitsToFill?: BigNumberish;
@@ -788,6 +801,7 @@ export class Seaport {
788801
conduitKey?: string;
789802
recipientAddress?: string;
790803
domain?: string;
804+
exactApproval?: boolean;
791805
}): Promise<
792806
OrderUseCase<
793807
ExchangeAction<
@@ -868,44 +882,50 @@ export class Seaport {
868882
shouldUseBasicFulfill(sanitizedOrder.parameters, totalFilled)
869883
) {
870884
// TODO: Use fulfiller proxy if there are approvals needed directly, but none needed for proxy
871-
return fulfillBasicOrder({
885+
return fulfillBasicOrder(
886+
{
887+
order: sanitizedOrder,
888+
seaportContract: this.contract,
889+
offererBalancesAndApprovals,
890+
fulfillerBalancesAndApprovals,
891+
timeBasedItemParams,
892+
conduitKey,
893+
offererOperator,
894+
fulfillerOperator,
895+
signer: fulfiller,
896+
tips: tipConsiderationItems,
897+
domain,
898+
},
899+
exactApproval
900+
);
901+
}
902+
903+
// Else, we fallback to the standard fulfill order
904+
return fulfillStandardOrder(
905+
{
872906
order: sanitizedOrder,
907+
unitsToFill,
908+
totalFilled,
909+
totalSize: totalSize.eq(0)
910+
? getMaximumSizeForOrder(sanitizedOrder)
911+
: totalSize,
912+
offerCriteria,
913+
considerationCriteria,
914+
tips: tipConsiderationItems,
915+
extraData,
873916
seaportContract: this.contract,
874917
offererBalancesAndApprovals,
875918
fulfillerBalancesAndApprovals,
876919
timeBasedItemParams,
877920
conduitKey,
921+
signer: fulfiller,
878922
offererOperator,
879923
fulfillerOperator,
880-
signer: fulfiller,
881-
tips: tipConsiderationItems,
924+
recipientAddress,
882925
domain,
883-
});
884-
}
885-
886-
// Else, we fallback to the standard fulfill order
887-
return fulfillStandardOrder({
888-
order: sanitizedOrder,
889-
unitsToFill,
890-
totalFilled,
891-
totalSize: totalSize.eq(0)
892-
? getMaximumSizeForOrder(sanitizedOrder)
893-
: totalSize,
894-
offerCriteria,
895-
considerationCriteria,
896-
tips: tipConsiderationItems,
897-
extraData,
898-
seaportContract: this.contract,
899-
offererBalancesAndApprovals,
900-
fulfillerBalancesAndApprovals,
901-
timeBasedItemParams,
902-
conduitKey,
903-
signer: fulfiller,
904-
offererOperator,
905-
fulfillerOperator,
906-
recipientAddress,
907-
domain,
908-
});
926+
},
927+
exactApproval
928+
);
909929
}
910930

911931
/**
@@ -918,6 +938,7 @@ export class Seaport {
918938
* @param input.recipientAddress optional recipient to forward the offer to as opposed to the fulfiller.
919939
* Defaults to the zero address which means the offer goes to the fulfiller
920940
* @param input.domain optional domain to be hashed and appended to calldata
941+
* @param input.exactApproval optional boolean to indicate whether the approval should be exact or not
921942
* @returns a use case containing the set of approval actions and fulfillment action
922943
*/
923944
public async fulfillOrders({
@@ -926,6 +947,7 @@ export class Seaport {
926947
conduitKey = this.defaultConduitKey,
927948
recipientAddress = ethers.constants.AddressZero,
928949
domain = "",
950+
exactApproval = false,
929951
}: {
930952
fulfillOrderDetails: {
931953
order: OrderWithCounter;
@@ -939,6 +961,7 @@ export class Seaport {
939961
conduitKey?: string;
940962
recipientAddress?: string;
941963
domain?: string;
964+
exactApproval?: boolean;
942965
}) {
943966
const fulfiller = this._getSigner(accountAddress);
944967

@@ -1029,6 +1052,7 @@ export class Seaport {
10291052
conduitKey,
10301053
recipientAddress,
10311054
domain,
1055+
exactApproval,
10321056
});
10331057
}
10341058

Diff for: src/utils/approval.ts

+44-31
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const approvedItemAmount = async (
4646
*/
4747
export function getApprovalActions(
4848
insufficientApprovals: InsufficientApprovals,
49+
exactApproval: boolean,
4950
signer: Signer
5051
): Promise<ApprovalAction[]> {
5152
return Promise.all(
@@ -55,39 +56,51 @@ export function getApprovalActions(
5556
index === insufficientApprovals.length - 1 ||
5657
insufficientApprovals[index + 1].token !== approval.token
5758
)
58-
.map(async ({ token, operator, itemType, identifierOrCriteria }) => {
59-
if (isErc721Item(itemType) || isErc1155Item(itemType)) {
60-
// setApprovalForAll check is the same for both ERC721 and ERC1155, defaulting to ERC721
61-
const contract = new Contract(token, ERC721ABI, signer) as ERC721;
59+
.map(
60+
async ({
61+
token,
62+
operator,
63+
itemType,
64+
identifierOrCriteria,
65+
requiredApprovedAmount,
66+
}) => {
67+
const isErc1155 = isErc1155Item(itemType);
68+
if (isErc721Item(itemType) || isErc1155) {
69+
// setApprovalForAll check is the same for both ERC721 and ERC1155, defaulting to ERC721
70+
const contract = new Contract(token, ERC721ABI, signer) as ERC721;
6271

63-
return {
64-
type: "approval",
65-
token,
66-
identifierOrCriteria,
67-
itemType,
68-
operator,
69-
transactionMethods: getTransactionMethods(
70-
contract.connect(signer),
71-
"setApprovalForAll",
72-
[operator, true]
73-
),
74-
};
75-
} else {
76-
const contract = new Contract(token, ERC20ABI, signer) as ERC20;
72+
return {
73+
type: "approval",
74+
token,
75+
identifierOrCriteria,
76+
itemType,
77+
operator,
78+
transactionMethods: getTransactionMethods(
79+
contract.connect(signer),
80+
exactApproval && !isErc1155 ? "approve" : "setApprovalForAll",
81+
[
82+
operator,
83+
exactApproval && !isErc1155 ? identifierOrCriteria : true,
84+
]
85+
),
86+
};
87+
} else {
88+
const contract = new Contract(token, ERC20ABI, signer) as ERC20;
7789

78-
return {
79-
type: "approval",
80-
token,
81-
identifierOrCriteria,
82-
itemType,
83-
transactionMethods: getTransactionMethods(
84-
contract.connect(signer),
85-
"approve",
86-
[operator, MAX_INT]
87-
),
88-
operator,
89-
};
90+
return {
91+
type: "approval",
92+
token,
93+
identifierOrCriteria,
94+
itemType,
95+
transactionMethods: getTransactionMethods(
96+
contract.connect(signer),
97+
"approve",
98+
[operator, exactApproval ? requiredApprovedAmount : MAX_INT]
99+
),
100+
operator,
101+
};
102+
}
90103
}
91-
})
104+
)
92105
);
93106
}

0 commit comments

Comments
 (0)