diff --git a/ShareBike/SharedBike.md b/ShareBike/SharedBike.md new file mode 100644 index 0000000..e503210 --- /dev/null +++ b/ShareBike/SharedBike.md @@ -0,0 +1,163 @@ +# 共享单车合约实现 + +## 1、简单介绍 + +共享单车合约主要由UserStorage实现用户的新增存储,SharedBike实现主要的业务逻辑,包括对单车的新增,借出,修理等一些业务。 +*** +本文章对整体代码逻辑进行了基础的介绍,对业务进行了简单使用,作为对solidity业务的简单快速入门。 + +## 2、代码逻辑 + +UserStorage中储存用户信息,作为用户管理合约,需要先进行部署 + +#### 基本属性 + +```solidity + //其中mapping对象储存用户信息,用户信息主要封装在这里 + mapping(address=>User) public registeredUsers; + + address public admin;//部署人地址 + + struct User { + string name; //姓名 + string contact; //联系方式 + uint32 creditPoints; //信誉分 + uint32 status; //用户状态 + }//结构体,相当于User模板 + + User public users;//用户信息对象 +``` + + +#### 封装的方法 + +```solidity +//注册 +registerUser(string memory name, string memory contact) + +//查询信誉分 +getCredits(address user) + +//用户是否注册过 +exists(address user) + +//加分 +addCredits(address user, uint32 credits) + +//扣分 +subCredits(address user, uint32 credits) +``` + +*** +SharedBike中封装了主要的业务实现,通过UserStorage的地址进行部署 + +#### 初始化 + +```solidity + //使用合约地址构造,指定要获取的UserStorage对象 + constructor(address _address) public{ + admin = msg.sender; + address addr=address(_address); + userStorage =UserStorage(addr); + } +``` + +#### 基本属性 + +```solidity + //信誉阈值 + uint32 public userCreditThreshold = 60; + + //管理员地址,部署时自动赋值 + address public admin; + + //用户管理对象,部署时自动赋值 + UserStorage public userStorage; + + //定义单车状态结构体 + struct Bike { + BikeStatus status; + } + + /** + * 定义一个枚举,以便可以使用数字代表单车的状态 + * 不存在 0 ,可使用 1 ,已借出 2 ,修理中 3 + */ + enum BikeStatus { + NotExist, //0 + Available, //1 + InBorrow, //2 + InRepair //3 + } + + //单车Id,一个Id代表一辆单车 + uint256 private _bikeCount; + + //存储不同单车的状态 + mapping(uint256=>Bike) private _bikes; + + //存储用户借用情况 + mapping(address=>uint256) private _borrows; + +``` +#### 封装的方法 + +```solidity +//删 +revokeBike(uint256 bikeId) + +//借 +borrowBike(uint256 bikeId) + +//还 +returnBike(uint256 bikeId) + +//报告故障 +reportDamge(uint256 bikeId) + +//故障修理 +fixDamge(uint256 bikeId) + +//用户信誉奖励 +reward(address user, uint32 credits) + +//用户信誉惩罚 +punish(address user, uint32 credits) + +//设置信誉阈值 +setCreditThreshold(uint32 newThreshold) + +//转让管理员 +transferAdmin(address newAdmin) +``` +## 3、合约测试 +___此处使用Remix在线编译器运行合约___ + +部署UserStorage + +![img](./SharedBike_image/1.jpg) + +复制UserStorage地址,部署SharedBike + +![img](./SharedBike_image/2.png) +![img](./SharedBike_image/3.png) + +当前调用者账户 + +![img](./SharedBike_image/4.png) + +注册xiaoming用户,联系方式为13012345678 + +![img](./SharedBike_image/5.png) + +registerBike点击注册一辆车,id自增,当前为1 +借,还,报损,修复,移除,依次测试方法均无问题 + +![img](./SharedBike_image/6.png) + +当前用户为0X17F...,调用奖励方法,变更管理员均无错误 + +![img](./SharedBike_image/7.png) +![img](./SharedBike_image/8.png) diff --git a/ShareBike/SharedBike.sol b/ShareBike/SharedBike.sol new file mode 100644 index 0000000..249b746 --- /dev/null +++ b/ShareBike/SharedBike.sol @@ -0,0 +1,173 @@ +pragma solidity ^0.6.10; + +import './UserStorage.sol'; + + +contract SharedBikes { + + uint32 public userCreditThreshold = 60; + address public admin; + UserStorage public userStorage; + + + + //使用合约地址构造,指定要获取的对象 + constructor(address _address) public{ + admin = msg.sender; + address addr=address(_address); + userStorage =UserStorage(addr); + + } + + modifier onlyAdmin(){ + require(msg.sender == admin, "admin required"); + _; + } + + modifier userRegistered(address user){ + //用户是否存在 + require(userStorage.exists(user), "user not registered"); + _; + } + + modifier requireStatus(uint256 bikeId, BikeStatus bikeStatus){ + //判断单车状态 + require(_bikes[bikeId].status == bikeStatus, "bad bike status"); + _; + } + + /** + * 定义单车状态对象 + */ + struct Bike { + BikeStatus status; + } + /** + * 定义一个枚举,以便可以使用数字代表单车的状态 + * 不存在 0 ,可使用 1 ,已借出 2 ,修理中 3 + */ + enum BikeStatus { + NotExist, + Available, + InBorrow, + InRepair + } + + + event RegisterBike(uint256 indexed bikeId);//注册 + event RevokeBike(uint256 indexed bikeId);//废除 + event BorrowBike(address indexed borrower, uint256 indexed bikeId);//借出 + event ReturnBike(address indexed borrower, uint256 indexed bikeId);//归还 + event ReportDamage(address indexed reporter, uint256 indexed bikeId);//报告损坏 + event FixDamage(uint256 indexed bikeId);//修复损坏 + event Reward(address indexed borrower, uint32 credits);//奖励 + event Punish(address indexed borrower, uint32 credits);//惩罚 + event SetCreditThreshold(uint32 newThreshold);//设置信用阈值 + event TransferAdmin(address oldAdmin, address newAdmin);//转移使用者 + + //自增单车ID + uint256 private _bikeCount; + //存储不同单车的状态 + mapping(uint256=>Bike) private _bikes; + //存储用户借用 + mapping(address=>uint256) private _borrows; + + //增 + function registerBike() external onlyAdmin returns(uint256 bikeId) { + //自增Id + _bikeCount++; + bikeId = _bikeCount; + //修改自行车状态 + Bike storage bike = _bikes[bikeId]; + bike.status = BikeStatus.Available; + emit RegisterBike(bikeId); + } + + + //删 + function revokeBike(uint256 bikeId) external onlyAdmin requireStatus(bikeId, BikeStatus.Available){ + Bike storage bike = _bikes[bikeId]; + //修改单车状态为不存在 + bike.status = BikeStatus.NotExist; + emit RevokeBike(bikeId); + } + //借 + function borrowBike(uint256 bikeId) external userRegistered(msg.sender) requireStatus(bikeId, BikeStatus.Available){ + //判断是否已经借出 + require(_borrows[msg.sender] == 0, "user in borrow"); + //判断用户信用分数 + require(userStorage.getCredits(msg.sender) >= userCreditThreshold, "not enough credits"); + + //修改借用者状态 + _borrows[msg.sender] = bikeId; + //修改自行车状态 + Bike storage bike = _bikes[bikeId]; + bike.status = BikeStatus.InBorrow; + + emit BorrowBike(msg.sender, bikeId); + } + //还 + function returnBike(uint256 bikeId) external userRegistered(msg.sender) requireStatus(bikeId, BikeStatus.InBorrow){ + require(_borrows[msg.sender] == bikeId, "not borrowing this one"); + //修改借用者状态 + _borrows[msg.sender] = 0; + //修改自行车状态 + Bike storage bike = _bikes[bikeId]; + bike.status = BikeStatus.Available; + emit ReturnBike(msg.sender, bikeId); + } + + //报告损坏 + function reportDamge(uint256 bikeId) external userRegistered(msg.sender) requireStatus(bikeId, BikeStatus.Available){ + //修改自行车状态 + Bike storage bike = _bikes[bikeId]; + bike.status = BikeStatus.InRepair; + emit ReportDamage(msg.sender, bikeId); + } + + //修理损坏 + function fixDamge(uint256 bikeId) external onlyAdmin requireStatus(bikeId, BikeStatus.InRepair){ + //修改自行车状态 + Bike storage bike = _bikes[bikeId]; + bike.status = BikeStatus.Available; + emit FixDamage(bikeId); + } + + //奖励 + function reward(address user, uint32 credits) external userRegistered(user) onlyAdmin{ + //调用addCredits方法 + userStorage.addCredits(user, credits); + emit Reward(user, credits); + } + + //惩罚 + function punish(address user, uint32 credits) external userRegistered(user) onlyAdmin{ + //调用subCredits + userStorage.subCredits(user, credits); + emit Punish(user, credits); + } + + //设置信誉分阈值 + function setCreditThreshold(uint32 newThreshold) external onlyAdmin { + userCreditThreshold = newThreshold; + emit SetCreditThreshold(newThreshold); + } + + //转让管理员 + function transferAdmin(address newAdmin) external onlyAdmin { + address oldAdmin = admin; + admin = newAdmin; + emit TransferAdmin(oldAdmin, newAdmin); + } +} + + + + + + + + + + + diff --git a/ShareBike/SharedBike_image/1.jpg b/ShareBike/SharedBike_image/1.jpg new file mode 100644 index 0000000..fd0d3a7 Binary files /dev/null and b/ShareBike/SharedBike_image/1.jpg differ diff --git a/ShareBike/SharedBike_image/2.png b/ShareBike/SharedBike_image/2.png new file mode 100644 index 0000000..cd4a3b8 Binary files /dev/null and b/ShareBike/SharedBike_image/2.png differ diff --git a/ShareBike/SharedBike_image/3.png b/ShareBike/SharedBike_image/3.png new file mode 100644 index 0000000..0a5d66c Binary files /dev/null and b/ShareBike/SharedBike_image/3.png differ diff --git a/ShareBike/SharedBike_image/4.png b/ShareBike/SharedBike_image/4.png new file mode 100644 index 0000000..1c1775d Binary files /dev/null and b/ShareBike/SharedBike_image/4.png differ diff --git a/ShareBike/SharedBike_image/5.png b/ShareBike/SharedBike_image/5.png new file mode 100644 index 0000000..6c867b8 Binary files /dev/null and b/ShareBike/SharedBike_image/5.png differ diff --git a/ShareBike/SharedBike_image/6.png b/ShareBike/SharedBike_image/6.png new file mode 100644 index 0000000..031591c Binary files /dev/null and b/ShareBike/SharedBike_image/6.png differ diff --git a/ShareBike/SharedBike_image/7.png b/ShareBike/SharedBike_image/7.png new file mode 100644 index 0000000..84cff29 Binary files /dev/null and b/ShareBike/SharedBike_image/7.png differ diff --git a/ShareBike/SharedBike_image/8.png b/ShareBike/SharedBike_image/8.png new file mode 100644 index 0000000..1903466 Binary files /dev/null and b/ShareBike/SharedBike_image/8.png differ diff --git a/ShareBike/UserStorage.sol b/ShareBike/UserStorage.sol new file mode 100644 index 0000000..5bdad66 --- /dev/null +++ b/ShareBike/UserStorage.sol @@ -0,0 +1,78 @@ +pragma solidity ^0.6.10; + + + +contract UserStorage{ + + address public admin; + + + struct User { + string name; //姓名 + string contact; //联系方式 + uint32 creditPoints; //信誉分 + uint32 status; //用户状态 + }//结构体,相当于User模板 + + User public users;//用户信息对象 + + //其中mapping对象储存用户信息,用户信息主要封装在这里 + mapping(address=>User) public registeredUsers; + + //直接用调用者作为admin地址 + constructor() public{ + admin = msg.sender; + } + + event RegisterUser(address indexed addr, string name, string contact); + + //注册 + function registerUser(string memory name, string memory contact) external { + //if status==0,is new User + require(!exists(msg.sender), "user existed"); + + registeredUsers[msg.sender].name = name; + registeredUsers[msg.sender].contact = contact; + registeredUsers[msg.sender].status = 1; + registeredUsers[msg.sender].creditPoints = 100; + + emit RegisterUser(msg.sender, name, contact); + } + + //查询信誉分 + function getCredits(address user) external view returns(uint32 credits) { + require(exists(user), "user not exists"); + return registeredUsers[user].creditPoints; + } + + //用户是否注册过 + function exists(address user) public view returns(bool) { + //用户状态为0就是未注册 + return registeredUsers[user].status != 0; + } + + //加分 + function addCredits(address user, uint32 credits) public { + + require(exists(user), "user not exists"); + + uint32 newPoint = registeredUsers[user].creditPoints + credits; + registeredUsers[user].creditPoints= newPoint; + } + + //减分 + function subCredits(address user, uint32 credits) public { + require(exists(user), "user not exists"); + require(credits > 0, "credits zero"); + + //添加if判断,防止溢出 + uint32 newPoint=0; + if (registeredUsers[user].creditPoints > credits) { + newPoint = registeredUsers[user].creditPoints - credits; + } else { + newPoint = 0; + } + + registeredUsers[user].creditPoints= newPoint; + } +} \ No newline at end of file