Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-1175: 所有代币的钱包和商店标准 (erc20)

Authors Jet Lim (@Nitro888)
Created 2018-06-21
Discussion Link https://github.com/ethereum/EIPs/issues/1182
Requires EIP-20

所有代币都去天堂

简单总结

使由认证合约创建的钱包和商店更容易地将 erc20 代币用于商业。

wallet

摘要

由经过身份验证的合约创建的钱包和商店之间的相互信任允许您通过简单的流程支付和购买商品。

动机

已经发布了具有改进的新标准,但目前正在开发的大多数代币都是 erc20 代币。 所以我觉得我需要一个提案来在商业中使用旧代币。 要使用各种 erc20 代币进行交易,您需要一个自定义合约。 但是,具有各种代币的单个钱包和相互信任的商店可以使交易变得简单而高效。 erc20 代币通过两次调用进行交易,approve (address _spender, uint256 _value)transferFrom (address _from, address _to, uint256 _value),但是当使用钱包合约时,paySafe (address _shop, uint256 _item) 将仅在一次调用中进行交易。 并且如果您仅重用商店界面,则还可以使用 payUnsafe (address _shop, uint256 _item) 进行交易。

规范

workflow

WalletCenter

方法

createWallet

创建钱包合约并添加到列表。 返回新钱包的地址。

function createWallet() public returns (address _wallet)

isWallet

返回 true 或 false 值,用于测试此地址是否由 createWallet 创建。

function isWallet(address _wallet) public constant returns (bool)

createShop

创建商店合约并添加到列表。 返回带有 erc20 代币地址的新商店的地址。

function createShop(address _erc20) public returns (address _shop)

isShop

返回 true 或 false 值,用于测试此地址是否由 createWallet 创建。

function isShop(address _shop) public constant returns (bool)

事件

Wallet

搜索我的钱包。

event Wallet(address indexed _owner, address indexed _wallet)

Shop

搜索我的商店。

event Shop(address indexed _owner, address indexed _shop, address indexed _erc20)

Wallet

钱包必须由钱包中心创建。

方法

balanceOf

返回钱包的帐户余额。

function balanceOf(address _erc20) public constant returns (uint256 balance)

withdrawal

_erc20 代币的 _value 数量提现到 _owner

function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success)

paySafe

支付安全商店(由合约创建)物品,物品索引为 _item

function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success)

payUnsafe

支付不安全商店(不是由合约创建)物品,物品索引为 _item

function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success)

payCancel

取消支付并退款。 (仅每周模式)

function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success)

refund

从商店退款,物品索引为 _item

function refund(uint256 _item, uint256 _value) public payable returns (bool success)

事件

Pay

event Pay(address indexed _shop, uint256 indexed _item, uint256 indexed _value)

Refund

event Refund(address indexed _shop, uint256 indexed _item, uint256 indexed _value)

Shop

商店由钱包中心创建或不创建。 但由钱包中心创建的商店称为安全商店。

方法

balanceOf

返回商店的帐户余额。

function balanceOf(address _erc20) public constant returns (uint256 balance)

withdrawal

_erc20 代币的 _value 数量提现到 _owner

function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success)

pay

从买家处付款,物品索引为 _item

function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success)

refund

将代币退还给 _to

function refund(address _buyer, uint256 _item, uint256 _value) onlyWallet(_buyer) onlyOwner public payable returns (bool success)

resister

列出要出售的物品。

function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId)

update

更新物品的出售状态。 (更改物品 _price 或添加物品 _stock

function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public

price

从买家处获取代币地址和价格,物品索引为 _item

function price(uint256 _item) public constant returns (address _erc20, uint256 _value)

canBuy

_who 可以购买 _item

function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy)

isBuyer

_who_item 的买家。

function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer)

info

设置商店信息字节。

function info(bytes _msgPack)

upVote

赞成这家商店。

function upVote()

dnVote

反对这家商店。

function dnVote()

about

获取商店代币、赞成票和反对票。

function about() view returns (address _erc20, uint256 _up, uint256 _down)

infoItem

设置物品信息字节。

function infoItem(uint256 _item, bytes _msgPack)

upVoteItem

赞成这个物品。

function upVoteItem(uint256 _item)

dnVoteItem

反对这个物品。

function dnVoteItem(uint256 _item)

aboutItem

获取物品价格、赞成票和反对票。

function aboutItem(uint256 _item) view returns (uint256 _price, uint256 _up, uint256 _down)

事件

Pay

event Pay(address indexed _buyer, uint256 indexed _item, uint256 indexed _value)

Refund

event Refund(address indexed _to, uint256 indexed _item, uint256 indexed _value)

Item

event Item(uint256 indexed _item, uint256 _price)

Info

event Info(bytes _msgPack)

InfoItem

event InfoItem(uint256 indexed _item, bytes _msgPack)

实现

示例代币合约地址为 0x393dd70ce2ae7b30501aec94727968c517f90d52

WalletCenter 合约地址为 0x1fe0862a4a8287d6c23904d61f02507b5044ea31

WalletCenter 创建商店合约地址为 0x59117730D02Ca3796121b7975796d479A5Fe54B0

WalletCenter 创建钱包合约地址为 0x39da7111844df424e1d0a0226183533dd07bc5c6

附录

pragma solidity ^0.4.24;

contract ERC20Interface {
    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

contract SafeMath {
    function safeAdd(uint a, uint b) public pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function safeSub(uint a, uint b) public pure returns (uint c) {
        require(b <= a);
        c = a - b;
    }
    function safeMul(uint a, uint b) public pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function safeDiv(uint a, uint b) public pure returns (uint c) {
        require(b > 0);
        c = a / b;
    }
}

contract _Base {
    address internal owner;
    address internal walletCenter;
    
    modifier onlyOwner {
        require(owner == msg.sender);
        _;
    }
    modifier onlyWallet(address _addr) {
        require(WalletCenter(walletCenter).isWallet(_addr));
        _;
    }
    modifier onlyShop(address _addr) {
        require(WalletCenter(walletCenter).isShop(_addr));
        _;
    }

    function balanceOf(address _erc20) public constant returns (uint256 balance) {
        if(_erc20==address(0))
            return address(this).balance;
        return ERC20Interface(_erc20).balanceOf(this);
    }

    function transfer(address _to, address _erc20, uint256 _value) internal returns (bool success) {
        require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
        if(_erc20==address(0))
            _to.transfer(_value);
        else
            ERC20Interface(_erc20).approve(_to,_value);
        return true;
    }
    
    function withdrawal(address _erc20, uint256 _value) public returns (bool success);
    
    event Pay(address indexed _who, uint256 indexed _item, uint256 indexed _value);
    event Refund(address indexed _who, uint256 indexed _item, uint256 indexed _value);
    event Prize(address indexed _who, uint256 indexed _item, uint256 indexed _value);
}

contract _Wallet is _Base {
    constructor(address _who) public {
        owner           = _who;
        walletCenter    = msg.sender;
    }
    
    function pay(address _shop, uint256 _item) private {
        require(_Shop(_shop).canBuy(this,_item));

        address _erc20;
        uint256 _value;
        (_erc20,_value) = _Shop(_shop).price(_item);
        
        transfer(_shop,_erc20,_value);
        _Shop(_shop).pay(_item);
        emit Pay(_shop,_item,_value);
    }
    
    function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success) {
        pay(_shop,_item);
        return true;
    }
    function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success) {
        pay(_shop,_item);
        return true;
    }
    function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success) {
        _Shop(_shop).payCancel(_item);
        return true;
    }

    function refund(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) {
        require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value);
        if(_erc20!=address(0))
            ERC20Interface(_erc20).transferFrom(msg.sender,this,_value);
        emit Refund(msg.sender,_item,_value);
        return true;
    }
    function prize(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) {
        require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value);
        if(_erc20!=address(0))
            ERC20Interface(_erc20).transferFrom(msg.sender,this,_value);
        emit Prize(msg.sender,_item,_value);
        return true;
    }
    
    function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) {
        require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
        if(_erc20==address(0))
            owner.transfer(_value);
        else
            ERC20Interface(_erc20).transfer(owner,_value);
        return true;
    }
}

contract _Shop is _Base, SafeMath{
    address erc20;
    constructor(address _who, address _erc20) public {
        owner           = _who;
        walletCenter    = msg.sender;
        erc20           = _erc20;
    }
    
    struct item {
        uint8                       category;   // 0 = 禁用, 1 = 无库存,无过期时间,2 = 可以过期(1 周后),3 = 可堆叠
        uint256                     price;
        uint256                     stockCount;

        mapping(address=>uint256)   customer;
    }

    uint                    index;
    mapping(uint256=>item)  items;
    
    function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success) {
        require(canBuy(msg.sender, _item));
        require((erc20==address(0)?msg.value:ERC20Interface(erc20).allowance(msg.sender,this))==items[_item].price);
        
        if(erc20!=address(0))
            ERC20Interface(erc20).transferFrom(msg.sender,this,items[_item].price);
        
        if(items[_item].category==1 || items[_item].category==2 && now > safeAdd(items[_item].customer[msg.sender], 1 weeks))
            items[_item].customer[msg.sender]   = now;
        else if(items[_item].category==2 && now < safeAdd(items[_item].customer[msg.sender], 1 weeks) )
            items[_item].customer[msg.sender]   = safeAdd(items[_item].customer[msg.sender], 1 weeks);
        else if(items[_item].category==3) {
            items[_item].customer[msg.sender]   = safeAdd(items[_item].customer[msg.sender],1);
            items[_item].stockCount             = safeSub(items[_item].stockCount,1);
        }

        emit Pay(msg.sender,_item,items[_item].customer[msg.sender]);
        return true;
    }
    
    function payCancel(uint256 _item) onlyWallet(msg.sender) public returns (bool success) {
        require (items[_item].category==2&&safeAdd(items[_item].customer[msg.sender],2 weeks)>now&&balanceOf(erc20)>=items[_item].price);

        items[_item].customer[msg.sender]  = safeSub(items[_item].customer[msg.sender],1 weeks);
        transfer(msg.sender, erc20, items[_item].price);
        _Wallet(msg.sender).refund(erc20,_item,items[_item].price);
        emit Refund(msg.sender,_item,items[_item].price);

        return true;
    }
    function refund(address _to, uint256 _item) onlyWallet(_to) onlyOwner public payable returns (bool success) {
        require(isBuyer(_to,_item)&&items[_item].category>0&&(items[_item].customer[_to]>0||(items[_item].category==2&&safeAdd(items[_item].customer[_to],2 weeks)>now)));
        require((erc20==address(0)?address(this).balance:ERC20Interface(erc20).balanceOf(this))>=items[_item].price);

        if(items[_item].category==1)
            items[_item].customer[_to]  = 0;
        else if(items[_item].category==2)
            items[_item].customer[_to]  = safeSub(items[_item].customer[_to],1 weeks);
        else
            items[_item].customer[_to]  = safeSub(items[_item].customer[_to],1);
            
        transfer(_to, erc20, items[_item].price);
        _Wallet(_to).refund(erc20,_item,items[_item].price);
        emit Refund(_to,_item,items[_item].price);

        return true;
    }
    
    event Item(uint256 indexed _item, uint256 _price);
    function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId) {
        require(_category>0&&_category<4);
        require(_price>0);
        items[index]    = item(_category,_price,_stock);
        index = safeAdd(index,1);
        emit Item(index,_price);
        return safeSub(index,1);
    }
    function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public {
        require(items[_item].category>0);
        require(_price>0);
        uint256 temp = items[_item].price;
        items[_item].price      = _price;
        items[_item].stockCount = safeAdd(items[_item].stockCount,_stock);
        
        if(temp!=items[_item].price)
            emit Item(index,items[_item].price);
    }
    
    function price(uint256 _item) public constant returns (address _erc20, uint256 _value) {
        return (erc20,items[_item].price);
    }
    
    function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy) {
        return  (items[_item].category>0) &&
                !(items[_item].category==1&&items[_item].customer[_who]>0) &&
                (items[_item].stockCount>0);
    }
    
    function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer) {
        return (items[_item].category==1&&items[_item].customer[_who]>0)||(items[_item].category==2&&safeAdd(items[_item].customer[_who],1 weeks)>now)||(items[_item].category==3&&items[_item].customer[_who]>0);
    }
    
    uint lastWithdrawal;
    function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) {
        require(safeAdd(lastWithdrawal,1 weeks)<=now);
        require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
        if(_erc20==address(0))
            owner.transfer(_value);
        else
            ERC20Interface(_erc20).transfer(owner,_value);
        lastWithdrawal = now;
        return true;
    }
}

contract WalletCenter {
    mapping(address=>bool) public     wallet;
    event Wallet(address indexed _owner, address indexed _wallet);
    function createWallet() public returns (address _wallet) {
        _wallet = new _Wallet(msg.sender);
        wallet[_wallet] = true;
        emit Wallet(msg.sender,_wallet);
        return _wallet;
    }
    function isWallet(address _wallet) public constant returns (bool) {
        return wallet[_wallet];
    }
    mapping(address=>bool) public     shop;
    event Shop(address indexed _owner, address indexed _shop, address indexed _erc20);
    function createShop(address _erc20) public returns (address _shop) {
        _shop   = new _Shop(msg.sender,_erc20);
        shop[_shop] = true;
        emit Shop(msg.sender,_shop,_erc20);
        return _shop;
    }
    function isShop(address _shop) public constant returns (bool) {
        return shop[_shop];
    }
}

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Jet Lim (@Nitro888), "ERC-1175: 所有代币的钱包和商店标准 (erc20) [DRAFT]," Ethereum Improvement Proposals, no. 1175, June 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1175.