-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathexchange.order-v2.builder.ts
More file actions
155 lines (144 loc) · 4.73 KB
/
Copy pathexchange.order-v2.builder.ts
File metadata and controls
155 lines (144 loc) · 4.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import type { JsonRpcSigner } from '@ethersproject/providers';
import type { Wallet } from '@ethersproject/wallet';
import {
EIP712_DOMAIN,
PROTOCOL_NAME,
} from './exchange.order.const.ts';
import {
PROTOCOL_VERSION_V2,
ORDER_V2_STRUCTURE,
} from './exchange.order-v2.const.ts';
import type { EIP712TypedData } from './model/eip712.model.ts';
import { hashTypedData } from 'viem';
import type {
OrderV2,
OrderDataV2,
OrderHashV2,
OrderSignatureV2,
SignedOrderV2,
} from './model/order-v2.model.ts';
import { SignatureType } from './model/signature-types.model.ts';
import { generateOrderSalt } from './utils.ts';
const BYTES32_ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
export class ExchangeOrderBuilderV2 {
constructor(
private readonly contractAddress: string,
private readonly chainId: number,
private readonly signer: Wallet | JsonRpcSigner,
private readonly generateSalt = generateOrderSalt,
) {}
/**
* Build an order object including the signature.
* @param orderData
* @returns a SignedOrderV2 object (order + signature)
*/
async buildSignedOrder(orderData: OrderDataV2): Promise<SignedOrderV2> {
const order = await this.buildOrder(orderData);
const orderTypedData = this.buildOrderTypedData(order);
const orderSignature = await this.buildOrderSignature(orderTypedData);
return {
...order,
signature: orderSignature,
} as SignedOrderV2;
}
/**
* Creates an OrderV2 object from order data.
* @param orderData
* @returns an OrderV2 object (not signed)
*/
async buildOrder({
maker,
tokenId,
makerAmount,
takerAmount,
side,
signer,
signatureType,
timestamp,
metadata,
builder,
expiration,
}: OrderDataV2): Promise<OrderV2> {
if (typeof signer == 'undefined' || !signer) {
signer = maker;
}
const resolvedSignatureType = signatureType ?? SignatureType.EOA;
// For POLY_DEPOSIT_WALLET, the order's signer field is the wallet
// contract address, while the actual ECDSA signing is done by the EOA owner
if (resolvedSignatureType !== SignatureType.POLY_DEPOSIT_WALLET) {
const signerAddress = await this.signer.getAddress();
if (signer !== signerAddress) {
throw new Error('signer does not match');
}
}
return {
salt: this.generateSalt(),
maker,
signer,
tokenId,
makerAmount,
takerAmount,
side,
signatureType: resolvedSignatureType,
timestamp: timestamp ?? Date.now().toString(),
metadata: metadata ?? BYTES32_ZERO,
builder: builder ?? BYTES32_ZERO,
expiration: expiration ?? '0',
};
}
/**
* Parses an OrderV2 object to EIP712 typed data
* @param order
* @returns a EIP712TypedData object
*/
buildOrderTypedData(order: OrderV2): EIP712TypedData {
return {
primaryType: 'Order',
types: {
EIP712Domain: EIP712_DOMAIN,
Order: ORDER_V2_STRUCTURE,
},
domain: {
name: PROTOCOL_NAME,
version: PROTOCOL_VERSION_V2,
chainId: this.chainId,
verifyingContract: this.contractAddress,
},
message: {
salt: order.salt,
maker: order.maker,
signer: order.signer,
tokenId: order.tokenId,
makerAmount: order.makerAmount,
takerAmount: order.takerAmount,
side: order.side,
signatureType: order.signatureType,
timestamp: order.timestamp,
metadata: order.metadata,
builder: order.builder,
},
};
}
/**
* Generates order's signature from a EIP712TypedData object + the signer address
* @param typedData
* @returns a OrderSignatureV2 string
*/
buildOrderSignature(typedData: EIP712TypedData): Promise<OrderSignatureV2> {
delete typedData.types.EIP712Domain;
return this.signer._signTypedData(
typedData.domain,
typedData.types,
typedData.message,
);
}
/**
* Generates the hash of the order from a EIP712TypedData object.
* @param orderTypedData
* @returns a OrderHashV2 string
*/
buildOrderHash(orderTypedData: EIP712TypedData): OrderHashV2 {
const digest = hashTypedData(orderTypedData);
return digest;
}
}