ERC-1175: 所有代币的钱包和商店标准 (erc20)
Authors | Jet Lim (@Nitro888) |
---|---|
Created | 2018-06-21 |
Discussion Link | https://github.com/ethereum/EIPs/issues/1182 |
Requires | EIP-20 |
所有代币都去天堂
简单总结
使由认证合约创建的钱包和商店更容易地将 erc20 代币用于商业。
摘要
由经过身份验证的合约创建的钱包和商店之间的相互信任允许您通过简单的流程支付和购买商品。
动机
已经发布了具有改进的新标准,但目前正在开发的大多数代币都是 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)
进行交易。
规范
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.