Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions auction/auction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## ✔ 合约介绍
### 场景介绍
举办一场拍卖会,被拍卖的商品有三个,每件商品最长出价时间为10min,每轮结束后,出
价最高者获得本轮商品,如果无人出价,商品进入新一轮的拍卖。
### 流程介绍
- 合约初始化时,公布商品信息,拍卖时间,起拍价。
- 商品具有状态、起拍价、当前最高出价、拥有者属性。
- 拍卖时间原则上统一十分钟。
- 起拍价不得低于100xuper。
- 商品初始状态为未上架。
- 在商品未上架时,拍卖行有权利设置商品的起拍价格,拍卖时间以及上架商品。
- 商品售出后,无法再次拍卖。
226 changes: 226 additions & 0 deletions auction/auction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
// SPDX-License-Identifier: SimPL-2.0
pragma solidity ^0.8.17;

contract auction {
// 为 uint256 类型使用 SafeMath 库
using SafeMath for uint256;
// 拍卖行
address auctionHouse;
// 状态池
mapping(uint256 => string) aStatus;
// 商品信息,简单考虑,只维护一个 desc
mapping(uint256 => string) desc;
// 商品状态
mapping(uint256 => uint256) status;
// 商品起拍时间
mapping(uint256 => uint256) timestamp;
// 商品起拍价
mapping(uint256 => uint256) price;
// 商品当前出价记录
mapping(uint256 => mapping(uint256 => address)) bids;
// 商品当前最高出价
mapping(uint256 => uint256) maxPrice;
// 商品拥有者
mapping(uint256 => address) owner;

// 合约初始化
constructor(address _owner) {
// 拍卖行
auctionHouse = _owner;
// 初始化状态池
aStatus[0] = "Off shelf";
aStatus[1] = "Under auction";
aStatus[2] = "Had sold";
// 创建商品
desc[0] = "xuperchain01";
desc[1] = "xuperchain02";
desc[3] = "xuperchain03";
}

// 上架商品
function putOnShelves(uint256 pid) public returns (bool) {
// 身份验证
require(sender() == auctionHouse, "auction error: no permission");
// 状态验证
require(status[pid] == 0, "auction error: this item cannot be listed");
// 起拍时间验证,避免执行占用拍卖时间,增加5分钟准备时间
require(
(timestamp[pid] - block.timestamp) > 15 minutes,
"auction error: unable to prepare adequately before this time, pls set the auction time"
);
// 起拍价验证
require(price[pid] > 100, "auction error: the price is too cheap");
// 开始拍卖
status[pid] = 1;
return true;
}

// 设置起拍时间
function setAuctionTime(uint256 pid, uint256 times) public returns (bool) {
// 身份验证
require(sender() == auctionHouse, "auction error: no permission");
// 状态验证
require(
status[pid] == 0,
"auction error: this item cannot be set auction time"
);
// 起拍时间验证,避免执行占用拍卖时间,增加1分钟准备时间
require(
(times - block.timestamp) > 15 minutes,
"auction error: unable to prepare adequately before this time"
);
// 修改起拍时间
timestamp[pid] = times;
return true;
}

// 设置起拍价
function setPrice(uint256 pid, uint256 prices) public returns (bool) {
// 身份验证
require(sender() == auctionHouse, "auction error: no permission");
// 状态验证
require(
status[pid] == 0,
"auction error: this item cannot be set auction time"
);
// 起拍价验证
require(prices > 100, "auction error: the price is too cheap");
// 设置起拍价格
price[pid] = prices;
// 商品初始归属为拍卖行
owner[pid] = auctionHouse;
// 起拍价格为初始最高出价
maxPrice[pid] = prices;
return true;
}

// 出价
function bid(uint256 pid, uint256 prices) public returns (bool) {
// 状态验证
require(status[pid] == 1, "auction error: this item cannot be bid");
// 价格验证
require(
maxPrice[pid] < prices,
"auction error: your price must more than the maxPrice"
);
// 能否继续叫价
require(verifyBid(pid), "auction error: the item had sold");
maxPrice[pid] = prices;
// 记录
bids[pid][prices] = sender();
return true;
}

// 能否继续叫价
function verifyBid(uint256 pid) private returns (bool) {
if (block.timestamp - timestamp[pid] > 10) {
// 需要停止
// 状态设置
status[pid] = 2;
// 归属者设置
owner[pid] = bids[pid][maxPrice[pid]];
return false;
}
return true;
}

// 获取商品描述
function getDesc(uint256 pid) public view returns (string memory) {
return desc[pid];
}

// 获取拍卖行地址
function getAuctionHouse() public view returns (address) {
return auctionHouse;
}

// 获取商品状态
function getStatus(uint256 pid) public view returns (string memory) {
return aStatus[status[pid]];
}

// 获取商品起拍时间
function getTimestamp(uint256 pid) public view returns (uint256) {
return timestamp[pid];
}

// 获取商品起拍价格
function getPrice(uint256 pid) public view returns (uint256) {
return price[pid];
}

// 获取商品当前最高价
function getMaxPrice(uint256 pid) public view returns (uint256) {
return maxPrice[pid];
}

// 获取商品归属人
function getOwner(uint256 pid) public view returns (address) {
return owner[pid];
}

// the sender
function sender() private view returns (address) {
return msg.sender;
}
}

library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}

/**
*
@dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*
**/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0); // Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}

/**
*
@dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*
**/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}

/**
*
@dev Adds two numbers, reverts on overflow.
*
**/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}

/**
*
@dev Divides two numbers and returns the remainder (unsigned integer modulo),
*
reverts when dividing by zero.
*
**/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
112 changes: 112 additions & 0 deletions campaign/campaign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#### 场景介绍

campaign 合约,实现场景为学生会主席竞选流程。

#### 流程介绍

1. 合约初始化时,指定具有owner权限的账户,该账户具有检票与提名候选人以及启动竞选提案的权利。
2. 启动竞选提案,需要提名一位候选人,并指定提案通过票数阈值,更新提案状态为投票中,返回该次提案ID。
3. 任何人都可以根据提案ID查询该提案的状态。
4. 当提案状态为投票中,任何人可以调用投票功能进行投票,限投一人一票,重复投票不会生效。
5. 当票数大于启动提案时设置的阈值,提案状态为待检票,owner 可启动检票。
6. 检票会进行身份验证,只有owner账户可以成功调用。
7. 检票通过后,提案流程结束,提案状态置为已生效,此时任何人都可以查询当前学生会主席信息。
8. 当提案状态为未启动、已生效、待检票时,不可使用投票功能。
9. 任何人都可根据提案ID查询该提案的候选人信息。

#### 功能介绍

##### constructor

- Params:
- owner:
- type: address
- desc: owner权限设置
- Desc: 设置owner权限账户,初始化提案状态

##### propose

- Params:
- candidate:
- type: string
- desc: 候选人
- target:
- type: uint256
- desc: 票数阈值
- Returns:
- proposalId:
- type: uint256
- desc: 提案ID
- Desc: 启动竞选提案

##### queryProposal

- Params:
- proposalId:
- type: uint256
- desc: 提案ID

- Returns:
- status:
- type: string
- desc: 提案状态:未启动(stoped)、投票中(voting)、待检票(passed)、已生效(completed)
- Desc: 查询提案状态

##### vote

- Params:
- proposalId:
- type: uint256
- desc: 提案ID

- Retruns:
- status:
- type: string
- desc: 投票状态:"success" or "error",error需给出原因
- Desc: 进行投票,调用该方法,视为调用者进行投票一次

##### queryVotes

- Params:
- proposalId:
- type: uint256
- desc: 提案ID

- Returns:
- votes:
- type: uint256
- desc: 当前所获票数,当状态为未启动时,应为0
- Desc: 查询已经获取的票数

##### check

- Params:
- proposalId:
- type: uint256
- desc: 提案ID

- Returns:
- status:
- type: string
- desc: 检票状态:"success" or "error",error需给出原因
- Desc: 启动检票

##### queryPresident

- Returns:
- president:
- type: string
- desc: 竞选成功的候选人
- Desc: 查询学生会主席信息

##### queryCandidate

- Params:
- proposalId:
- type: uint256
- desc: 提案ID
- Returns:
- candidate:
- type: string
- desc: 提案候选人信息
- Desc: 查询提案候选人信息
Loading