5.13.3 货币合约

优质
小牛编辑
141浏览
2023-12-01

货币

什么是货币?货币比他们看起来更有趣和有用,它们本质上只是一个可交易的令牌,但可以变得更多,取决于你如何使用它们。其价值取决于您使用的方式:令牌可用于控制访问(门票),可用于组织(共享)中的投票权,可以是第三方持有的资产的占位符(所有权证书),甚至只能用作社区(货币)内的价值交换。+

您可以通过创建一个集中的服务器来完成所有这些工作,但是使用Ethereum令牌合约带有一些免费的功能:一个是一个分散的服务,即使原始服务由任何原因导致宕机,令牌也可以交换。代码可以保证不会创建除原始代码中设置的令牌以外的令牌。最后,通过使每个用户拥有自己的令牌,这消除了一个单一服务器突破可能导致数千客户端资金损失的情况。

您可以在不同的blockchain上创建自己的令牌,但是在ethereum上创造更容易。所以您可以将精力集中在创新上,使您的货币脱颖而出。它更安全,因为您的安全由所有正在支持ethereum网络的矿工提供。最后,通过在Ethereum中创建你的令牌,你的硬币将与任何运行在ethereum上其他合约兼容。

代码

下面就是我们合约的代码:

contract token {
    mapping (address => uint) public coinBalanceOf;
    event CoinTransfer(address sender, address receiver, uint amount);

  /* Initializes contract with initial supply tokens to the creator of the contract */
  function token(uint supply) {
        coinBalanceOf[msg.sender] = supply;
    }

  /* Very simple trade function */
    function sendCoin(address receiver, uint amount) returns(bool sufficient) {
        if (coinBalanceOf[msg.sender] < amount) return false;
        coinBalanceOf[msg.sender] -= amount;
        coinBalanceOf[receiver] += amount;
        CoinTransfer(msg.sender, receiver, amount);
        return true;
    }
}

如果你有编程基础的话,你不会很难理解它的作用:这是一个合约,为合同的创建者生成10万个令牌,然后允许有足够的余额的任何人发送给他人。这些令牌是最小可交易单位,不能被细分,但最终用户可以表示为100个可再细分成100个子单位的单位,因此拥有单个令牌将占总数的0.01%。如果您的应用程序需要更细粒度的原子分割,那么只需增加初始发行量。

在这个例子中,我们将变量“coinBalanceOf”声明为public,这将自动创建一个检查任何账户余额的函数。

编译和部署

让我们开始吧

var tokenSource = ' contract token { mapping (address => uint) public coinBalanceOf; event CoinTransfer(address sender, address receiver, uint amount); /* Initializes contract with initial supply tokens to the creator of the contract */ function token(uint supply) { coinBalanceOf[msg.sender] = supply; } /* Very simple trade function */ function sendCoin(address receiver, uint amount) returns(bool sufficient) { if (coinBalanceOf[msg.sender] < amount) return false; coinBalanceOf[msg.sender] -= amount; coinBalanceOf[receiver] += amount; CoinTransfer(msg.sender, receiver, amount); return true; } }'

var tokenCompiled = eth.compile.solidity(tokenSource)

现在我们来设定合同,就像我们在上一节中所做的一样。将“初始供应”更改为要创建的不可分割令牌的数量。如果你想要有可分割的单位,你应该在用户端设置它,但保持用账户的最小单位来表示它。

var supply = 10000;
var tokenContract = web3.eth.contract(tokenCompiled.token.info.abiDefinition);
var token = tokenContract.new(
  supply,
  {
    from:web3.eth.accounts[0],
    data:tokenCompiled.token.code,
    gas: 1000000
  }, function(e, contract){
    if(!e) {

      if(!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined...");

      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }

    }
})

在线编译器

如果您没有安装SolC,可以直接使用在线编译器。将合同代码复制到在线solidity编译器,如果合约上没有错误,您应该看到标有Geth Deploy的文本框。将内容复制到文本文件,以便您可以更改第一行以设置初始供应量,如下所示:

var supply = 10000;

现在您可以将生成的文本粘贴到您的geth窗口。等待三十秒钟,您会看到如下消息:

Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e

检查余额来观察货币流动

如果一切正常,您应该可以通过以下方式查看自己的余额:

token.coinBalanceOf(eth.accounts[0]) + " tokens"

合同一旦发布后,应该拥有10000个令牌。由于没有任何其他定义的方式来发行新的硬币,这些固定令牌都是永远存在的。

每当任何人使用您的合约发送硬币时,您可以设置一个观察者来做出反应。以下是您的操作方法:

var event = token.CoinTransfer({}, '', function(error, result){
  if (!error)
    console.log("Coin transfer: " + result.args.amount + " tokens were sent. Balances now are as following: \n Sender:\t" + result.args.sender + " \t" + token.coinBalanceOf.call(result.args.sender) + " tokens \n Receiver:\t" + result.args.receiver + " \t" + token.coinBalanceOf.call(result.args.receiver) + " tokens" )
});

发送货币

如果你囤积他们,那么这些令牌没有用,所以为了发送给别人,使用这个命令:

token.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]})

如果朋友在注册商上注册了一个名字,您可以在不知道他们的地址的情况下发送给他:

token.sendCoin.sendTransaction(registrar.addr("Alice"), 2000, {from: eth.accounts[0]})

请注意,我们的第一个函数coinBalanceOf只是直接在合同实例上调用并返回一个值。这是可能的,因为这是一个简单的读取操作,不会导致状态更改,并且在本地和同步执行。我们的第二个函数sendCoin需要一个.sendTransaction() 调用。由于该功能旨在改变状态(写入操作),所以将其作为交易发送到网络以供矿工打包并包含在规范块中。因此,所有参与者节点的共识状态将充分反映执行事务所导致的状态变化。发件人地址需要作为交易的一部分发送,以资助运行交易所需的花费。现在,等待几分钟然后检查每个账户的余额:

token.coinBalanceOf.call(eth.accounts[0])/100 + "% of all tokens"
token.coinBalanceOf.call(eth.accounts[1])/100 + "% of all tokens"
token.coinBalanceOf.call(registrar.addr("Alice"))/100 + "% of all tokens"

改进建议

现在这个加密货币有很大局限性的,因为只有10000个硬币,所有的都是由货币创建者控制的,但是你可以改变它。你可以通过创建一个交易来奖励找到当前块的旷工:

mapping (uint => address) miningReward;
function claimMiningReward() {
  if (miningReward[block.number] == 0) {
    coinBalanceOf[block.coinbase] += 1;
    miningReward[block.number] = block.coinbase;
  }
}

你可以把它修改为其他任何东西:也许是奖励一个找到新的拼图解决方案的人,赢得一场棋的人,安装一个太阳能电池板的人。只要可以以某种方式翻译成一个合同。或者也许你想为你的个人国家创建一个中央银行,所以你可以跟踪工作时间,倾向于或控制财产。在这种情况下,您可能需要添加一个功能,以便银行能够远程冻结资金并在需要时销毁令牌。

注册你的硬币的名字

所提到的命令只能工作,因为您在本地计算机上实例化了令牌JavaScript对象。如果您向某人发送令牌,则由于他们没有相同的对象而无法将其移动,也不会知道在何处寻找合同或调用其功能。事实上,如果您重新启动控制台,这些对象将被删除,您一直在处理的合约将永远丢失。那么如何在干净的机器上实例化合同?

有两种方法 让我们快速开始,向您的朋友提供您的合同ABI的参: 考:

token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at('0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8')

只需替换自己的令牌地址的最后一个地址,那么使用此代码段的任何人都可以立即使用您的合同。当然这只适用于这个具体的合同,所以让我们逐步分析一下,看看如何改进这个代码,这样你就可以在任何地方使用它。

网络中的所有帐户都被其公共地址引用。但地址长,难以写下来,难以记忆和不变。如果您想要以您的名义生成新帐户,或者升级您的合同代码,则最后一个是特别重要的。为了解决这个问题,有一个默认的名称注册商合同,用于将长地址与简短的,人性化的名称相关联。

名称必须仅使用字母数字字符,并且不能包含空格。在未来的版本中,名称注册商可能会实施一个招标过程,以防止名称光占着茅坑,但现在,它是先到先得的原则:只要没有人注册该名称,您可以声明。

首先,如果你注册一个名字,那么你最终不需要硬编码的地址。选择一个不错的硬币名称,并尝试为自己预留。首先,选择你的名字:

var tokenName = "MyFirstCoin"

然后,检查你的名字的可用性:

registrar.addr(tokenName)

如果该函数返回“0x00 ..”,您可以向自己声明:

registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]});

等待先前的交易被打包。等待三十秒钟,然后尝试:

registrar.owner(myName)

如果它返回您的地址,则表示您拥有该名称,并且可以将您选择的名称设置为您想要的任何地址:

registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]});

如果要将其用作个人昵称,可以替换eth.accounts[0] token.address

等待一会儿,让交易被确认,然后测试下:

registrar.addr("MyFirstCoin")

你可以通过简单地输入名字而不是账户来向任何人或者任何合约发送交易:

eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")})

提示:请勿将registrar.addr同Registrar.owner搞混了。第一个是该名称指向的地址:任何人都可以将名称指向其他任何地方,就像任何人都可以转发到google.com的链接,但只有该名称的所有者可以更改和更新链接。您可以将两者设置为相同的地址。

现在应该返回您的令牌地址,这意味着以前要实例化的代码现在可以使用名称来替换地址。

token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at(registrar.addr("MyFirstCoin"))

这也意味着货币的所有者可以通过将注册商指向新的合同来更新硬币。这当然要求货币持有人信任Registrar.owner(“MyFirstCoin”)设置的所有者

当然,这是一个令人不快的大块代码,只是为了允许他人与合同进行交互。有一些将合同ABI上传到网络的方法正在讨论中,以便所有用户需要的仅仅是合同名称。你可以阅读这些方法,但它们是实验性的,将来肯定会发生变化。

学到更多

  • 元硬币标准是为硬币和令牌合约功能名称的标准化而提出的,允许它们自动添加到运用交易的,类似交易所或托管中心的其他ethereum合同中。
  • 正式校验是合同开发商能够声明合同的一些定量的方式,如硬币的总上限。但是尚未实现。