Dapp 数字积分 开发(一)
学习以太坊一段时间,一直想想找个demo练习一下,看到趣链的一个数字积分项目,突然想重新写一边,增加自己对相关概念的理解,也积累一点项目经验。
开发工具:vscode + hardhat + Ganache
合约大约有两个文件,一个Utils.sol文件和Score.sol 文件
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.9;
/// @title 工具类
/// @author arrom
contract Utils {
/// @notice string ->bytes32
function stringToBytes32(
string memory source
) internal pure returns (bytes32 result) {
assembly {
result := mload(add(source, 32))
}
}
/// @notice bytes32 ->string
function bytes32ToString(bytes32 x) internal pure returns (string memory) {
bytes memory bytesString = new bytes(32);
uint charCount = 0;
for (uint j = 0; j < 32; j++) {
bytes1 char = bytes1(bytes32(uint(x) * 2 ** (8 * j)));
if (char != 0) {
bytesString[charCount] = char;
charCount++;
}
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (uint j = 0; j < charCount; j++) {
bytesStringTrimmed[j] = bytesString[j];
}
return string(bytesStringTrimmed);
}
}
Score.sol
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.9;
import "./Utils.sol";
/// @title 积分
/// @author arrom
contract Score is Utils {
/// @notice 合约的拥有者
address owner;
/// @notice 发行的积分总数
uint issuedScoreAmount;
/// @notice 已经清算的积分总数
uint settledScoreAmount;
struct Customer {
/// @notice 客户的address
address customerAddr;
/// @notice 客户密码
bytes32 password;
/// @notice 积分
uint scoreAmount;
/// @notice 兑换的商品
bytes32[] buyGoods;
}
struct Merchant {
/// @notice 商户address
address merchantAddr;
/// @notice 商户密码
bytes32 password;
/// @notice 积分余额
uint scoreAmount;
/// @notice 发布的商品数组
bytes32[] sellGoods;
}
struct Good {
/// @dev 商品Id
bytes32 goodId;
/// @dev 商品价格
uint price;
/// @dev 商品属于哪个商户
address belong;
}
mapping(address => Customer) customer;
mapping(address => Merchant) merchant;
/// @notice 根据商品ID查找该商品
mapping(bytes32 => Good) good;
/// @notice 已注册的客户
address[] customers;
/// @notice 已注册的商户数
address[] merchants;
/// @notice 商品
bytes32[] goods;
/// @dev 只有合约的创建者才能调用
modifier onlyOwner() {
if (msg.sender == owner) _;
}
constructor() {
owner = msg.sender;
}
/// @notice 返回合约调用者的地址
function getOwner() public view returns (address) {
return owner;
}
/// @notice 客户注册
event RegCustomer(address sender, bool isSuccess, string password);
/// @notice 客户注册
function regCustomer(
address _customerAddr,
string memory _password
) public {
/// @dev 判断是否注册
if (!isCustomerAlreadyReg(_customerAddr)) {
/// @dev 未注册
customer[_customerAddr].customerAddr = _customerAddr;
customer[_customerAddr].password = stringToBytes32(_password);
customers.push(_customerAddr);
emit RegCustomer(msg.sender, true, _password);
return;
} else {
emit RegCustomer(msg.sender, false, _password);
return;
}
}
/// @notice 判断客户是否注册
function isCustomerAlreadyReg(
address _customerAddr
) internal view returns (bool) {
for (uint i = 0; i < customers.length; i++) {
if (customers[i] == _customerAddr) return true;
}
return false;
}
/// @notice 查询用户密码
function getCustomerPassword(
address _customerAddr
) public view returns (bool, bytes32) {
/// @notice 先判断该用户注册
if (isCustomerAlreadyReg(_customerAddr)) {
return (true, customer[_customerAddr].password);
} else {
return (false, "");
}
}
/// @notice 查询商户密码
function getMerchantPassword(
address _merchantAddr
) public view returns (bool, bytes32) {
if (isMerchantAlreadyReg(_merchantAddr)) {
return (true, merchant[_merchantAddr].password);
}
return (false, "");
}
/// @notice 商户注册
event RegMerchant(address sender, bool isSuccess, string message);
function regMerchant(
address _merchantAddr,
string memory _password
) public {
if (!isMerchantAlreadyReg(_merchantAddr)) {
merchant[_merchantAddr].merchantAddr = _merchantAddr;
merchant[_merchantAddr].password = stringToBytes32(_password);
merchants.push(_merchantAddr);
emit RegMerchant(msg.sender, true, unicode"注册");
return;
} else {
emit RegMerchant(msg.sender, false, unicode"该账户已经注册");
return;
}
}
/// @notice 商户是否注册
function isMerchantAlreadyReg(
address _merchantAddr
) internal view returns (bool) {
for (uint i = 0; i < customers.length; i++) {
if (customers[i] == _merchantAddr) {
return true;
}
}
return false;
}
/// @notice 发送积分给客户(智能银行调用)
event SendScoreToCustomer(address sender, string message);
function sendScoreToCustomer(
address _receiver,
uint _amount
) public onlyOwner {
if (isCustomerAlreadyReg(_receiver)) {
/// @dev 已经注册
issuedScoreAmount += _amount;
customer[_receiver].scoreAmount += _amount;
emit SendScoreToCustomer(msg.sender, unicode"发行积分成功");
return;
}
emit SendScoreToCustomer(
msg.sender,
unicode"该账户未注册,发行积分失败"
);
return;
}
/// @notice 根据客户address查询余额
function getScoreWithCustomerAddr(
address customerAddr
) public view returns (uint) {
return customer[customerAddr].scoreAmount;
}
/// @notice 根据商户address查找余额
function getScoreWithMerchantAddr(
address merchantAddr
) public view returns (uint) {
return merchant[merchantAddr].scoreAmount;
}
/// @notice 转移积分
event TransferScoreToAnother(address sender, string message);
function transferScoreToAnother(
uint _senderType,
address _sender,
address _receiver,
uint _amount
) public {
if (
!isCustomerAlreadyReg(_receiver) && !isMerchantAlreadyReg(_receiver)
) {
emit TransferScoreToAnother(
msg.sender,
unicode"账户不存在,请确认后再转移!"
);
return;
}
if (_senderType == 0) {
//客户转移
if (customer[_sender].scoreAmount >= _amount) {
customer[_sender].scoreAmount -= _amount;
if (isCustomerAlreadyReg(_receiver)) {
customer[_receiver].scoreAmount += _amount;
} else {
merchant[_receiver].scoreAmount += _amount;
}
emit TransferScoreToAnother(msg.sender, unicode"积分转让成功!");
return;
}
emit TransferScoreToAnother(
msg.sender,
unicode"你的积分不够,转让失败!"
);
return;
} else {
/// @dev 商户转移
if (merchant[_sender].scoreAmount >= _amount) {
merchant[_sender].scoreAmount -= _amount;
if (isCustomerAlreadyReg(_receiver)) {
customer[_receiver].scoreAmount += _amount;
} else {
merchant[_receiver].scoreAmount += _amount;
}
emit TransferScoreToAnother(msg.sender, unicode"积分转让成功!");
return;
}
emit TransferScoreToAnother(
msg.sender,
unicode"你的积分不够,转让失败!"
);
return;
}
}
/// @notice 查询发行的积分总数
function getIssuedScoreAmount() public view returns (uint) {
return issuedScoreAmount;
}
/// @notice 清算的积分总数
function getSettleScoreAmount() public view returns (uint) {
return settledScoreAmount;
}
/// @notice 商户添加商品
event AddGood(address sender, bool isSuccess, string message);
function addGood(
address _merchantAddr,
string memory _goodId,
uint _price
) public {
bytes32 tempId = stringToBytes32(_goodId);
/// @dev 判断是否存在
if (!isGoodAlreadyAdd(tempId)) {
good[tempId].goodId = tempId;
good[tempId].price = _price;
good[tempId].belong = _merchantAddr;
goods.push(tempId);
merchant[_merchantAddr].sellGoods.push(tempId);
emit AddGood(msg.sender, true, unicode"创建商品成功!");
return;
}
emit AddGood(msg.sender, false, unicode"商品已经添加,请确认后操作!");
return;
}
function isGoodAlreadyAdd(bytes32 _goodId) internal view returns (bool) {
for (uint i = 0; i < goods.length; i++) {
if (goods[i] == _goodId) {
return true;
}
}
return false;
}
/// @notice 积分购买商品
event BuyGood(address sender, bool isSuccess, string message);
function buyGood(address _customerAddr, string memory _goodId) public {
/// @dev 判断商品Id是否存在
bytes32 tempId = stringToBytes32(_goodId);
if (isGoodAlreadyAdd(tempId)) {
/// @dev 商品已经添加,可以购买
if (customer[_customerAddr].scoreAmount < good[tempId].price) {
emit BuyGood(
msg.sender,
false,
unicode"余额不足,购买商品失败!"
);
return;
}
customer[_customerAddr].scoreAmount -= good[tempId].price;
merchant[good[tempId].belong].scoreAmount += good[tempId].price;
customer[_customerAddr].buyGoods.push(tempId);
emit BuyGood(msg.sender, true, unicode"购买商品成功!");
return;
} else {
emit BuyGood(
msg.sender,
false,
unicode"输入商品Id不存在,请确认后购买!"
);
return;
}
}
/// @notice 查询购买的商品
function getGoodsByCustomer(
address _customerAddr
) public view returns (bytes32[] memory) {
return customer[_customerAddr].buyGoods;
}
/// @notice 商户查找自己的商品
function getGoodsByMerchant(
address _merchantAddr
) public view returns (bytes32[] memory) {
return merchant[_merchantAddr].sellGoods;
}
/// @notice 商户和银行清算积分
event SettleScoreWithBank(address sender, string message);
function settleScoreWithBank(address _merchantAddr, uint _amount) public {
if (merchant[_merchantAddr].scoreAmount >= _amount) {
merchant[_merchantAddr].scoreAmount -= _amount;
settledScoreAmount += _amount;
emit SettleScoreWithBank(msg.sender, unicode"积分清算成功!");
return;
}
emit SettleScoreWithBank(
msg.sender,
unicode"您的积分余额不足,清算失败!"
);
return;
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!