这份合约包括创建物品、租用物品、支付押金租金返还押金等功能。这个需求其实很简单,很适合学习和参考。合约并非原创,感谢我的师兄对本合约的帮助!如果有语法还不清楚的朋友请参看solidity官方文档。
代码更新于2018.5.8 14:52分
pragma solidity ^0.4.4;
contract myShare {
struct Renter{
address addr;//renter's address
uint since;//from which time?
}
struct Object{
address creator;//the owner of obj
string name;// name of obj
uint priceDaily;//price of each day
uint deposit;//deposits of the obj
Renter renter;//who rent the obj
bool rented;//if rented?
string detail;//another infomation
}
struct Namekey{
uint[] keys;//storage the name's keys
}
uint[] private ids; //to return the ids of obj
uint public numObjects;
mapping(uint => Object) private objects;
mapping(string => Namekey) private nameToKeys;
address public owner;
event NewObject(uint objID,address creator);
modifier objectInRange(uint objID) {//modify function
if (objID >= numObjects)
throw;
_;
}
modifier onlyOwner(){
if(msg.sender != owner){
throw;
}
_;
}
function myShare() {
owner = msg.sender;
}
function objectIsRented(uint objID) objectInRange(objID) returns (bool){
return objects[objID].rented;
}
function createObj(string name,uint priceDaily,uint deposit,string detail){
Object newObject = objects[numObjects];
nameToKeys[name].keys.push(numObjects);//add the key to the name's key
newObject.creator = msg.sender;
newObject.name = name;
newObject.priceDaily = priceDaily;
newObject.rented = false;
newObject.deposit = deposit;
newObject.detail = detail;
NewObject(numObjects,msg.sender);
ids.push(numObjects);
numObjects++;
}
function rentObj(uint objID) payable objectInRange(objID) returns(bool){
if(objectIsRented(objID) || msg.value < objects[objID].deposit || msg.sender == objects[objID].creator){
throw;
}
objects[objID].renter = Renter({addr:msg.sender, since:now}); //record the info of the renter
uint rest = msg.value - objects[objID].deposit;
if(!objects[objID].renter.addr.send(rest)){ // return the rest balance
throw;
}
objects[objID].rented = true;
return true;
}
function returnObj(uint objID) payable objectInRange(objID) returns (bool){
if(!objects[objID].rented){
throw;
}
//if(objects[objID].renter.addr != msg.sender){
//
throw;
//}
uint duration = (now - objects[objID].renter.since) / (24*60*60*1.0);
if(duration == 0){
duration = 1;
}
uint charge = duration * objects[objID].priceDaily;
if(!objects[objID].creator.send(charge)){ //return the charge to creator
throw;
}
if(!objects[objID].renter.addr.send(objects[objID].deposit - charge)){ //return the rest deposit to renter
throw;
}
delete objects[objID].renter;
objects[objID].rented = false;
return true;
}
function getBalance(address addr) returns (uint){
return addr.balance;
}
function findNames(string name) constant returns(uint[]){
return nameToKeys[name].keys;
}
function getNumObjects() constant returns(uint){
return numObjects;
}
function getObjectIds() constant returns(uint[]){
return ids;
}
function getObjectName(uint objID) objectInRange(objID) returns(string objName){
var obj = objects[objID];
objName = obj.name;
}
function getObjectCreator(uint objID) constant objectInRange(objID) returns(address){
return objects[objID].creator;
}
function getObjectPriceDaily(uint objID) constant objectInRange(objID) returns(uint){
return objects[objID].priceDaily;
}
function getObjectDeposit(uint objID) constant objectInRange(objID) returns(uint){
return objects[objID].deposit;
}
function getObjectRenterAddress(uint objID) constant objectInRange(objID) returns(address){
return objects[objID].renter.addr;
}
function getObjectRenterSince(uint objID) constant objectInRange(objID) returns(uint){
return objects[objID].renter.since;
}
function getObjectDetail(uint objID) constant objectInRange(objID) returns(string){
return objects[objID].detail;
}
function remove() onlyOwner {
selfdestruct(owner);
}
}
这份合约运行在Remix IDE上(一个在线的Solidity编译器很适合新手入门,直接百度进入)。如何编译运行参照点击打开链接
(下面这段解释我这个实验是怎么设计的。以及为什么这样设计)
我发现了一个很棘手的问题,创建合约和执行合约中的某个函数都要消耗gas,(什么是gas请参看点击打开链接),会给我的实验带来麻烦,我设计的验证方案是,账户1创建一个物品,账户2来租用,然后归还,跟踪整个过程中以太币的去向。但是比如账户2归还的时候一定会消耗gas,也就会消耗余额同时押金返还会增加余额,尽管日志中有gas消耗具体数值,但是实在不会计算。而账户1在创建物品后,不再需要调用任何函数,所以只能判断账户1的余额具体变化。应该有一个账户3,专门用来创建合约和调用函数的。简单来说就是为了跟踪余额,尽量排除gas带来的影响!但是到最后我设计的方案还是无法具体检测用户2的余额变化,因为消耗gas。如果有更好的实验方案请提出来谢谢!
一、创建合约
二、创建一个物品(注意创建物品选用第一个账户 0xca35b7d915458ef540ade6068dfe2f44e8fa733c)
在函数中输入物品参数。
我们创建了第一个物品 自行车,创建成功。
三、租用一个物品试一试(这里选用第二个账户租用 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c)
然后点解rentObj,在控制台中查看details,返回值是true物品就租借成功了。这时候查看一下账户2的余额,注意:不要用账户2来getBalance,用账户5来调用getBalance,参数输入账户2的地址,这样保证账户2的以太币仅用来支付和返还租金。
得到的账户2余额如下:
账户1的余额如下:
合约地址的余额如下:
这个过程告诉我们账户2的10个以太币转移到了合约上(其实合约也是一个地址,和各个账户一样),合约暂为保管。合约地址就是memory前面那个,如果对这个地方很晕,建议再看看关于以太坊地址的资料,弄懂这些地址都是什么。
四、归还物品
这里注意要选择账户2来归还物品,无法避免消耗账户2的gas。这时候我们再来看一下各个账户的余额(调用getBalance函数时都要用帐号5否则会影响实验结果)
账户1:
账户2:
合约账户:
与物品归还前相比,账户1里面尾数由794684变成了794685,多了一位以太币,就是租金1元/天,不足一天按一天计算。
账户2由9907792变成9794685,押金退还反而少了?为什么呢,因为归还物品的时候调用了returnObj函数,消耗了gas。
合约账户余额变成了0,因为10位押金本来就是暂时保存的,1位给了账户1,9位返还给了账户2。
这个实验过程的不足之处就是没有弄清楚账户2的变化,不理解以太币的单位eth和wei,以及gas和以太币之间的关系。虽然不严谨,至少账户1收到了租金,也证实了押金的整个过程,实现了去中心化的一次租借过程。
最后希望大家多提意见,有疑问请留言,有更好的方案请提出来谢谢!