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,276 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
5
+ import "@openzeppelin/contracts/access/Ownable.sol";
6
+ import "./utils/RLPReader.sol";
7
+ import "./interfaces/IUnlockStrategy.sol";
8
+ import "./coinbase-and-stake/invokeCoinbase.sol";
9
+
10
+ contract ChainYVaultV2CB is CoinbaseOperator, ReentrancyGuard, Ownable {
11
+ using RLPReader for bytes;
12
+ using RLPReader for RLPReader.RLPItem;
13
+
14
+ struct AuctionConfig {
15
+ uint32 auctionType; // 4字节竞标类型: 0000 || 00 || 00 竞价方式||单次||公开竞标
16
+ uint256 baseAmount; // 基础金额
17
+ bool isSystemExpiration; // 是否系统时间
18
+ bool isActive; // 是否激活
19
+ }
20
+
21
+ struct Auction {
22
+ uint32 auctionType; // 应该和config保持一致
23
+ uint256 baseAmount; // 基础金额
24
+ uint256 revealTime; // 揭示时间
25
+ }
26
+
27
+ struct AuctionLock {
28
+ address owner;
29
+ bytes32 hashSecret;
30
+ uint256 amount;
31
+ uint32 auctionType; // 4字节竞标类型
32
+ bool isLocked;
33
+ bool secretRevealed;
34
+ uint256 revealTime; // 揭示时间
35
+ uint256 auctionId; // 竞标ID
36
+ }
37
+
38
+ uint256 public activeAuctionsCount;
39
+ uint256 public activeConfigsCount;
40
+ uint256 public onlyOneAuction;
41
+
42
+ mapping(bytes32 => AuctionLock) public lockedTokens;
43
+ mapping(uint256 => AuctionConfig) public auctionConfigs;
44
+ mapping(uint32 => address) public unlockStrategies;
45
+ mapping(uint256 => Auction) public auctions;
46
+
47
+ event AuctionConfigCreated(
48
+ uint256 indexed configId,
49
+ uint32 auctionType,
50
+ uint256 baseAmount,
51
+ uint256 extension
52
+ );
53
+
54
+ event AuctionCreated(
55
+ uint256 indexed auctionId,
56
+ uint32 auctionType,
57
+ uint256 nounce,
58
+ uint256 revealTime
59
+ );
60
+
61
+ event TokensLocked(
62
+ bytes32 indexed lockId,
63
+ address indexed owner,
64
+ uint256 amount,
65
+ uint32 auctionType,
66
+ uint256 auctionId
67
+ );
68
+
69
+ event TokensUnlocked(
70
+ bytes32 indexed lockId,
71
+ address indexed recipient,
72
+ uint256 amount
73
+ );
74
+
75
+ event UnlockStrategyUpdated(uint32 indexed auctionType, address strategy);
76
+
77
+ constructor() ReentrancyGuard() Ownable(msg.sender) {}
78
+
79
+ function isSingleAuction(uint32 auctionType) internal pure returns (bool) {
80
+ return (auctionType & 0x0000FF00) == 0;
81
+ }
82
+
83
+ function setUnlockStrategy(uint32 auctionType, address strategy) external onlyOwner {
84
+ require(strategy != address(0), "Invalid strategy address");
85
+ unlockStrategies[auctionType] = strategy;
86
+ emit UnlockStrategyUpdated(auctionType, strategy);
87
+ }
88
+
89
+ function createAuctionConfig(
90
+ uint32 auctionType,
91
+ uint256 baseAmount,
92
+ uint256 extension
93
+ ) external onlyOwner {
94
+ uint256 configId = activeConfigsCount;
95
+ auctionConfigs[configId] = AuctionConfig({
96
+ auctionType: auctionType,
97
+ baseAmount: baseAmount,
98
+ isSystemExpiration: false,
99
+ isActive: true
100
+ });
101
+ activeConfigsCount++;
102
+ emit AuctionConfigCreated(configId, auctionType, baseAmount, extension);
103
+ }
104
+
105
+ function getTodayEndTimestamp() public view returns (uint256) {
106
+ // 获取当前时间戳
107
+ uint256 timestamp = block.timestamp;
108
+
109
+ // 计算当天结束时间 (UTC 23:59:59)
110
+ // 1 天 = 86400 秒
111
+ // 将时间戳除以86400得到天数,加1后乘以86400得到下一天的开始
112
+ // 然后减去1秒得到当天的结束时间
113
+ return ((timestamp / 86400) * 86400) + 86400 - 1;
114
+ }
115
+
116
+ function createAuction(
117
+ uint256 configId,
118
+ bytes32 hashSecret,
119
+ uint256 expiration
120
+ ) external payable nonReentrant returns (bytes32 lockId) {
121
+ AuctionConfig memory config = auctionConfigs[configId];
122
+ require(config.isActive, "Auction not active");
123
+
124
+ Auction memory auction = auctions[onlyOneAuction];
125
+ if (!isSingleAuction(auction.auctionType)) {
126
+ require(auction.revealTime < block.timestamp, "Only one auction is allowed");
127
+ }
128
+
129
+ // 生成唯一的 auctionId
130
+ uint256 auctionId = uint256(keccak256(abi.encodePacked(
131
+ msg.sender,
132
+ block.chainid,
133
+ address(this),
134
+ activeAuctionsCount
135
+ )));
136
+
137
+ uint32 auctionType = config.auctionType;
138
+ uint256 revealTime = isSingleAuction(auctionType) && !config.isSystemExpiration ?
139
+ expiration : getTodayEndTimestamp();
140
+
141
+ onlyOneAuction = isSingleAuction(config.auctionType) ? onlyOneAuction : auctionId;
142
+
143
+ auctions[auctionId] = Auction({
144
+ auctionType: auctionType,
145
+ baseAmount: config.baseAmount,
146
+ revealTime: revealTime
147
+ });
148
+
149
+ lockId = lockTokens(hashSecret, auctionId);
150
+ activeAuctionsCount++;
151
+
152
+ emit AuctionCreated(auctionId, auctionType, activeAuctionsCount-1, revealTime);
153
+ }
154
+
155
+ function lockTokens(
156
+ bytes32 hashSecret,
157
+ uint256 auctionId
158
+ ) public payable nonReentrant returns (bytes32 lockId) {
159
+ Auction storage auction = auctions[auctionId];
160
+ uint32 auctionType = auction.auctionType;
161
+ require(auctionType != 0, "Auction not exist");
162
+ require(msg.value > 0, "Amount must be greater than 0");
163
+ require(msg.value % auction.baseAmount == 0, "Amount must be multiple of baseAmount");
164
+
165
+ lockId = keccak256(abi.encodePacked(
166
+ block.chainid,
167
+ address(this),
168
+ auctionId,
169
+ msg.sender,
170
+ hashSecret,
171
+ auctionType
172
+ ));
173
+
174
+ require(!lockedTokens[lockId].isLocked, "Lock ID exists");
175
+
176
+ lockedTokens[lockId] = AuctionLock({
177
+ owner: msg.sender,
178
+ hashSecret: hashSecret,
179
+ amount: msg.value,
180
+ auctionType: auctionType,
181
+ isLocked: true,
182
+ secretRevealed: false,
183
+ revealTime: auction.revealTime,
184
+ auctionId: auctionId
185
+ });
186
+
187
+ emit TokensLocked(lockId, msg.sender, msg.value, auctionType, auctionId);
188
+ }
189
+
190
+ function unlockTokens(bytes32 lockId, bytes memory receipt) external nonReentrant {
191
+ AuctionLock storage lock = lockedTokens[lockId];
192
+ require(lock.isLocked, "Tokens not locked");
193
+
194
+ address strategy = unlockStrategies[lock.auctionType];
195
+ require(strategy != address(0), "No unlock strategy");
196
+
197
+ RLPReader.RLPItem[] memory items = receipt.toRlpItem().toList();
198
+ require(items.length >= 4, "Invalid receipt format");
199
+
200
+ bytes memory logs = items[3].toBytes();
201
+ RLPReader.RLPItem[] memory logItems = logs.toRlpItem().toList();
202
+ require(logItems.length > 0, "No logs found");
203
+
204
+ RLPReader.RLPItem[] memory logParts = logItems[0].toList();
205
+ require(logParts.length >= 3, "Invalid log format");
206
+
207
+ bytes32 eventTopic = bytes32(logParts[1].toUint());
208
+ bytes memory eventData = logParts[2].toBytes();
209
+
210
+ (address recipient, uint256 unlockAmount) = IUnlockStrategy(strategy).processUnlock(
211
+ eventTopic,
212
+ eventData,
213
+ lock.amount
214
+ );
215
+
216
+ require(unlockAmount <= lock.amount, "Invalid unlock amount");
217
+ lock.isLocked = false;
218
+
219
+ uint256 rewardAmount = 0;
220
+ if (recipient == address(0)) {
221
+ // 竞拍者地址为0,退回给原主人
222
+ recipient = lock.owner;
223
+ rewardAmount = lock.amount;
224
+ } else if (recipient != address(this)) {
225
+ rewardAmount = unlockAmount;
226
+ }
227
+
228
+ /*
229
+ distributeRewardDirectly(
230
+ "ChainYVaultV2",
231
+ 0,
232
+ new address[](1, lock.owner),
233
+ new uint256[](1, rewardAmount)
234
+ );*/
235
+
236
+ emit TokensUnlocked(lockId, recipient, unlockAmount);
237
+ }
238
+
239
+ function getAuctionInfo(uint256 auctionId)
240
+ external
241
+ view
242
+ returns (
243
+ uint32 auctionType,
244
+ uint256 baseAmount,
245
+ uint256 revealTime
246
+ )
247
+ {
248
+ Auction storage auction = auctions[auctionId];
249
+ return (
250
+ auction.auctionType,
251
+ auction.baseAmount,
252
+ auction.revealTime
253
+ );
254
+ }
255
+
256
+ function getAuctionLockInfo(bytes32 lockId)
257
+ external
258
+ view
259
+ returns (
260
+ address owner,
261
+ uint256 amount,
262
+ bool isLocked,
263
+ uint256 revealTime
264
+ )
265
+ {
266
+ AuctionLock storage lock = lockedTokens[lockId];
267
+ return (
268
+ lock.owner,
269
+ lock.amount,
270
+ lock.isLocked,
271
+ lock.revealTime
272
+ );
273
+ }
274
+
275
+ receive() external payable {}
276
+ }
@@ -0,0 +1,318 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
5
+ import "@openzeppelin/contracts/access/Ownable.sol";
6
+ import "./utils/RLPReader.sol";
7
+ import "./interfaces/IUnlockStrategy.sol";
8
+ import "./libraries/TransactionParser.sol";
9
+ import "./coinbase-and-stake/invokeCoinbase.sol";
10
+
11
+ // CoinBaseOperator继承属性,支持Coinbase激励发放
12
+ contract ChainYVaultV2 is ReentrancyGuard, Ownable,CoinbaseOperator {
13
+ using RLPReader for bytes;
14
+ using RLPReader for RLPReader.RLPItem;
15
+
16
+ struct AuctionConfig {
17
+ uint32 auctionType; // 4字节竞标类型: 00 || 00 || 单次/多次 || 公开竞标
18
+ uint256 baseAmount; // 拍卖的最小单位金额
19
+ bool isSystemExpiration; // 是否系统时间
20
+ bool isActive; // 是否激活
21
+ }
22
+
23
+ struct Auction {
24
+ uint32 auctionType; // 应该和config保持一致
25
+ uint256 baseAmount;
26
+ uint256 revealTime; // 揭示时间
27
+ }
28
+
29
+ struct AuctionLock {
30
+ address owner;
31
+ bytes32 hashSecret;
32
+ uint256 amount;
33
+ uint32 auctionType; // 4字节竞标类型
34
+ bool isLocked;
35
+ bool secretRevealed;
36
+ uint256 revealTime; // 揭示时间
37
+ uint256 auctionId; // 竞标ID
38
+ }
39
+
40
+ uint256 public activeAuctionsCount;
41
+ uint256 public activeConfigsCount;
42
+ uint256 public onlyOneAuction;
43
+ CoinbaseOperator public coinbase;
44
+
45
+ mapping(bytes32 => AuctionLock) public lockedTokens;
46
+ mapping(uint256 => AuctionConfig) public auctionConfigs;
47
+ mapping(uint32 => address) public unlockStrategies;
48
+ mapping(uint256 => Auction) public auctions;
49
+
50
+ event AuctionConfigCreated(
51
+ uint256 indexed configId,
52
+ uint32 auctionType,
53
+ uint256 baseAmount,
54
+ uint256 extension
55
+ );
56
+
57
+ event AuctionCreated(
58
+ uint256 indexed auctionId,
59
+ uint32 auctionType,
60
+ uint256 activeAuctionCount,
61
+ uint256 revealTime
62
+ );
63
+
64
+ event TokensLocked(
65
+ bytes32 indexed lockId,
66
+ address indexed owner,
67
+ uint256 amount,
68
+ uint32 auctionType,
69
+ uint256 auctionId
70
+ );
71
+
72
+ event TokensUnlocked(
73
+ bytes32 indexed lockId,
74
+ address indexed recipient,
75
+ uint256 amount
76
+ );
77
+
78
+
79
+ constructor(address coinBaseAddress) ReentrancyGuard() Ownable(msg.sender) {
80
+ coinbase = CoinbaseOperator(coinBaseAddress);
81
+ }
82
+
83
+ function isSingleAuction(uint32 auctionType) internal pure returns (bool) {
84
+ return (auctionType & 0x0000FF00) == 0;
85
+ }
86
+
87
+ // 创建Config,创建config,createAuction创建必须指定ID
88
+ function createAuctionConfig(
89
+ uint32 auctionType,
90
+ uint256 baseAmount,
91
+ uint256 extension
92
+ ) external onlyOwner {
93
+ uint256 configId = activeConfigsCount;
94
+ auctionConfigs[configId] = AuctionConfig({
95
+ auctionType: auctionType,
96
+ baseAmount: baseAmount,
97
+ isSystemExpiration: false,
98
+ isActive: true
99
+ });
100
+ activeConfigsCount++;
101
+ emit AuctionConfigCreated(configId, auctionType, baseAmount, extension);
102
+ }
103
+
104
+ function getTodayEndTimestamp() public view returns (uint256) {
105
+ // 获取当前时间戳
106
+ uint256 timestamp = block.timestamp;
107
+
108
+ // 计算当天结束时间 (UTC 23:59:59)
109
+ // 1 天 = 86400 秒
110
+ // 将时间戳除以86400得到天数,加1后乘以86400得到下一天的开始
111
+ // 然后减去1秒得到当天的结束时间
112
+ return ((timestamp / 86400) * 86400) + 86400 - 1;
113
+ }
114
+
115
+ function createAuction(
116
+ uint256 configId,
117
+ bytes32 hashSecret, // 哈希时间锁.
118
+ uint256 expiration
119
+ ) external payable returns (bytes32 lockId) { // nonReentrant
120
+ AuctionConfig memory config = auctionConfigs[configId];
121
+ require(config.isActive, "Auction not active");
122
+
123
+ Auction memory auction = auctions[onlyOneAuction];
124
+ if (auction.baseAmount != 0 && !isSingleAuction(auction.auctionType)) {
125
+ require(auction.revealTime < block.timestamp, "Only one auction is allowed");
126
+ }
127
+
128
+ // 生成唯一的 auctionId
129
+ uint256 auctionId = uint256(keccak256(abi.encodePacked(
130
+ msg.sender,
131
+ block.chainid,
132
+ address(this),
133
+ activeAuctionsCount
134
+ )));
135
+ uint256 currentCount=activeAuctionsCount;
136
+ activeAuctionsCount++;
137
+
138
+
139
+ uint32 auctionType = config.auctionType;
140
+ uint256 revealTime = isSingleAuction(auctionType) && !config.isSystemExpiration ? expiration : getTodayEndTimestamp();
141
+
142
+ onlyOneAuction = isSingleAuction(config.auctionType) ? onlyOneAuction : auctionId;
143
+
144
+ auctions[auctionId] = Auction({
145
+ auctionType: auctionType,
146
+ baseAmount: config.baseAmount,
147
+ revealTime: revealTime
148
+ });
149
+
150
+ lockId = lockTokens(hashSecret, auctionId);
151
+ emit AuctionCreated(auctionId, auctionType, currentCount, revealTime);
152
+
153
+ }
154
+
155
+ function lockTokens(
156
+ bytes32 hashSecret,
157
+ uint256 auctionId
158
+ ) public payable nonReentrant returns (bytes32 lockId) {
159
+ Auction storage auction = auctions[auctionId];
160
+ uint32 auctionType = auction.auctionType;
161
+ require(auctionType != 0, "Auction not exist");
162
+ require(msg.value > 0, "Amount must be greater than 0");
163
+ require(msg.value % auction.baseAmount == 0, "Amount must be multiple of baseAmount");
164
+
165
+ lockId = keccak256(abi.encodePacked(
166
+ block.chainid,
167
+ address(this),
168
+ auctionId,
169
+ msg.sender,
170
+ hashSecret,
171
+ auctionType
172
+ ));
173
+
174
+ require(!lockedTokens[lockId].isLocked, "Lock ID exists");
175
+
176
+ lockedTokens[lockId] = AuctionLock({
177
+ owner: msg.sender,
178
+ hashSecret: hashSecret,
179
+ amount: msg.value,
180
+ auctionType: auctionType,
181
+ isLocked: true,
182
+ secretRevealed: false,
183
+ revealTime: auction.revealTime,
184
+ auctionId: auctionId
185
+ });
186
+
187
+ emit TokensLocked(lockId, msg.sender, msg.value, auctionType, auctionId);
188
+ }
189
+
190
+ // 接受 auction链的receipt事件才可以解锁。
191
+ // 例如: MatchResultWithdrawn(uint256,bytes32,address,uint256)
192
+ function unlockTokens(bytes32 lockId, bytes memory receipt) external nonReentrant {
193
+ AuctionLock storage lock = lockedTokens[lockId];
194
+ require(lock.isLocked, "Tokens not locked");
195
+
196
+ TransactionParser.RecptLog memory log = TransactionParser.parseRecptLog(receipt);
197
+ // 从log中解析出:中标成功者,和解锁金额
198
+ (address recipient, uint256 unlockAmount) = processUnlock(
199
+ log.eventTopic,
200
+ log.eventData,
201
+ lock.amount
202
+ );
203
+
204
+ require(unlockAmount <= lock.amount, "Invalid unlock amount");
205
+ lock.isLocked = false;
206
+
207
+ // CoinBase逻辑,通过CoinBase发送奖励
208
+ uint256 rewardAmount = 0;
209
+ if (recipient == address(0)) {
210
+ // 竞拍者地址为0,退回给原主人
211
+ recipient = lock.owner;
212
+ rewardAmount = lock.amount;
213
+ } else if (recipient != address(this)) {
214
+ rewardAmount = unlockAmount;
215
+ }
216
+
217
+ if (address(coinbase) == address(0)){
218
+ // 方法1 :直接发起转账
219
+ if (recipient == address(0)) {
220
+ // 竞拍者地址为0,退回给原主人
221
+ (bool success, ) = lock.owner.call{value: lock.amount}("");
222
+ require(success, "Transfer failed");
223
+ } else if (recipient != address(this)) {
224
+ // 直接转账
225
+ (bool success, ) = recipient.call{value: unlockAmount}("");
226
+ require(success, "Transfer failed");
227
+ }
228
+ }else{
229
+ // 方法2: CoinBase合约发放
230
+ address[] memory recipients = new address[](1);
231
+ recipients[0] = recipient; // 或 lock.owner,看你的业务
232
+ uint256[] memory amounts = new uint256[](1);
233
+ amounts[0] = rewardAmount;
234
+
235
+ // 调用CoinBase分发奖励接口
236
+ coinbase.distributeRewardDirectly(
237
+ "ChainYVaultV2",
238
+ 0, // rewardTypeId,确保 0 对应你定义的类型
239
+ recipients,
240
+ amounts
241
+ );
242
+ }
243
+ emit TokensUnlocked(lockId, recipient, unlockAmount);
244
+ }
245
+
246
+ function processUnlock(
247
+ bytes32 eventTopic,
248
+ bytes memory eventData,
249
+ uint256 lockedAmount
250
+ ) internal returns (address recipient, uint256 unlockAmount) {
251
+ // 验证事件主题是否为 MatchResultWithdrawn
252
+ require(
253
+ eventTopic == keccak256("MatchResultWithdrawn(uint256,bytes32,address,uint256)"),
254
+ "Invalid event topic"
255
+ );
256
+
257
+ // 解析事件数据
258
+ (
259
+ uint256 auctionId,
260
+ bytes32 lockId,
261
+ address bidder,
262
+ uint256 transferAmount
263
+ ) = abi.decode(eventData, (uint256, bytes32, address, uint256));
264
+
265
+ // 返回解锁信息
266
+ return (
267
+ bidder, // 接收者为中标者
268
+ transferAmount // 解锁金额为转账金额
269
+ );
270
+ }
271
+
272
+
273
+ function getAuctionInfo(uint256 auctionId)
274
+ external
275
+ view
276
+ returns (
277
+ uint32 auctionType,
278
+ uint256 baseAmount,
279
+ uint256 revealTime
280
+ )
281
+ {
282
+ Auction storage auction = auctions[auctionId];
283
+ return (
284
+ auction.auctionType,
285
+ auction.baseAmount,
286
+ auction.revealTime
287
+ );
288
+ }
289
+
290
+ function getAuctionLockInfo(bytes32 lockId)
291
+ external
292
+ view
293
+ returns (
294
+ address owner,
295
+ uint256 amount,
296
+ bool isLocked,
297
+ uint256 revealTime
298
+ )
299
+ {
300
+ AuctionLock storage lock = lockedTokens[lockId];
301
+ return (
302
+ lock.owner,
303
+ lock.amount,
304
+ lock.isLocked,
305
+ lock.revealTime
306
+ );
307
+ }
308
+
309
+ function getActiveAuctionsCount() external view returns (uint256){
310
+ return activeAuctionsCount;
311
+ }
312
+
313
+ function getActiveConfigsCount() external view returns (uint256){
314
+ return activeConfigsCount;
315
+ }
316
+
317
+ receive() external payable {}
318
+ }
@@ -0,0 +1,55 @@
1
+ ##### 两个合约的地址
2
+
3
+ ```
4
+ coinbase 合约地址:"F02F87F086a53cb793E7e920bea648bb52A7d75D"
5
+
6
+ stake 合约地址:"63BC05BC6FCAb99AF9A4c215B2e92a9C6f45D41F"
7
+ ```
8
+
9
+ ##### 合约接口说明
10
+
11
+ ```solidity
12
+ interface ICoinbase {
13
+ // 设置Coinbase合约的白名单(目前是没有限制该方法的调用者,任何人都可以设置)
14
+ function addToWhitelist(address _address) external;
15
+
16
+ // 带抽签的激励记录
17
+ function addCoinbase(
18
+ string calldata source, // 激励来源区
19
+ address[] calldata rewardAddresses,// 激励地址
20
+ string calldata rewardType, // 激励类型,质押、投票等
21
+ uint256 totalAmount, // 激励总额
22
+ uint256 numWinners // 最终可获得激励的人数
23
+ ) external;
24
+
25
+ // 不带抽签的激励记录
26
+ function addCoinbaseDirectly(
27
+ string calldata source, // 来源区
28
+ address[] calldata rewardAddresses,// 激励地址
29
+ uint256[] calldata rewardAmounts, // 每个地址对应的金额
30
+ string calldata rewardType // 激励类型
31
+ ) external;
32
+ }
33
+ ```
34
+
35
+ ```solidity
36
+ // Stake合约仅作记录,Deposit 和 Withdraw 具体方法自定义
37
+ interface IStake {
38
+ // 单地址的提现:用于大额提现,不会经过抽签
39
+ function withdraw(
40
+ string calldata source, // 来源区
41
+ address account, // 提现地址
42
+ uint256 amount // 提现金额
43
+ ) external;
44
+
45
+ // 多地址的提现:用于小额提现,会经过抽签
46
+ function withdrawMultiple(
47
+ string calldata source, // 来源区
48
+ address[] calldata accounts, // 提现地址
49
+ uint256[] calldata amounts // 每个提现地址对应的金额
50
+ ) external;
51
+
52
+ // 设置Stake合约的白名单(目前是没有限制该方法的调用者,任何人都可以设置)
53
+ function addToWhitelist(address _address) external;
54
+ }
55
+ ```