Dapp 数字积分 开发(一)

  • arrom
  • 更新于 2022-12-05 19:14
  • 阅读 1821

Dapp 数字积分 开发(一)

学习以太坊一段时间,一直想想找个demo练习一下,看到趣链的一个数字积分项目,突然想重新写一边,增加自己对相关概念的理解,也积累一点项目经验。

总体架构

image.png

合约开发

开发工具: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;
    }
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
arrom
arrom
江湖只有他的大名,没有他的介绍。