punkkit-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/.env +47 -0
  2. package/.gitmodules +3 -0
  3. package/README.md +158 -0
  4. package/config/auction.config.ts +40 -0
  5. package/config/env.config.ts +204 -0
  6. package/config/uniswap.config.ts +107 -0
  7. package/config/voucher.config.ts +10 -0
  8. package/contracts/MutiVoucher.sol +78 -0
  9. package/contracts/auction/ChainXAuction.sol +177 -0
  10. package/contracts/auction/ChainXAuctionV2.sol +672 -0
  11. package/contracts/auction/ChainXWrappedETH.sol +80 -0
  12. package/contracts/auction/ChainYLiquidityManager.sol +57 -0
  13. package/contracts/auction/ChainYShadowETH.sol +148 -0
  14. package/contracts/auction/ChainYVault.sol +195 -0
  15. package/contracts/auction/ChainYVaultCoinbase.sol +276 -0
  16. package/contracts/auction/ChainYVaultV2.sol +318 -0
  17. package/contracts/auction/coinbase-and-stake/README.md +55 -0
  18. package/contracts/auction/coinbase-and-stake/coinbase.sol +142 -0
  19. package/contracts/auction/coinbase-and-stake/invokeCoinbase.sol +159 -0
  20. package/contracts/auction/coinbase-and-stake/invokeStake.sol +82 -0
  21. package/contracts/auction/coinbase-and-stake/stake.sol +92 -0
  22. package/contracts/auction/interfaces/IUniswapV2Factory.sol +15 -0
  23. package/contracts/auction/interfaces/IUniswapV2Pair.sol +53 -0
  24. package/contracts/auction/interfaces/IUniswapV2Router02.sol +25 -0
  25. package/contracts/auction/interfaces/IUnlockStrategy.sol +18 -0
  26. package/contracts/auction/libraries/EventParser.sol +32 -0
  27. package/contracts/auction/libraries/TransactionParser.sol +70 -0
  28. package/contracts/auction/strategies/MatchResultWithdrawnStrategy.sol +33 -0
  29. package/contracts/auction/utils/BytesLib.sol +180 -0
  30. package/contracts/auction/utils/RLPReader.sol +355 -0
  31. package/contracts/uniswap/Create2.sol +80 -0
  32. package/contracts/uniswap/DynamicFee.sol +100 -0
  33. package/contracts/uniswap/Example.sol +35 -0
  34. package/contracts/uniswap/HookMiner.sol +52 -0
  35. package/contracts/uniswap/LimitOrder.sol +486 -0
  36. package/contracts/uniswap/LiquidPool.sol +179 -0
  37. package/contracts/uniswap/MockERC20.sol +20 -0
  38. package/hardhat.config.ts +35 -0
  39. package/ignition/modules/LimitOrder.ts +33 -0
  40. package/package.json +32 -0
  41. package/scripts/auction/deploy.ts +23 -0
  42. package/scripts/auction/deployCoinbase.ts +21 -0
  43. package/scripts/auction/deployXAuction.ts +23 -0
  44. package/scripts/auction/deployYVault.ts +22 -0
  45. package/scripts/deploy_voucher.ts +20 -0
  46. package/scripts/uniswap/deploy/deploy.ts +65 -0
  47. package/scripts/uniswap/deploy/deploy_create2.ts +11 -0
  48. package/scripts/uniswap/deploy/deploy_example.ts +35 -0
  49. package/scripts/uniswap/deploy/deploy_hooks.ts +74 -0
  50. package/scripts/uniswap/deploy/deploy_mockERC20.ts +42 -0
  51. package/scripts/uniswap/deploy/help.ts +96 -0
  52. package/scripts/uniswap/deploy/init.ts +70 -0
  53. package/src/auction/chainXAuction.ts +209 -0
  54. package/src/auction/chainYVault.ts +153 -0
  55. package/src/auction/event.ts +19 -0
  56. package/src/auction/serialize.ts +162 -0
  57. package/src/auction/type.ts +71 -0
  58. package/src/lib/signer.ts +20 -0
  59. package/src/lib/unlock.ts +14 -0
  60. package/src/uniswap/1-marketprice/addLiquidity.ts +80 -0
  61. package/src/uniswap/1-marketprice/removeLiquidity.ts +63 -0
  62. package/src/uniswap/1-marketprice/swap.ts +100 -0
  63. package/src/uniswap/2-limitorder/kill.ts +70 -0
  64. package/src/uniswap/2-limitorder/place.ts +93 -0
  65. package/src/uniswap/2-limitorder/withdraw.ts +78 -0
  66. package/src/uniswap/3-dynamicfee/dynamicfee.ts +321 -0
  67. package/src/uniswap/lib/ERC20.ts +49 -0
  68. package/src/uniswap/lib/contract.ts +18 -0
  69. package/src/uniswap/lib/limitOrder.ts +40 -0
  70. package/src/uniswap/lib/liqCalculation.ts +152 -0
  71. package/src/uniswap/lib/listen.ts +57 -0
  72. package/src/uniswap/lib/pool.ts +62 -0
  73. package/src/uniswap/lib/swap.ts +8 -0
  74. package/src/uniswap/lib/types.ts +21 -0
  75. package/src/uniswap/lib/utils.ts +26 -0
  76. package/src/uniswap/playgroud/abiencode.ts +21 -0
  77. package/src/uniswap/playgroud/amount0.ts +47 -0
  78. package/src/uniswap/playgroud/errordecode.ts +54 -0
  79. package/src/uniswap/playgroud/errorsigs.ts +86 -0
  80. package/src/voucher.ts +122 -0
  81. package/test/auction/ChainXAuctionV2.test.ts +265 -0
  82. package/test/auction/ChainYVaultV2.test.js +163 -0
  83. package/test/auction/ChainYVaultV2.test.ts +183 -0
  84. package/test/auction/auction.test.ts +106 -0
  85. package/test/connect_punk.test.ts +26 -0
  86. package/test/create2.test.ts +44 -0
  87. package/test/normal.ts +43 -0
  88. package/test/test-config.ts +18 -0
  89. package/test/uniswap/example.test.ts +62 -0
  90. package/test/uniswap/limitOrder.test.ts +184 -0
  91. package/test/uniswap/mockERC20.test.ts +142 -0
  92. package/test/voucher_hardhat.test.ts +120 -0
  93. package/test/voucher_punk.test.ts +83 -0
  94. package/tsconfig.json +11 -0
@@ -0,0 +1,33 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import "../interfaces/IUnlockStrategy.sol";
5
+
6
+ // 直接迁移到ChianYVault中实现,该合约弃用
7
+ contract MatchResultWithdrawnStrategy is IUnlockStrategy {
8
+ function processUnlock(
9
+ bytes32 eventTopic,
10
+ bytes memory eventData,
11
+ uint256 lockedAmount
12
+ ) external pure override returns (address recipient, uint256 unlockAmount) {
13
+ // 验证事件主题是否为 MatchResultWithdrawn
14
+ require(
15
+ eventTopic == keccak256("MatchResultWithdrawn(uint256,bytes32,address,uint256)"),
16
+ "Invalid event topic"
17
+ );
18
+
19
+ // 解析事件数据
20
+ (
21
+ uint256 auctionId,
22
+ bytes32 lockId,
23
+ address bidder,
24
+ uint256 transferAmount
25
+ ) = abi.decode(eventData, (uint256, bytes32, address, uint256));
26
+
27
+ // 返回解锁信息
28
+ return (
29
+ bidder, // 接收者为中标者
30
+ transferAmount // 解锁金额为转账金额
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,180 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.10;
3
+
4
+ library BytesLib {
5
+
6
+ function reverseBytes32(bytes32 input) public pure returns (bytes32) {
7
+ bytes32 output;
8
+ assembly {
9
+ let outputPtr := add(output, 0x20)
10
+ for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
11
+ mstore8(add(outputPtr, sub(31, i)), byte(i, input))
12
+ }
13
+ }
14
+ return output;
15
+ }
16
+
17
+ // ref: https://ethereum.stackexchange.com/questions/83626/how-to-reverse-byte-order-in-uint256-or-bytes32
18
+ function reverse(bytes32 input) internal pure returns (bytes32 v) {
19
+ v = input;
20
+
21
+ // swap bytes
22
+ v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
23
+ ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
24
+
25
+ // swap 2-byte long pairs
26
+ v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
27
+ ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
28
+
29
+ // swap 4-byte long pairs
30
+ v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) |
31
+ ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
32
+
33
+ // swap 8-byte long pairs
34
+ v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) |
35
+ ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
36
+
37
+ // swap 16-byte long pairs
38
+ v = (v >> 128) | (v << 128);
39
+ }
40
+
41
+ function slice(bytes memory data, uint start, uint len) internal pure returns (bytes memory) {
42
+ bytes memory result = new bytes(len);
43
+ assembly {
44
+ let dataPtr := add(data, 0x20)
45
+ let resultPtr := add(result, 0x20)
46
+ for { let i := 0 } lt(i, len) { i := add(i, 0x20) } {
47
+ mstore(add(resultPtr, i), mload(add(dataPtr, add(start, i))))
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+
53
+ function slice32(bytes memory data, uint start) internal pure returns (bytes32) {
54
+ require(start + 32 <= data.length, "slice32: out of bounds");
55
+
56
+ bytes32 result;
57
+ assembly {
58
+ let dataPtr := add(data, 0x20)
59
+ result := mload(add(dataPtr, start))
60
+ }
61
+ return result;
62
+ }
63
+
64
+ function toUint32(bytes memory b) internal pure returns (uint32) {
65
+ require(b.length == 4, "Invalid input length");
66
+
67
+ uint32 value;
68
+ assembly {
69
+ value := mload(add(b, 0x04))
70
+ }
71
+ return value;
72
+ }
73
+
74
+ function toUint64(bytes memory b) internal pure returns (uint64) {
75
+ require(b.length == 8, "Invalid input length");
76
+
77
+ uint64 value;
78
+ assembly {
79
+ value := mload(add(b, 0x08))
80
+ }
81
+ return value;
82
+ }
83
+
84
+ function bytesToUint(bytes memory b) internal pure returns (uint256){
85
+ uint256 number;
86
+ for(uint i = 0; i < b.length; i++){
87
+ number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1))));
88
+ }
89
+ return number;
90
+ }
91
+
92
+ function reverseBytes(bytes memory input) internal pure returns (bytes memory) {
93
+ bytes memory output = new bytes(input.length);
94
+ assembly {
95
+ let len := mload(input)
96
+ let inputPtr := add(input, 0x20)
97
+ let outputPtr := add(output, 0x20)
98
+ for { let i := 0 } lt(i, len) { i := add(i, 0x20) } {
99
+ mstore(add(outputPtr, sub(sub(len, i), 0x20)), mload(add(inputPtr, i)))
100
+ }
101
+ }
102
+ return output;
103
+ }
104
+
105
+ function toBytes32(bytes memory b) internal pure returns (bytes32) {
106
+ bytes32 out;
107
+ assembly {
108
+ out := mload(add(b, 0x20))
109
+ }
110
+ return out;
111
+ }
112
+
113
+ function toBytes(bytes32 _data) internal pure returns (bytes memory) {
114
+ return abi.encodePacked(_data);
115
+ }
116
+
117
+ function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
118
+ bool success = true;
119
+
120
+ assembly {
121
+ let length := mload(_preBytes)
122
+
123
+ // if lengths don't match the arrays are not equal
124
+ switch eq(length, mload(_postBytes))
125
+ case 1 {
126
+ // cb is a circuit breaker in the for loop since there's
127
+ // no said feature for inline assembly loops
128
+ // cb = 1 - don't breaker
129
+ // cb = 0 - break
130
+ let cb := 1
131
+
132
+ let mc := add(_preBytes, 0x20)
133
+ let end := add(mc, length)
134
+
135
+ for {
136
+ let cc := add(_postBytes, 0x20)
137
+ // the next line is the loop condition:
138
+ // while(uint256(mc < end) + cb == 2)
139
+ } eq(add(lt(mc, end), cb), 2) {
140
+ mc := add(mc, 0x20)
141
+ cc := add(cc, 0x20)
142
+ } {
143
+ // if any of these checks fails then arrays are not equal
144
+ if iszero(eq(mload(mc), mload(cc))) {
145
+ // unsuccess:
146
+ success := 0
147
+ cb := 0
148
+ }
149
+ }
150
+ }
151
+ default {
152
+ // unsuccess:
153
+ success := 0
154
+ }
155
+ }
156
+
157
+ return success;
158
+ }
159
+
160
+ /*
161
+ * @notice Converts a little endian (LE) byte array of size 32 to big endian (BE), i.e., flips byte order
162
+ * @param bytesLE To be flipped LE byte array
163
+ * @return bytes32 BE representation of parsed bytesLE
164
+ */
165
+ function flipBytes(bytes memory bytesLE) internal pure returns (bytes memory) {
166
+ bytes memory bytesBE = new bytes(bytesLE.length);
167
+ for (uint i = 0; i < bytesLE.length; i++){
168
+ bytesBE[bytesLE.length - i - 1] = bytesLE[i];
169
+ }
170
+ return bytesBE;
171
+ }
172
+
173
+ function flipBytes32(bytes32 bytesLE) internal pure returns (bytes32) {
174
+ bytes memory bytesBE = new bytes(bytesLE.length);
175
+ for (uint i = 0; i < bytesLE.length; i++){
176
+ bytesBE[bytesLE.length - i - 1] = bytesLE[i];
177
+ }
178
+ return toBytes32(bytesBE);
179
+ }
180
+ }
@@ -0,0 +1,355 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+
3
+ /*
4
+ * @author Hamdi Allam hamdi.allam97@gmail.com
5
+ * Please reach out with any questions or concerns
6
+ */
7
+ pragma solidity >=0.5.10 <0.9.0;
8
+
9
+ library RLPReader {
10
+ uint8 constant STRING_SHORT_START = 0x80;
11
+ uint8 constant STRING_LONG_START = 0xb8;
12
+ uint8 constant LIST_SHORT_START = 0xc0;
13
+ uint8 constant LIST_LONG_START = 0xf8;
14
+ uint8 constant WORD_SIZE = 32;
15
+
16
+ struct RLPItem {
17
+ uint256 len;
18
+ uint256 memPtr;
19
+ }
20
+
21
+ struct Iterator {
22
+ RLPItem item; // Item that's being iterated over.
23
+ uint256 nextPtr; // Position of the next item in the list.
24
+ }
25
+
26
+ /*
27
+ * @dev Returns the next element in the iteration. Reverts if it has not next element.
28
+ * @param self The iterator.
29
+ * @return The next element in the iteration.
30
+ */
31
+ function next(Iterator memory self) internal pure returns (RLPItem memory) {
32
+ require(hasNext(self));
33
+
34
+ uint256 ptr = self.nextPtr;
35
+ uint256 itemLength = _itemLength(ptr);
36
+ self.nextPtr = ptr + itemLength;
37
+
38
+ return RLPItem(itemLength, ptr);
39
+ }
40
+
41
+ /*
42
+ * @dev Returns true if the iteration has more elements.
43
+ * @param self The iterator.
44
+ * @return true if the iteration has more elements.
45
+ */
46
+ function hasNext(Iterator memory self) internal pure returns (bool) {
47
+ RLPItem memory item = self.item;
48
+ return self.nextPtr < item.memPtr + item.len;
49
+ }
50
+
51
+ /*
52
+ * @param item RLP encoded bytes
53
+ */
54
+ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
55
+ uint256 memPtr;
56
+ assembly {
57
+ // item 偏移 32字节,因为bytes类型前32字节为长度信息,后32字节才是具体数据
58
+ memPtr := add(item, 0x20)
59
+ }
60
+
61
+ return RLPItem(item.length, memPtr);
62
+ }
63
+
64
+ /*
65
+ * @dev Create an iterator. Reverts if item is not a list.
66
+ * @param self The RLP item.
67
+ * @return An 'Iterator' over the item.
68
+ */
69
+ function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
70
+ require(isList(self));
71
+
72
+ uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
73
+ return Iterator(self, ptr);
74
+ }
75
+
76
+ /*
77
+ * @param the RLP item.
78
+ */
79
+ function rlpLen(RLPItem memory item) internal pure returns (uint256) {
80
+ return item.len;
81
+ }
82
+
83
+ /*
84
+ * @param the RLP item.
85
+ * @return (memPtr, len) pair: location of the item's payload in memory.
86
+ */
87
+ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
88
+ uint256 offset = _payloadOffset(item.memPtr);
89
+ uint256 memPtr = item.memPtr + offset;
90
+ uint256 len = item.len - offset; // data length
91
+ return (memPtr, len);
92
+ }
93
+
94
+ /*
95
+ * @param the RLP item.
96
+ */
97
+ function payloadLen(RLPItem memory item) internal pure returns (uint256) {
98
+ (, uint256 len) = payloadLocation(item);
99
+ return len;
100
+ }
101
+
102
+ /*
103
+ * @param the RLP item containing the encoded list.
104
+ */
105
+ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
106
+ require(isList(item));
107
+
108
+ uint256 items = numItems(item);
109
+ RLPItem[] memory result = new RLPItem[](items);
110
+
111
+ uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
112
+ uint256 dataLen;
113
+ for (uint256 i = 0; i < items; i++) {
114
+ dataLen = _itemLength(memPtr);
115
+ result[i] = RLPItem(dataLen, memPtr);
116
+ memPtr = memPtr + dataLen;
117
+ }
118
+
119
+ return result;
120
+ }
121
+
122
+ // @return indicator whether encoded payload is a list. negate this function call for isData.
123
+ function isList(RLPItem memory item) internal pure returns (bool) {
124
+ if (item.len == 0) return false;
125
+
126
+ uint8 byte0;
127
+ uint256 memPtr = item.memPtr;
128
+ assembly {
129
+ byte0 := byte(0, mload(memPtr))
130
+ }
131
+
132
+ if (byte0 < LIST_SHORT_START) return false;
133
+ return true;
134
+ }
135
+
136
+ /*
137
+ * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
138
+ * @return keccak256 hash of RLP encoded bytes.
139
+ */
140
+ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
141
+ uint256 ptr = item.memPtr;
142
+ uint256 len = item.len;
143
+ bytes32 result;
144
+ assembly {
145
+ result := keccak256(ptr, len)
146
+ }
147
+ return result;
148
+ }
149
+
150
+ /*
151
+ * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
152
+ * @return keccak256 hash of the item payload.
153
+ */
154
+ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
155
+ (uint256 memPtr, uint256 len) = payloadLocation(item);
156
+ bytes32 result;
157
+ assembly {
158
+ result := keccak256(memPtr, len)
159
+ }
160
+ return result;
161
+ }
162
+
163
+ /** RLPItem conversions into data types **/
164
+
165
+ // @returns raw rlp encoding in bytes
166
+ function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
167
+ bytes memory result = new bytes(item.len);
168
+ if (result.length == 0) return result;
169
+
170
+ uint256 ptr;
171
+ assembly {
172
+ ptr := add(0x20, result)
173
+ }
174
+
175
+ copy(item.memPtr, ptr, item.len);
176
+ return result;
177
+ }
178
+
179
+ // any non-zero byte except "0x80" is considered true
180
+ function toBoolean(RLPItem memory item) internal pure returns (bool) {
181
+ require(item.len == 1);
182
+ uint256 result;
183
+ uint256 memPtr = item.memPtr;
184
+ assembly {
185
+ result := byte(0, mload(memPtr))
186
+ }
187
+
188
+ // SEE Github Issue #5.
189
+ // Summary: Most commonly used RLP libraries (i.e Geth) will encode
190
+ // "0" as "0x80" instead of as "0". We handle this edge case explicitly
191
+ // here.
192
+ if (result == 0 || result == STRING_SHORT_START) {
193
+ return false;
194
+ } else {
195
+ return true;
196
+ }
197
+ }
198
+
199
+ function toAddress(RLPItem memory item) internal pure returns (address) {
200
+ // 1 byte for the length prefix
201
+ require(item.len == 21);
202
+
203
+ return address(uint160(toUint(item)));
204
+ }
205
+
206
+ function toUint(RLPItem memory item) internal pure returns (uint256) {
207
+ require(item.len > 0 && item.len <= 33);
208
+
209
+ (uint256 memPtr, uint256 len) = payloadLocation(item);
210
+
211
+ uint256 result;
212
+ assembly {
213
+ result := mload(memPtr)
214
+
215
+ // shift to the correct location if neccesary
216
+ if lt(len, 32) {
217
+ result := div(result, exp(256, sub(32, len)))
218
+ }
219
+ }
220
+
221
+ return result;
222
+ }
223
+
224
+ // enforces 32 byte length
225
+ function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
226
+ // one byte prefix
227
+ require(item.len == 33);
228
+
229
+ uint256 result;
230
+ uint256 memPtr = item.memPtr + 1;
231
+ assembly {
232
+ result := mload(memPtr)
233
+ }
234
+
235
+ return result;
236
+ }
237
+
238
+ function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
239
+ require(item.len > 0);
240
+
241
+ (uint256 memPtr, uint256 len) = payloadLocation(item);
242
+ bytes memory result = new bytes(len);
243
+
244
+ uint256 destPtr;
245
+ assembly {
246
+ destPtr := add(0x20, result)
247
+ }
248
+
249
+ copy(memPtr, destPtr, len);
250
+ return result;
251
+ }
252
+
253
+ /*
254
+ * Private Helpers
255
+ */
256
+
257
+ // @return number of payload items inside an encoded list.
258
+ function numItems(RLPItem memory item) private pure returns (uint256) {
259
+ if (item.len == 0) return 0;
260
+
261
+ uint256 count = 0;
262
+ uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
263
+ uint256 endPtr = item.memPtr + item.len;
264
+ while (currPtr < endPtr) {
265
+ currPtr = currPtr + _itemLength(currPtr); // skip over an item
266
+ count++;
267
+ }
268
+
269
+ return count;
270
+ }
271
+
272
+ // @return entire rlp item byte length
273
+ function _itemLength(uint256 memPtr) private pure returns (uint256) {
274
+ uint256 itemLen;
275
+ uint256 byte0;
276
+ assembly {
277
+ byte0 := byte(0, mload(memPtr))
278
+ }
279
+
280
+ if (byte0 < STRING_SHORT_START) {
281
+ itemLen = 1;
282
+ } else if (byte0 < STRING_LONG_START) {
283
+ itemLen = byte0 - STRING_SHORT_START + 1;
284
+ } else if (byte0 < LIST_SHORT_START) {
285
+ assembly {
286
+ let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
287
+ memPtr := add(memPtr, 1) // skip over the first byte
288
+
289
+ /* 32 byte word size */
290
+ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
291
+ itemLen := add(dataLen, add(byteLen, 1))
292
+ }
293
+ } else if (byte0 < LIST_LONG_START) {
294
+ itemLen = byte0 - LIST_SHORT_START + 1;
295
+ } else {
296
+ assembly {
297
+ let byteLen := sub(byte0, 0xf7)
298
+ memPtr := add(memPtr, 1)
299
+
300
+ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
301
+ itemLen := add(dataLen, add(byteLen, 1))
302
+ }
303
+ }
304
+
305
+ return itemLen;
306
+ }
307
+
308
+ // @return number of bytes until the data
309
+ function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
310
+ uint256 byte0;
311
+ assembly {
312
+ byte0 := byte(0, mload(memPtr))
313
+ }
314
+
315
+ if (byte0 < STRING_SHORT_START) {
316
+ return 0;
317
+ } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
318
+ return 1;
319
+ } else if (byte0 < LIST_SHORT_START) {
320
+ // being explicit
321
+ return byte0 - (STRING_LONG_START - 1) + 1;
322
+ } else {
323
+ return byte0 - (LIST_LONG_START - 1) + 1;
324
+ }
325
+ }
326
+
327
+ /*
328
+ * @param src Pointer to source
329
+ * @param dest Pointer to destination
330
+ * @param len Amount of memory to copy from the source
331
+ */
332
+ function copy(uint256 src, uint256 dest, uint256 len) private pure {
333
+ if (len == 0) return;
334
+
335
+ // copy as many word sizes as possible
336
+ for (; len >= WORD_SIZE; len -= WORD_SIZE) {
337
+ assembly {
338
+ mstore(dest, mload(src))
339
+ }
340
+
341
+ src += WORD_SIZE;
342
+ dest += WORD_SIZE;
343
+ }
344
+
345
+ if (len > 0) {
346
+ // left over bytes. Mask is used to remove unwanted bytes from the word
347
+ uint256 mask = 256**(WORD_SIZE - len) - 1;
348
+ assembly {
349
+ let srcpart := and(mload(src), not(mask)) // zero out src
350
+ let destpart := and(mload(dest), mask) // retrieve the bytes
351
+ mstore(dest, or(destpart, srcpart))
352
+ }
353
+ }
354
+ }
355
+ }
@@ -0,0 +1,80 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.9;
3
+
4
+ import "hardhat/console.sol";
5
+
6
+ // ref: https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses
7
+ contract Create2 {
8
+ event Deploy(address addr);
9
+
10
+
11
+ function deployCreate2(bytes memory initCode) public payable returns (address newContract) {
12
+ // Note that the safeguarding function `_guard` is called as part of the overloaded function
13
+ // `deployCreate2`.
14
+ newContract = deployCreate2WithSalt({salt: _generateSalt(), initCode: initCode});
15
+ }
16
+
17
+ function deployCreate2WithSalt(bytes memory initCode, bytes32 salt) public payable returns (address newContract) {
18
+ assembly ("memory-safe") {
19
+ /**
20
+ * @param 1: amount of wei to send
21
+ * @param 2: pointer to start of code (after the length field)
22
+ * @param 3: size of code (loaded from the length field)
23
+ * @param 4: salt from function arguments
24
+ */
25
+ newContract := create2(callvalue(), add(initCode, 0x20), mload(initCode), salt)
26
+ }
27
+ console.log("Create2 deployed to:", newContract);
28
+ emit Deploy(newContract);
29
+ }
30
+
31
+ function computeCreate2Address(
32
+ bytes32 salt,
33
+ bytes32 initCodeHash,
34
+ address deployer
35
+ ) public pure returns (address computedAddress) {
36
+ assembly ("memory-safe") {
37
+ // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
38
+ // |----------------------|---------------------------------------------------------------------------|
39
+ // | initCodeHash | CCCCCCCCCCCCC...CC |
40
+ // | salt | BBBBBBBBBBBBB...BB |
41
+ // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
42
+ // | 0xFF | FF |
43
+ // |----------------------|---------------------------------------------------------------------------|
44
+ // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
45
+ // | keccak256(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
46
+ let ptr := mload(0x40)
47
+ mstore(add(ptr, 0x40), initCodeHash)
48
+ mstore(add(ptr, 0x20), salt)
49
+ mstore(ptr, deployer)
50
+ let start := add(ptr, 0x0b)
51
+ mstore8(start, 0xff)
52
+ computedAddress := keccak256(start, 85)
53
+ }
54
+ }
55
+
56
+ function _generateSalt() internal view returns (bytes32 salt) {
57
+ unchecked {
58
+ salt = keccak256(
59
+ abi.encode(
60
+ // We don't use `block.number - 256` (the maximum value on the EVM) to accommodate
61
+ // any chains that may try to reduce the amount of available historical block hashes.
62
+ // We also don't subtract 1 to mitigate any risks arising from consecutive block
63
+ // producers on a PoS chain. Therefore, we use `block.number - 32` as a reasonable
64
+ // compromise, one we expect should work on most chains, which is 1 epoch on Ethereum
65
+ // mainnet. Please note that if you use this function between the genesis block and block
66
+ // number 31, the block property `blockhash` will return zero, but the returned salt value
67
+ // `salt` will still have a non-zero value due to the hashing characteristic and the other
68
+ // remaining properties.
69
+ blockhash(block.number - 32),
70
+ block.coinbase,
71
+ block.number,
72
+ block.timestamp,
73
+ block.prevrandao,
74
+ block.chainid,
75
+ msg.sender
76
+ )
77
+ );
78
+ }
79
+ }
80
+ }