区块链夺宝合约

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
pragma solidity ^0.4.23;
 
/**
 * Math operations with safety checks
 */
library SafeMath {
  function mul(uint a, uint b) internal returns (uint) {
    uint c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }
 
  function div(uint a, uint b) internal returns (uint) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }
 
  function sub(uint a, uint b) internal returns (uint) {
    assert(b <= a);
    return a - b;
  }
 
  function add(uint a, uint b) internal returns (uint) {
    uint c = a + b;
    assert(c >= a);
    return c;
  }
 
  function max64(uint64 a, uint64 b) internal constant returns (uint64) {
    return a >= b ? a : b;
  }
 
  function min64(uint64 a, uint64 b) internal constant returns (uint64) {
    return a < b ? a : b;
  }
 
  function max256(uint256 a, uint256 b) internal constant returns (uint256) {
    return a >= b ? a : b;
  }
 
  function min256(uint256 a, uint256 b) internal constant returns (uint256) {
    return a < b ? a : b;
  }
 
  function assert(bool assertion) internal {
    if (!assertion) {
      throw;
    }
  }
}
 
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
 
contract TokenERC20 {
 
    using SafeMath for uint256;
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    uint256 public totalSupply;
 
    // This creates an array with all balances
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;
 
    // This generates a public event on the blockchain that will notify clients
    event Transfer(address indexed from, address indexed to, uint256 value);
 
    // This notifies clients about the amount burnt
    event Burn(address indexed from, uint256 value);
 
    /**
     * Constructor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    function TokenERC20(
        uint256 initialSupply,
        string tokenName,
        string tokenSymbol
    ) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
        balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
    }
 
    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != 0x0);
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. They should never fail
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }
     
    function onechance_transfer(address _to, uint _value) public {
         _transfer(tx.origin,_to, _value);
    }
 
    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public {
        _transfer(msg.sender, _to, _value);
    }
 
    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` on behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }
 
    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }
 
    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
        public
        returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }
 
    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }
 
    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        emit Burn(_from, _value);
        return true;
    }
}
 
contract OneChance {
    
    using SafeMath for uint;
    address public sponsor;
     
    modifier onlySponsor() {
        if (msg.sender != sponsor) throw;
        _;
    }
     
    event PostGoods(uint goodsId, string goodsUuid); // 商品发布成功通知:已发布多少件商品(商品编号),商品uuid编号
    event DelGoods(uint goodsId,bool isActive);//删除商品事件:商品编号,商品状态(true代表正常,false代表删除)
    event BuyChance(address consumer,uint goodsId, uint chanceStartId, uint chanceEndId); // 购买Chance成功通知:购买者地址;商品Id,购买chance获得的起始编号;购买chance获得的终止编号
    event NotifySubmitPlaintext(uint goodsId); // 售磬通知:商品编号
    event NotifyWinnerResult(uint goodsId, uint winnerId, address winnerAddr);//中奖通知:商品编号;获奖者编号;获奖者地址
    
    // 稳定币合约地址
    TokenERC20 public stableCoin;
     
    // 商品
    struct Goods {
        string name; // 奖品名称
        uint256 amt; // 奖品价格
        string description; // 奖品描述
        bool isActive; //商品状态,true代表商品可以购买查看,false代表商品已删除
        uint256 winnerId; // 中奖用户Id=获奖算法结果%(amt/stableCoinPrice)/+1 ,用户id从1开始,winnerId=0说明还没有开奖
        address[] consumers; // 购买用户列表,index+1=用户Id,存储内容为压缩地址uid
        TokenERC20 otherCoin; // 其他币合约地址
        uint256 stableCoinPrice; // 购买一个chance需要的稳定币
        uint256 stableAndOtherCoinPrice; //稳定币与其它币组合购买,不使用值为0 (需要稳定币)
        uint256 otherCoinPrice; //稳定币与其它币组合购买,不使用值为0 (需要其他币,因为是方案2,所以如果otherCoinPrice的值不为0)
    }
     
    // 商品列表
    Goods[] public goodses;
    
    // 初始化,将合约创建者设置为主办方,设置稳定币地址
    function OneChance(address _stableCoin){
        sponsor = msg.sender;
        stableCoin = TokenERC20(_stableCoin);
    }
     
    // 发布奖品,只有主办方可以调用,主办方用 uuid确定多笔发布奖品操作具体哪一个奖品发布成功
    function postGoods(string _name, uint256 _amt, string _description,uint256 _stableCoinPrice,address _otherCoin,uint256 _stableAndOtherCoinPrice, uint256 _otherCoinPrice,string uuid) public onlySponsor {
        Goods memory goods;
        goods.name = _name;
        goods.amt = _amt;
        goods.description = _description;
        goods.isActive = true;
        goods.stableCoinPrice = _stableCoinPrice;
        if(_otherCoinPrice != 0){
            goods.otherCoin = TokenERC20(_otherCoin);
            goods.stableAndOtherCoinPrice = _stableAndOtherCoinPrice;
            goods.otherCoinPrice = _otherCoinPrice;
        }
        goodses.push(goods);
        // 通知主办方发布成功(事件)
        emit PostGoods(goodses.length, uuid);
    }
     
    //已发布商品数目
    function topGoodsId() public view returns (uint) {
        return goodses.length;
    }
     
    //删除商品
     function delGoodsById(uint _goodsId) public onlySponsor {
         Goods goods = goodses[_goodsId-1];
         goods.isActive = false;
         emit DelGoods(_goodsId,false);
    }
     
    // 查询奖品信息
    function goods(uint256 _goodsId) public view returns (string name, uint256 amt, string description, bool isActive,uint consumersLength,  uint256 winnerId, address winnerAddr, uint256 stableCoinPrice, uint256 stableAndOtherCoinPrice, uint256 otherCoinPrice) {
        Goods goods = goodses[_goodsId-1];
        name = goods.name;
        amt = goods.amt;
        description = goods.description;
        isActive = goods.isActive;
        consumersLength = goods.consumers.length;
        winnerId = goods.winnerId;
        if (winnerId!=0) {
            // 用户Id-1得到数组下标,然后用地址压缩合约查询uid得到用户实际地址
            winnerAddr = goods.consumers[winnerId-1];
        }
        stableCoinPrice = goods.stableCoinPrice;
        stableAndOtherCoinPrice = goods.stableAndOtherCoinPrice;
        otherCoinPrice = goods.otherCoinPrice;
    }
     
    // 查询用户地址
    function user(uint256 _goodsId, uint256 _userId) public view returns (address userAddr) {
        Goods goods = goodses[_goodsId-1];
        userAddr = goods.consumers[_userId-1];
    }
    
    // 购买chance
    function buyChance(uint256 _goodsId, uint256 _quantity1, uint256 _quantity2) public {
        if (_quantity1+_quantity2 <= 0) throw;
        Goods goods = goodses[_goodsId-1];
        if (goods.isActive == false ) throw;
        if ((goods.consumers.length + _quantity1 + _quantity2) * goods.stableCoinPrice > goods.amt) throw;
        stableCoin.onechance_transfer(sponsor,_quantity1*goods.stableCoinPrice+_quantity2*goods.stableAndOtherCoinPrice);
        if (_quantity2 != 0){
            goods.otherCoin.onechance_transfer(sponsor,_quantity2*goods.otherCoinPrice);
        }
        // 通知用户购买成功,用户需要记录自己的 goodsId+beginUserId
        emit BuyChance(tx.origin, _goodsId, goods.consumers.length+1,goods.consumers.length+_quantity1+_quantity2);
        // 记录商品的购买用户
        for (uint256 i=0; i<_quantity1 +_quantity2; i++) {
            goods.consumers.push(tx.origin);
        }
        // 如果商品 Chance 已售罄,通知购买用户提交原始随机数以生成中奖用户
        if (goods.consumers.length == goods.amt/goods.stableCoinPrice) {
            emit NotifySubmitPlaintext(_goodsId);
        }
    }
     
    // 计算获奖用户,取幸运区块号签名(哈希值)的最后8位,转成10进制数字
    function submitPlaintext(uint256 hashNum,uint256 _goodsId) public {
        Goods goods = goodses[_goodsId-1];
        goods.winnerId = hashNum % (goods.amt/goods.stableCoinPrice) +1;
        //通知用户中奖结果
        emit NotifyWinnerResult(_goodsId, goods.winnerId,goods.consumers[goods.winnerId-1]);
    }
 
}

  

posted @   人艰不拆_zmc  阅读(217)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示