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.
- package/.env +47 -0
- package/.gitmodules +3 -0
- package/README.md +158 -0
- package/config/auction.config.ts +40 -0
- package/config/env.config.ts +204 -0
- package/config/uniswap.config.ts +107 -0
- package/config/voucher.config.ts +10 -0
- package/contracts/MutiVoucher.sol +78 -0
- package/contracts/auction/ChainXAuction.sol +177 -0
- package/contracts/auction/ChainXAuctionV2.sol +672 -0
- package/contracts/auction/ChainXWrappedETH.sol +80 -0
- package/contracts/auction/ChainYLiquidityManager.sol +57 -0
- package/contracts/auction/ChainYShadowETH.sol +148 -0
- package/contracts/auction/ChainYVault.sol +195 -0
- package/contracts/auction/ChainYVaultCoinbase.sol +276 -0
- package/contracts/auction/ChainYVaultV2.sol +318 -0
- package/contracts/auction/coinbase-and-stake/README.md +55 -0
- package/contracts/auction/coinbase-and-stake/coinbase.sol +142 -0
- package/contracts/auction/coinbase-and-stake/invokeCoinbase.sol +159 -0
- package/contracts/auction/coinbase-and-stake/invokeStake.sol +82 -0
- package/contracts/auction/coinbase-and-stake/stake.sol +92 -0
- package/contracts/auction/interfaces/IUniswapV2Factory.sol +15 -0
- package/contracts/auction/interfaces/IUniswapV2Pair.sol +53 -0
- package/contracts/auction/interfaces/IUniswapV2Router02.sol +25 -0
- package/contracts/auction/interfaces/IUnlockStrategy.sol +18 -0
- package/contracts/auction/libraries/EventParser.sol +32 -0
- package/contracts/auction/libraries/TransactionParser.sol +70 -0
- package/contracts/auction/strategies/MatchResultWithdrawnStrategy.sol +33 -0
- package/contracts/auction/utils/BytesLib.sol +180 -0
- package/contracts/auction/utils/RLPReader.sol +355 -0
- package/contracts/uniswap/Create2.sol +80 -0
- package/contracts/uniswap/DynamicFee.sol +100 -0
- package/contracts/uniswap/Example.sol +35 -0
- package/contracts/uniswap/HookMiner.sol +52 -0
- package/contracts/uniswap/LimitOrder.sol +486 -0
- package/contracts/uniswap/LiquidPool.sol +179 -0
- package/contracts/uniswap/MockERC20.sol +20 -0
- package/hardhat.config.ts +35 -0
- package/ignition/modules/LimitOrder.ts +33 -0
- package/package.json +32 -0
- package/scripts/auction/deploy.ts +23 -0
- package/scripts/auction/deployCoinbase.ts +21 -0
- package/scripts/auction/deployXAuction.ts +23 -0
- package/scripts/auction/deployYVault.ts +22 -0
- package/scripts/deploy_voucher.ts +20 -0
- package/scripts/uniswap/deploy/deploy.ts +65 -0
- package/scripts/uniswap/deploy/deploy_create2.ts +11 -0
- package/scripts/uniswap/deploy/deploy_example.ts +35 -0
- package/scripts/uniswap/deploy/deploy_hooks.ts +74 -0
- package/scripts/uniswap/deploy/deploy_mockERC20.ts +42 -0
- package/scripts/uniswap/deploy/help.ts +96 -0
- package/scripts/uniswap/deploy/init.ts +70 -0
- package/src/auction/chainXAuction.ts +209 -0
- package/src/auction/chainYVault.ts +153 -0
- package/src/auction/event.ts +19 -0
- package/src/auction/serialize.ts +162 -0
- package/src/auction/type.ts +71 -0
- package/src/lib/signer.ts +20 -0
- package/src/lib/unlock.ts +14 -0
- package/src/uniswap/1-marketprice/addLiquidity.ts +80 -0
- package/src/uniswap/1-marketprice/removeLiquidity.ts +63 -0
- package/src/uniswap/1-marketprice/swap.ts +100 -0
- package/src/uniswap/2-limitorder/kill.ts +70 -0
- package/src/uniswap/2-limitorder/place.ts +93 -0
- package/src/uniswap/2-limitorder/withdraw.ts +78 -0
- package/src/uniswap/3-dynamicfee/dynamicfee.ts +321 -0
- package/src/uniswap/lib/ERC20.ts +49 -0
- package/src/uniswap/lib/contract.ts +18 -0
- package/src/uniswap/lib/limitOrder.ts +40 -0
- package/src/uniswap/lib/liqCalculation.ts +152 -0
- package/src/uniswap/lib/listen.ts +57 -0
- package/src/uniswap/lib/pool.ts +62 -0
- package/src/uniswap/lib/swap.ts +8 -0
- package/src/uniswap/lib/types.ts +21 -0
- package/src/uniswap/lib/utils.ts +26 -0
- package/src/uniswap/playgroud/abiencode.ts +21 -0
- package/src/uniswap/playgroud/amount0.ts +47 -0
- package/src/uniswap/playgroud/errordecode.ts +54 -0
- package/src/uniswap/playgroud/errorsigs.ts +86 -0
- package/src/voucher.ts +122 -0
- package/test/auction/ChainXAuctionV2.test.ts +265 -0
- package/test/auction/ChainYVaultV2.test.js +163 -0
- package/test/auction/ChainYVaultV2.test.ts +183 -0
- package/test/auction/auction.test.ts +106 -0
- package/test/connect_punk.test.ts +26 -0
- package/test/create2.test.ts +44 -0
- package/test/normal.ts +43 -0
- package/test/test-config.ts +18 -0
- package/test/uniswap/example.test.ts +62 -0
- package/test/uniswap/limitOrder.test.ts +184 -0
- package/test/uniswap/mockERC20.test.ts +142 -0
- package/test/voucher_hardhat.test.ts +120 -0
- package/test/voucher_punk.test.ts +83 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
contract Coinbase {
|
|
5
|
+
// 白名单mapping
|
|
6
|
+
mapping(address => bool) public whitelist;
|
|
7
|
+
|
|
8
|
+
// 硬编码的mapping地址
|
|
9
|
+
address public constant STAKING_ADDRESS = 0x63BC05BC6FCAb99AF9A4c215B2e92a9C6f45D41F;
|
|
10
|
+
|
|
11
|
+
// 构造函数中初始化硬编码地址到白名单
|
|
12
|
+
constructor() {
|
|
13
|
+
whitelist[STAKING_ADDRESS] = true;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 事件定义
|
|
17
|
+
event CoinbaseAdded(
|
|
18
|
+
string indexed source, // 来源区 string类型
|
|
19
|
+
string indexed rewardType, // 奖励类型(如:挖矿、质押、投票等)
|
|
20
|
+
uint256 indexed timestamp,
|
|
21
|
+
address[] selectedAddresses, // 奖励地址
|
|
22
|
+
uint256[] rewards // 奖励金额
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// 检查白名单的modifier
|
|
26
|
+
modifier onlyWhitelisted() {
|
|
27
|
+
require(whitelist[msg.sender], "Caller is not whitelisted");
|
|
28
|
+
_;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 添加白名单地址
|
|
32
|
+
function addToWhitelist(address _address) public {
|
|
33
|
+
require(_address != address(0), "Invalid address");
|
|
34
|
+
whitelist[_address] = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 选择随机地址的内部函数 : "Fisher-Yates洗牌算法"的变体
|
|
38
|
+
function _selectRandomAddresses(address[] memory addresses, uint256 numToSelect)
|
|
39
|
+
internal view returns (address[] memory) {
|
|
40
|
+
require(numToSelect <= addresses.length, "Cannot select more addresses than provided");
|
|
41
|
+
|
|
42
|
+
address[] memory selectedAddresses = new address[](numToSelect);
|
|
43
|
+
address[] memory tempAddresses = new address[](addresses.length);
|
|
44
|
+
|
|
45
|
+
// 复制地址数组
|
|
46
|
+
for(uint i = 0; i < addresses.length; i++) {
|
|
47
|
+
tempAddresses[i] = addresses[i];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 随机选择地址
|
|
51
|
+
for(uint i = 0; i < numToSelect; i++) {
|
|
52
|
+
// 1. 生成随机索引:范围是从0到未处理的地址数量
|
|
53
|
+
// block.prevrandao 经过修改后可获取共识传来的随机数
|
|
54
|
+
uint256 randomIndex = block.prevrandao % (tempAddresses.length - i);
|
|
55
|
+
|
|
56
|
+
// 2. 将随机选中的地址保存到结果数组
|
|
57
|
+
selectedAddresses[i] = tempAddresses[randomIndex];
|
|
58
|
+
|
|
59
|
+
// 3. 将已选中的地址与数组末尾未选择的地址交换
|
|
60
|
+
tempAddresses[randomIndex] = tempAddresses[tempAddresses.length - 1 - i];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return selectedAddresses;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 添加coinbase奖励(带抽签)
|
|
67
|
+
function addCoinbase(
|
|
68
|
+
string calldata source, // 新增 source 参数,类型为 string
|
|
69
|
+
address[] calldata rewardAddresses,
|
|
70
|
+
string calldata rewardType,
|
|
71
|
+
uint256 totalAmount,
|
|
72
|
+
uint256 numWinners // 抽签人数
|
|
73
|
+
) external onlyWhitelisted {
|
|
74
|
+
require(rewardAddresses.length > 0, "No addresses provided");
|
|
75
|
+
require(numWinners > 0 && numWinners <= rewardAddresses.length, "Invalid number of winners");
|
|
76
|
+
|
|
77
|
+
// 随机选择获奖地址
|
|
78
|
+
address[] memory selectedAddresses = _selectRandomAddresses(rewardAddresses, numWinners);
|
|
79
|
+
|
|
80
|
+
// 计算奖励比例
|
|
81
|
+
uint256[] memory rewards = new uint256[](numWinners);
|
|
82
|
+
uint256 remainingAmount = totalAmount;
|
|
83
|
+
|
|
84
|
+
// 按抽签顺序分配不同比例的奖励
|
|
85
|
+
// 第一名获得剩余金额的50%
|
|
86
|
+
// 第二名获得剩余金额的30%
|
|
87
|
+
// 其余平分剩下的金额
|
|
88
|
+
if(numWinners >= 1) {
|
|
89
|
+
rewards[0] = remainingAmount * 50 / 100; // 第一名50%
|
|
90
|
+
remainingAmount -= rewards[0];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if(numWinners >= 2) {
|
|
94
|
+
rewards[1] = remainingAmount * 30 / 100; // 第二名30%
|
|
95
|
+
remainingAmount -= rewards[1];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if(numWinners > 2) {
|
|
99
|
+
uint256 rewardPerRemaining = remainingAmount / (numWinners - 2);
|
|
100
|
+
for(uint i = 2; i < numWinners; i++) {
|
|
101
|
+
rewards[i] = rewardPerRemaining;
|
|
102
|
+
remainingAmount -= rewardPerRemaining;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 如果有余数,将余数加到第一名的奖励中
|
|
107
|
+
if(remainingAmount > 0) {
|
|
108
|
+
rewards[0] += remainingAmount;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 触发事件
|
|
112
|
+
emit CoinbaseAdded(
|
|
113
|
+
source, // 使用传入的 source
|
|
114
|
+
rewardType,
|
|
115
|
+
block.timestamp,
|
|
116
|
+
selectedAddresses,
|
|
117
|
+
rewards
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 添加coinbase奖励(不需要抽签)
|
|
122
|
+
function addCoinbaseDirectly(
|
|
123
|
+
string calldata source, // 新增 source 参数,类型为 string
|
|
124
|
+
address[] calldata rewardAddresses,
|
|
125
|
+
uint256[] calldata rewardAmounts,
|
|
126
|
+
string calldata rewardType
|
|
127
|
+
) external onlyWhitelisted {
|
|
128
|
+
require(rewardAddresses.length > 0, "No addresses provided");
|
|
129
|
+
require(rewardAddresses.length == rewardAmounts.length, "Arrays length mismatch");
|
|
130
|
+
|
|
131
|
+
emit CoinbaseAdded(
|
|
132
|
+
source, // 使用传入的 source
|
|
133
|
+
rewardType,
|
|
134
|
+
block.timestamp,
|
|
135
|
+
rewardAddresses,
|
|
136
|
+
rewardAmounts
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
interface ICoinbase {
|
|
5
|
+
function addToWhitelist(address _address) external;
|
|
6
|
+
|
|
7
|
+
function addCoinbase(
|
|
8
|
+
string calldata source,
|
|
9
|
+
address[] calldata rewardAddresses,
|
|
10
|
+
string calldata rewardType,
|
|
11
|
+
uint256 totalAmount,
|
|
12
|
+
uint256 numWinners
|
|
13
|
+
) external;
|
|
14
|
+
|
|
15
|
+
function addCoinbaseDirectly(
|
|
16
|
+
string calldata source,
|
|
17
|
+
address[] calldata rewardAddresses,
|
|
18
|
+
uint256[] calldata rewardAmounts,
|
|
19
|
+
string calldata rewardType
|
|
20
|
+
) external;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
contract CoinbaseOperator {
|
|
24
|
+
// Coinbase合约地址
|
|
25
|
+
address public immutable COINBASE_ADDRESS = 0xF02F87F086a53cb793E7e920bea648bb52A7d75D;
|
|
26
|
+
|
|
27
|
+
// 操作者mapping
|
|
28
|
+
mapping(address => bool) public operators;
|
|
29
|
+
|
|
30
|
+
// 奖励类型枚举
|
|
31
|
+
enum RewardType {
|
|
32
|
+
STAKE,
|
|
33
|
+
MINE,
|
|
34
|
+
VOTE,
|
|
35
|
+
CUSTOM
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 自定义奖励类型结构体
|
|
39
|
+
struct CustomRewardType {
|
|
40
|
+
string name;
|
|
41
|
+
string description;
|
|
42
|
+
bool isValid;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 存储自定义奖励类型
|
|
46
|
+
mapping(uint256 => CustomRewardType) public customRewardTypes;
|
|
47
|
+
uint256 public nextCustomRewardTypeId = uint256(RewardType.CUSTOM);
|
|
48
|
+
|
|
49
|
+
// 事件
|
|
50
|
+
event OperatorAdded(address indexed operator);
|
|
51
|
+
event OperatorRemoved(address indexed operator);
|
|
52
|
+
event CustomRewardTypeAdded(uint256 indexed typeId, string name);
|
|
53
|
+
event RewardDistributed(
|
|
54
|
+
string source,
|
|
55
|
+
string rewardType,
|
|
56
|
+
uint256 totalAmount,
|
|
57
|
+
uint256 recipientCount
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// 构造函数
|
|
61
|
+
constructor() {
|
|
62
|
+
operators[msg.sender] = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 修饰符
|
|
66
|
+
modifier onlyOperator() {
|
|
67
|
+
require(operators[msg.sender], "Caller is not an operator");
|
|
68
|
+
_;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 管理操作者
|
|
72
|
+
function addOperator(address operator) external onlyOperator {
|
|
73
|
+
require(operator != address(0), "Invalid operator address");
|
|
74
|
+
operators[operator] = true;
|
|
75
|
+
emit OperatorAdded(operator);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function removeOperator(address operator) external onlyOperator {
|
|
79
|
+
operators[operator] = false;
|
|
80
|
+
emit OperatorRemoved(operator);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 增加白名单
|
|
84
|
+
function addToWhitelist(address _address) external onlyOperator {
|
|
85
|
+
ICoinbase(COINBASE_ADDRESS).addToWhitelist(_address);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 添加自定义奖励类型
|
|
89
|
+
function addCustomRewardType(
|
|
90
|
+
string calldata name,
|
|
91
|
+
string calldata description
|
|
92
|
+
) external onlyOperator returns (uint256) {
|
|
93
|
+
uint256 newTypeId = nextCustomRewardTypeId++;
|
|
94
|
+
|
|
95
|
+
customRewardTypes[newTypeId] = CustomRewardType({
|
|
96
|
+
name: name,
|
|
97
|
+
description: description,
|
|
98
|
+
isValid: true
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
emit CustomRewardTypeAdded(newTypeId, name);
|
|
102
|
+
return newTypeId;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 获取奖励类型字符串
|
|
106
|
+
function getRewardTypeString(uint256 rewardTypeId) public view returns (string memory) {
|
|
107
|
+
if (rewardTypeId == uint256(RewardType.STAKE)) return "stake";
|
|
108
|
+
if (rewardTypeId == uint256(RewardType.MINE)) return "mine";
|
|
109
|
+
if (rewardTypeId == uint256(RewardType.VOTE)) return "vote";
|
|
110
|
+
|
|
111
|
+
require(customRewardTypes[rewardTypeId].isValid, "Invalid reward type");
|
|
112
|
+
return customRewardTypes[rewardTypeId].name;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 随机抽奖分发奖励
|
|
116
|
+
function distributeRewardWithLottery(
|
|
117
|
+
string calldata source,
|
|
118
|
+
uint256 rewardTypeId,
|
|
119
|
+
address[] calldata candidates,
|
|
120
|
+
uint256 totalAmount,
|
|
121
|
+
uint256 numWinners
|
|
122
|
+
) external onlyOperator {
|
|
123
|
+
string memory rewardType = getRewardTypeString(rewardTypeId);
|
|
124
|
+
|
|
125
|
+
ICoinbase(COINBASE_ADDRESS).addCoinbase(
|
|
126
|
+
source,
|
|
127
|
+
candidates,
|
|
128
|
+
rewardType,
|
|
129
|
+
totalAmount,
|
|
130
|
+
numWinners
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
emit RewardDistributed(source, rewardType, totalAmount, numWinners);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 直接分发奖励
|
|
137
|
+
function distributeRewardDirectly(
|
|
138
|
+
string calldata source,
|
|
139
|
+
uint256 rewardTypeId,
|
|
140
|
+
address[] calldata recipients,
|
|
141
|
+
uint256[] calldata amounts
|
|
142
|
+
) external onlyOperator {
|
|
143
|
+
string memory rewardType = getRewardTypeString(rewardTypeId);
|
|
144
|
+
|
|
145
|
+
ICoinbase(COINBASE_ADDRESS).addCoinbaseDirectly(
|
|
146
|
+
source,
|
|
147
|
+
recipients,
|
|
148
|
+
amounts,
|
|
149
|
+
rewardType
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
uint256 totalAmount = 0;
|
|
153
|
+
for(uint i = 0; i < amounts.length; i++) {
|
|
154
|
+
totalAmount += amounts[i];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
emit RewardDistributed(source, rewardType, totalAmount, recipients.length);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
interface IStake {
|
|
5
|
+
function withdraw(
|
|
6
|
+
string calldata source,
|
|
7
|
+
address account,
|
|
8
|
+
uint256 amount
|
|
9
|
+
) external;
|
|
10
|
+
|
|
11
|
+
function withdrawMultiple(
|
|
12
|
+
string calldata source,
|
|
13
|
+
address[] calldata accounts,
|
|
14
|
+
uint256[] calldata amounts
|
|
15
|
+
) external;
|
|
16
|
+
|
|
17
|
+
function addToWhitelist(address _address) external;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
contract InvokeStake {
|
|
21
|
+
// Stake合约地址
|
|
22
|
+
address public immutable STAKE_ADDRESS = 0x63BC05BC6FCAb99AF9A4c215B2e92a9C6f45D41F;
|
|
23
|
+
|
|
24
|
+
// 操作者地址
|
|
25
|
+
address public owner;
|
|
26
|
+
|
|
27
|
+
// 事件
|
|
28
|
+
event SingleWithdraw(string source, address account, uint256 amount);
|
|
29
|
+
event MultipleWithdraw(string source, address[] accounts, uint256[] amounts);
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
owner = msg.sender;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
modifier onlyOwner() {
|
|
36
|
+
require(msg.sender == owner, "Only owner can call this function");
|
|
37
|
+
_;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 初始化:将本合约添加到stake合约的白名单中
|
|
41
|
+
function initialize() external onlyOwner {
|
|
42
|
+
IStake(STAKE_ADDRESS).addToWhitelist(address(this));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 增加白名单
|
|
46
|
+
function addToWhitelist(address _address) public onlyOwner {
|
|
47
|
+
IStake(STAKE_ADDRESS).addToWhitelist(_address);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 单地址提现示例
|
|
51
|
+
function singleWithdrawExample(
|
|
52
|
+
string calldata source,
|
|
53
|
+
address account,
|
|
54
|
+
uint256 amount
|
|
55
|
+
) external onlyOwner {
|
|
56
|
+
// 调用stake合约的withdraw方法
|
|
57
|
+
IStake(STAKE_ADDRESS).withdraw(
|
|
58
|
+
source,
|
|
59
|
+
account,
|
|
60
|
+
amount
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
emit SingleWithdraw(source, account, amount);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 多地址提现示例
|
|
67
|
+
function multipleWithdrawExample(
|
|
68
|
+
string calldata source,
|
|
69
|
+
address[] calldata accounts,
|
|
70
|
+
uint256[] calldata amounts
|
|
71
|
+
) external onlyOwner {
|
|
72
|
+
// 调用stake合约的withdrawMultiple方法
|
|
73
|
+
IStake(STAKE_ADDRESS).withdrawMultiple(
|
|
74
|
+
source,
|
|
75
|
+
accounts,
|
|
76
|
+
amounts
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
emit MultipleWithdraw(source, accounts, amounts);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
// 修改 Coinbase 合约的接口
|
|
5
|
+
interface ICoinbase {
|
|
6
|
+
function addCoinbaseDirectly(
|
|
7
|
+
string calldata source,
|
|
8
|
+
address[] calldata rewardAddresses,
|
|
9
|
+
uint256[] calldata rewardAmounts,
|
|
10
|
+
string calldata rewardType
|
|
11
|
+
) external;
|
|
12
|
+
|
|
13
|
+
function addCoinbase(
|
|
14
|
+
string calldata source,
|
|
15
|
+
address[] calldata rewardAddresses,
|
|
16
|
+
string calldata rewardType,
|
|
17
|
+
uint256 totalAmount,
|
|
18
|
+
uint256 numWinners
|
|
19
|
+
) external;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
contract Stake {
|
|
23
|
+
// Coinbase合约地址
|
|
24
|
+
address public constant COINBASE_ADDRESS = 0xF02F87F086a53cb793E7e920bea648bb52A7d75D;
|
|
25
|
+
string public constant REWARDTYPE = "STAKE";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// 白名单mapping
|
|
29
|
+
mapping(address => bool) public whitelist;
|
|
30
|
+
|
|
31
|
+
// 检查白名单的modifier
|
|
32
|
+
modifier onlyWhitelisted() {
|
|
33
|
+
require(whitelist[msg.sender], "Caller is not whitelisted");
|
|
34
|
+
_;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 添加白名单地址
|
|
38
|
+
function addToWhitelist(address _address) public {
|
|
39
|
+
require(_address != address(0), "Invalid address");
|
|
40
|
+
whitelist[_address] = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 单地址提现函数
|
|
44
|
+
function withdraw(
|
|
45
|
+
string calldata source,
|
|
46
|
+
address account,
|
|
47
|
+
uint256 amount
|
|
48
|
+
) external onlyWhitelisted {
|
|
49
|
+
require(account != address(0), "Invalid address");
|
|
50
|
+
require(amount > 0, "Amount must be greater than 0");
|
|
51
|
+
|
|
52
|
+
// 准备参数
|
|
53
|
+
address[] memory accounts = new address[](1);
|
|
54
|
+
accounts[0] = account;
|
|
55
|
+
|
|
56
|
+
uint256[] memory amounts = new uint256[](1);
|
|
57
|
+
amounts[0] = amount;
|
|
58
|
+
|
|
59
|
+
// 调用Coinbase合约的addCoinbaseDirectly方法
|
|
60
|
+
ICoinbase(COINBASE_ADDRESS).addCoinbaseDirectly(
|
|
61
|
+
source,
|
|
62
|
+
accounts,
|
|
63
|
+
amounts,
|
|
64
|
+
REWARDTYPE
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 多地址提现函数
|
|
69
|
+
function withdrawMultiple(
|
|
70
|
+
string calldata source,
|
|
71
|
+
address[] calldata accounts,
|
|
72
|
+
uint256[] calldata amounts
|
|
73
|
+
) external onlyWhitelisted {
|
|
74
|
+
require(accounts.length > 0, "No addresses provided");
|
|
75
|
+
require(accounts.length == amounts.length, "Arrays length mismatch");
|
|
76
|
+
|
|
77
|
+
// 计算总金额
|
|
78
|
+
uint256 totalAmount = 0;
|
|
79
|
+
for(uint i = 0; i < amounts.length; i++) {
|
|
80
|
+
totalAmount += amounts[i];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 调用Coinbase合约的addCoinbase方法
|
|
84
|
+
ICoinbase(COINBASE_ADDRESS).addCoinbase(
|
|
85
|
+
source,
|
|
86
|
+
accounts,
|
|
87
|
+
REWARDTYPE,
|
|
88
|
+
totalAmount,
|
|
89
|
+
accounts.length
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
interface IUniswapV2Factory {
|
|
5
|
+
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
|
|
6
|
+
|
|
7
|
+
function feeTo() external view returns (address);
|
|
8
|
+
function feeToSetter() external view returns (address);
|
|
9
|
+
function getPair(address tokenA, address tokenB) external view returns (address pair);
|
|
10
|
+
function allPairs(uint) external view returns (address pair);
|
|
11
|
+
function allPairsLength() external view returns (uint);
|
|
12
|
+
function createPair(address tokenA, address tokenB) external returns (address pair);
|
|
13
|
+
function setFeeTo(address) external;
|
|
14
|
+
function setFeeToSetter(address) external;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
interface IUniswapV2Pair {
|
|
5
|
+
event Approval(address indexed owner, address indexed spender, uint value);
|
|
6
|
+
event Transfer(address indexed from, address indexed to, uint value);
|
|
7
|
+
|
|
8
|
+
function name() external pure returns (string memory);
|
|
9
|
+
function symbol() external pure returns (string memory);
|
|
10
|
+
function decimals() external pure returns (uint8);
|
|
11
|
+
function totalSupply() external view returns (uint);
|
|
12
|
+
function balanceOf(address owner) external view returns (uint);
|
|
13
|
+
function allowance(address owner, address spender) external view returns (uint);
|
|
14
|
+
|
|
15
|
+
function approve(address spender, uint value) external returns (bool);
|
|
16
|
+
function transfer(address to, uint value) external returns (bool);
|
|
17
|
+
function transferFrom(address from, address to, uint value) external returns (bool);
|
|
18
|
+
|
|
19
|
+
function DOMAIN_SEPARATOR() external view returns (bytes32);
|
|
20
|
+
function PERMIT_TYPEHASH() external pure returns (bytes32);
|
|
21
|
+
function nonces(address owner) external view returns (uint);
|
|
22
|
+
|
|
23
|
+
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
|
|
24
|
+
|
|
25
|
+
event Mint(address indexed sender, uint amount0, uint amount1);
|
|
26
|
+
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
|
|
27
|
+
event Swap(
|
|
28
|
+
address indexed sender,
|
|
29
|
+
uint amount0In,
|
|
30
|
+
uint amount1In,
|
|
31
|
+
uint amount0Out,
|
|
32
|
+
uint amount1Out,
|
|
33
|
+
address indexed to
|
|
34
|
+
);
|
|
35
|
+
event Sync(uint112 reserve0, uint112 reserve1);
|
|
36
|
+
|
|
37
|
+
function MINIMUM_LIQUIDITY() external pure returns (uint);
|
|
38
|
+
function factory() external view returns (address);
|
|
39
|
+
function token0() external view returns (address);
|
|
40
|
+
function token1() external view returns (address);
|
|
41
|
+
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
|
|
42
|
+
function price0CumulativeLast() external view returns (uint);
|
|
43
|
+
function price1CumulativeLast() external view returns (uint);
|
|
44
|
+
function kLast() external view returns (uint);
|
|
45
|
+
|
|
46
|
+
function mint(address to) external returns (uint liquidity);
|
|
47
|
+
function burn(address to) external returns (uint amount0, uint amount1);
|
|
48
|
+
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
|
|
49
|
+
function skim(address to) external;
|
|
50
|
+
function sync() external;
|
|
51
|
+
|
|
52
|
+
function initialize(address, address) external;
|
|
53
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
interface IUniswapV2Router02 {
|
|
5
|
+
function WETH() external pure returns (address);
|
|
6
|
+
function factory() external pure returns (address);
|
|
7
|
+
|
|
8
|
+
function addLiquidityETH(
|
|
9
|
+
address token,
|
|
10
|
+
uint amountTokenDesired,
|
|
11
|
+
uint amountTokenMin,
|
|
12
|
+
uint amountETHMin,
|
|
13
|
+
address to,
|
|
14
|
+
uint deadline
|
|
15
|
+
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
|
|
16
|
+
|
|
17
|
+
function removeLiquidityETH(
|
|
18
|
+
address token,
|
|
19
|
+
uint liquidity,
|
|
20
|
+
uint amountTokenMin,
|
|
21
|
+
uint amountETHMin,
|
|
22
|
+
address to,
|
|
23
|
+
uint deadline
|
|
24
|
+
) external returns (uint amountToken, uint amountETH);
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
interface IUnlockStrategy {
|
|
5
|
+
/**
|
|
6
|
+
* @dev 处理解锁逻辑
|
|
7
|
+
* @param eventTopic 事件的主题哈希
|
|
8
|
+
* @param eventData 事件数据
|
|
9
|
+
* @param lockedAmount 已锁定的金额
|
|
10
|
+
* @return recipient 解锁的接收者
|
|
11
|
+
* @return unlockAmount 解锁的金额
|
|
12
|
+
*/
|
|
13
|
+
function processUnlock(
|
|
14
|
+
bytes32 eventTopic,
|
|
15
|
+
bytes memory eventData,
|
|
16
|
+
uint256 lockedAmount
|
|
17
|
+
) external returns (address recipient, uint256 unlockAmount);
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
library EventParser {
|
|
5
|
+
// AuctionCreated 事件解析
|
|
6
|
+
function parseAuctionCreatedEvent(bytes memory eventData) internal view returns (
|
|
7
|
+
uint256 auctionId,
|
|
8
|
+
uint32 auctionType,
|
|
9
|
+
uint256 nonce,
|
|
10
|
+
uint256 revealTime
|
|
11
|
+
) {
|
|
12
|
+
// 验证数据长度
|
|
13
|
+
require(eventData.length == 100, "Invalid event data length"); // 3 * 32 + 4 bytes
|
|
14
|
+
|
|
15
|
+
// ! 直接使用assemly获取存在问题,改用abi.decode
|
|
16
|
+
assembly {
|
|
17
|
+
// 跳过前32字节的长度数据
|
|
18
|
+
auctionId := mload(add(eventData, 32)) // 读取 auctionId
|
|
19
|
+
auctionType := mload(add(eventData, 36)) // 读取 auctionType
|
|
20
|
+
nonce := mload(add(eventData, 68)) // 读取 nonce
|
|
21
|
+
revealTime := mload(add(eventData, 100)) // 读取 revealTime
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 验证参数有效性
|
|
25
|
+
require(auctionId != 0, "Invalid auction ID");
|
|
26
|
+
// require(nonce != 0, "Invalid nonce");
|
|
27
|
+
require(revealTime > block.timestamp, "Invalid reveal time");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 其他事件解析函数可以在这里添加... d
|
|
31
|
+
|
|
32
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import "../utils/RLPReader.sol";
|
|
5
|
+
import "hardhat/console.sol";
|
|
6
|
+
|
|
7
|
+
library TransactionParser {
|
|
8
|
+
using RLPReader for bytes;
|
|
9
|
+
using RLPReader for RLPReader.RLPItem;
|
|
10
|
+
|
|
11
|
+
struct RawTransaction {
|
|
12
|
+
uint256 nonce;
|
|
13
|
+
uint256 gasPrice;
|
|
14
|
+
uint256 gasLimit;
|
|
15
|
+
address to;
|
|
16
|
+
uint256 value;
|
|
17
|
+
bytes data;
|
|
18
|
+
uint256 v; // use full width to keep chainId info
|
|
19
|
+
bytes32 r;
|
|
20
|
+
bytes32 s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
struct RecptLog {
|
|
24
|
+
bytes32 eventTopic; // topic0: keccak256(event signature)
|
|
25
|
+
bytes32[] topics; // full topics array (topic0 + indexed fields)
|
|
26
|
+
bytes eventData; // abi-encoded non-indexed event data
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// RLP 交易解析
|
|
30
|
+
function parseRawTransaction(bytes memory rawTx) internal pure returns (RawTransaction memory) {
|
|
31
|
+
RLPReader.RLPItem[] memory items = rawTx.toRlpItem().toList();
|
|
32
|
+
require(items.length == 9, "Invalid transaction format");
|
|
33
|
+
|
|
34
|
+
return RawTransaction({
|
|
35
|
+
nonce: items[0].toUint(),
|
|
36
|
+
gasPrice: items[1].toUint(),
|
|
37
|
+
gasLimit: items[2].toUint(),
|
|
38
|
+
to: address(uint160(items[3].toUint())),
|
|
39
|
+
value: items[4].toUint(),
|
|
40
|
+
data: items[5].toBytes(),
|
|
41
|
+
v: items[6].toUint(),
|
|
42
|
+
r: bytes32(items[7].toUint()),
|
|
43
|
+
s: bytes32(items[8].toUint())
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseRecptLog(bytes memory receipt) internal pure returns (RecptLog memory) {
|
|
48
|
+
RLPReader.RLPItem[] memory items = receipt.toRlpItem().toList();
|
|
49
|
+
require(items.length >= 4, "Invalid receipt format");
|
|
50
|
+
|
|
51
|
+
bytes memory logs = items[3].toBytes();
|
|
52
|
+
RLPReader.RLPItem[] memory logItems = logs.toRlpItem().toList();
|
|
53
|
+
require(logItems.length > 0, "No logs found");
|
|
54
|
+
|
|
55
|
+
RLPReader.RLPItem[] memory logTopics = logItems[1].toList();
|
|
56
|
+
|
|
57
|
+
bytes32[] memory topics = new bytes32[](logTopics.length);
|
|
58
|
+
for (uint256 i = 0; i < logTopics.length; i++) {
|
|
59
|
+
topics[i] = bytes32(logTopics[i].toBytes());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
return RecptLog({
|
|
64
|
+
eventTopic: topics[0],
|
|
65
|
+
topics: topics,
|
|
66
|
+
eventData: logItems[2].toBytes()
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|