下面分享几个智能合约供大家一起学习。

一、投注合约

主要功能点:1)投注;2)开奖;3)退奖;4)获取奖池奖金;5)返回当前期数;6)返回中奖者地址;7)返回参与彩民的地址;

1.1 定义合约属性

合约主要包含有四个属性:

contract Lottery {address manager;  // 管理员address[] players;  // 投了注的彩民address winner;   // 上期彩票的胜出者uint256 round = 1;    // 第几期
}

管理员属性可以在创建合约的时候进行初始化。

constructor() public {manager = msg.sender;
}

1.2 投注

假设每次投注只能投1个以太币。

// 投注
function play() public payable {require(msg.value == 1 ether);players.push(msg.sender);
}

1.3 开奖

开奖就是在投注彩民数组players中随机选出一个彩民,然后将合约的余额转账到该彩民的地址上。

这里需要先定义一个修饰器,用于限定只有管理员角色有权执行开奖的方法。

modifier onlyManager() {require(manager == msg.sender);_;
}

下面是开奖方法的实现逻辑:

function kaijiang() public payable {// 生成players数组的随机下标bytes memory v1 = abi.encodePacked(block.difficulty, now, players.length);bytes32 v2 = keccak256(v1);uint v3 = uint256(v2) % players.length;// 获取中奖者winner = players[v3];// 把奖池的金额转账给中奖者winner.transfer(address(this).balance);// 清空playsdelete players;// 期数加1round++;
}

1.4 退奖

只有管理员才可以发起退奖操作。

// 退奖
function tuiJiang() public onlyManager {require(players.length != 0);// 把奖池的金额退还给每一个玩家for (uint i = 0; i < players.length; i++) {players[i].transfer(1 ether);}// 清空playsdelete players;// 期数加1round++;
}

值得注意的是,上面开奖和退奖方法中,都会执行transfer函数执行转账操作。上面代码会存在代码“重入”的风险。所以作为改善措施,应该按照Checks-Effects-Interactions模式编写函数代码。

优化后的代码:

function kaijiang() public payable {// 生成随机下标bytes memory v1 = abi.encodePacked(block.difficulty, now, players.length);bytes32 v2 = keccak256(v1);uint v3 = uint256(v2) % players.length;// 获取中奖者winner = players[v3];    // 清空playsdelete players;// 期数加1round++;// 把奖池的金额转账给中奖者winner.transfer(address(this).balance);
}// 退奖
function tuiJiang() public onlyManager {require(players.length != 0);// 清空playsdelete players;// 期数加1round++;// 把奖池的金额退还给每一个玩家for (uint i = 0; i < players.length; i++) {players[i].transfer(1 ether);}
}

上面代码将transfer操作放在方法最后执行。另外,上面代码通过delete players删除所有参与的玩家信息,这样会存在一定的风险:如果数组较大,可能会超过区块gas限制,从而引发out of gas异常。其实对于动态数组而言,使用length属性修改数组大小也可以达到同样效果。

players.lenght = 0;

1.5 其他操作

// 获取奖金池的金额
function getAmount() public view returns(uint256) {return address(this).balance;
}// 获取管理员地址
function getManagerAddress() public view returns(address) {return manager;
}// 返回当前期数
function getRound() public view returns(uint256) {return round;
}// 返回中奖者地址
function getWinner() public view returns(address) {return winner;
}// 返回参与彩民的地址
function getPlays() public view returns(address[]) {return players;
}

二、众筹合约

主要功能点:1)创建众筹合约;2)获取所有众筹合约;3)获取发起者的众筹合约;4)获取参与者的众筹合约;5)参与众筹;6)获取已筹集到的金额;7)获取所有参与者;8)退款;9)众筹成功后,发起花费请求;10)审批花费请求;11)完成花费请求;12)获取众筹的剩余时间;13)获取参与者的数量;14)获取花费申请的详情;

2.1 创建众筹合约

第一步:定义合约。

contract Funding {// 合约发起者address public manager;// 众筹项目名称string public projectName;// 目标金额uint public targetMoney;// 支持金额uint public supportMoney;// 项目结束时间,单位秒uint public endTime;// 参与者address payable[] investors;constructor(string memory _projectName, uint _targetMoney, uint _supportMoney, uint _duration, address _creator) public {manager = _creator;projectName = _projectName;targetMoney = _targetMoney;supportMoney = _supportMoney;endTime = now + _duration;}
}

第二步:定义一个工厂合约,该合约保存了所有的众筹实例,并提供了操作众筹合约的方法;

contract FundingFactory {// 平台管理员address public platformManager;// 所有的众筹合约address[] allFundings;// 自己创建的合约集合,key代表合约发起者地址,value代表合约机制的集合mapping(address => address[]) creatorFundings;constructor() public {platformManager = msg.sender;}
}

第三步:定义发起众筹的方法;

function createFunding(string memory _projectName, uint _targetMoney, uint _supportMoney, uint _duration) public {Funding funding = new Funding(_projectName, _targetMoney, _supoortMoney, _duration, msg.sender);allFundings.push(address(funding));creatorFundings[msg.sender].push(address(funding));
}

2.2 获取所有众筹合约和发起者的众筹合约

接着在FundingFactory中添加其他操作合约的方法。

// 获取所有众筹合约
function getAllFundings() public view returns(address[] memory) {return allFundings;
}// 获取发起者的众筹合约
function getCreatorFundings() public view returns(address[] memory) {return creatorFundings[msg.sender];
}

2.3 获取参与者参与过的众筹集合

第一步:为了便于维护参与者的众筹记录,我们定义一个合约,专门用来记录所有参与者参与过的众筹合约。

contract SupportFunding {// 记录参与过的众筹mapping(address => address[]) supportFundings;function setSupportFunding(address _supportor, address funding) public {supportFundings[_supportor].push(funding);}function getSupportFunding(address _supportor) public {return supportFundings[_supportor];}
}

第二步:在FundingFactory中增加supportFunding属性,并提供获取参与者参与过的合约方法;

SupportFunding supportFunding;// 获取参与者参与过的众筹合约
function getSupportFunding() public view return(address[] memory) {return supportFunding.getFundings(msg.sender);
}

2.4 参与众筹

第一步:在Funding合约增加一个supportFunding属性,在该合约的构造函数中对该属性执行初始化;

SupportFunding supportFunding;constructor(string memory _projectName, uint _targetMoney, uint _supportMoney, uint _duration, address _creator, SupportFunding _supportFunding) public {manager = _creator;projectName = _projectName;targetMoney = _targetMoney;supportMoney = _supportMoney;endTime = now + _duration;supportFunding = _supportFunding;}
}

第二步:定义参与众筹方法;

// 记录是否投资人,key代表参与者,value代表是否投资人
mapping(address => bool) isInvestors;// 参与众筹
function invest() public payable returns(uint) {  // 约束条件:发送币的数量必须要等于支持金额require(msg.value == supportMoney);// 记录投资人investors.push(msg.sender);// 记录参与者为投资人isInvestors[msg.sender] = true;// 记录参与者参与过的合约(当前合约)supportFunding.setFunding(msg.sender, address(this));
}

2.5 获取已筹集到的金额和所有的参与者

// 获取已经筹集到的金额,即当前合约的余额
function getBalance() public view returns(uint) {return address(this).balance;
}// 获取所有的参与者
function getInvestors() public view returns(address payable[] memory) {return investors;
}

2.6 退款

如果合约还没结束,允许投资人退出众筹。所以我们在Funding合约中定义一个修饰器,该修饰器用于添加方法的约束条件。

modifier onlyManager {require(msg.sender == manager);
}

然后定义退款方法,并使用上面定义好的修饰器。

// 退款
function refund() onlyManager public {// 循环遍历所有投资人,并向其转账for (uint i = 0; i < investors.length; i++) {investors[i].transfer(supportMoney);}// 清空投资人数组delete investors;
}

2.7 申请花费

如果众筹成功,管理员在使用众筹资金前,需要发起花费。

第一步:在Funding合约中定义一个结构体,用于记录花费的详情。

// 花费申请状态,0代表申请中,1代表已批准,2代表已完成
enum RequestStatus {Voting, Approved, Completed
}// 记录花费申请信息
struct Request {// 花费目的string purpose;// 申请花费的金额uint cost;// 转账给商家的地址address payable seller;// 花费申请赞同的票数uint approveCount;// 申请状态RequestStatus status;// 参与者的投票状态,true代表已经投票,false代表还没投票mapping(address => bool) hasVoted;
}

第二步:在Funding合约中增加一个属性,该属性用于记录管理员发起的花费请求。

Request[] requests

第三步:定义申请花费的方法;

// 发起花费申请
function createRequest(string memory _purpose, uint _cost, address payable _seller) onlyManager public {Request memory req = Request({purpose: _purpose,cost: _cose * 10**18,  // 将花费金额转换成单位weiseller: _seller,approveCount: 0,status: RequestStatus.Voting});requests.push(req);
}

2.8 发起申请审核

审核通过条件:1)消息发起者是投资人;2)投资人之前没有投过票;

// 对指定索引的申请进行审核
// 参数i代表数组的索引
function approveRequest(uint i) public {Request storage req = requests[i];// 检查是否是投资人require(isInvestors[msg.sender] == true);// 检查是否投过票require(req.hasVoted[msg.sender] == false);// 赞同数增加req.approveCount++;// 记录该投资人已经投过票req.hasVoted[msg.sender] = true;// 如果票数过半,更新申请状态为Approvedif (req.approveCount * 2 > investors.length) {req.status = RequestStatus.Approved;}
}

2.9 完成花费

结束花费申请的条件:1)合约余额必须要大于等于申请的花费金额;2)赞同票数要过半;

// 完成花费
function finalizeRequest(uint i) onlyManager public {Request storage req = requests[i];// 合约的余额必须要足够支付花费require(address(this).balance >= req.cost);// 申请状态必须为已通过require(req.status == RequestStatus.Approved);// 向商家转账req.seller.transfer(req.cose);// 更新申请状态为已完成req.status = RequestStatus.Completed;
}

2.10 获取众筹的剩余时间、参与者的数量、花费申请的详情

function getLeftTime() public view returns(uint) {return endTime - now;
}function getRequestCount() public view returns(uint) {return requests.length;
}function getRequest(uint i) public view returns(string memory, uint, address, uint, RequestStatus) { Request storage req = requests[i];return(req.purpose, req.cost, req.seller, req.approveCount, req.status);
}

到这里为止,整个众筹合约的核心代码已经完成。

三、智能评分合约

该合约实现了根据每一个学员的计算分数指标m和n计算出他们的最终成绩。

首先在合约中定义一个结构体,用于封装学员相关的信息。

contract SmartScore {struct Score {// 学生IDuint uid; // 课程IDuint cid; // m为被其他学生发现并成功评价的实验操作错误数量uint m; // n为成功评价其他学生实验操作错误数量uint n; // 分数uint score; }}

定义一个计算学员成绩的函数。函数入参是一个数组类型,而数组中每一个元素也是一个长度为4的一维数组,分别用于存储学员ID,课程ID,分数指标m,分数指标n、以及最终成绩。

// 设置完成后,计算学生成绩
function calc(uint[4][] memory data) public pure returns(string memory) {Score[] memory scores = new Score[](data.length);uint i = 0;for (i = 0; i < data.length; i++) {uint uid = data[i][0];uint cid = data[i][1];uint m = data[i][2];uint n = data[i][3];Score memory score = Score(uid, cid, m, n, 0);scores[i] = score;}// 找出最高分数,以n-m的值作为参考值Score memory maxScore = scores[0];for (i = 1; i < scores.length; i++) {int a1 = int(maxScore.n - maxScore.m);int a2 = int(scores[i].n - scores[i].m);if(a2 > a1) {maxScore = scores[i];}}// 计算alpha参数的公式为:100 = 80 + (n - m) * alphauint alpha = 20 / (maxScore.n - maxScore.m);// 计算每个学生的成绩for (i = 0; i < scores.length; i++ ){scores[i].score = 80 + (scores[i].n - scores[i].m) * alpha;}// 返回学员的成绩,返回格式: uid_cid_score#uid_cid_score#uid_cid_score#...string memory result = "";for (i = 0; i < scores.length; i++ ){Score memory sc = scores[i];result = result.concat(uint2str(sc.uid).concat("_").concat(uint2str(sc.cid)).concat("_").concat(uint2str(sc.score)));if (i != scores.length - 1) {result = result.concat("#");}}return result;
}

因为solidity不支持uintstring类型之间的强制类型转换,因此这里我们自定义了一个uint2str函数,用于将一个uint类型变量转换成string类型变量。

uint2str函数的实现如下:

function uint2str(uint i) internal pure returns (string memory c) {if (i == 0) {return "0";}uint j = i;uint length;while (j != 0){length++;j /= 10;}bytes memory b = new bytes(length);uint k = length - 1;while (i != 0){b[k--] = byte(uint8(48 + i % 10));i /= 10;}return string(b);
}

上面代码就是将uint类型的变量中每一个数字转换成对应的ascii码后,再封装到bytes里面,最终再将bytes转换成string类型。

另外,合约里面还需要实现字符串的拼接。遗憾的是,solidity并没有提供字符串拼接的工具。所以需要我们自己来实现字符串的拼接。

library StringUtils {function concat(string memory self, string memory s) internal pure returns (string memory) {bytes memory b = new bytes(_a.length + _b.length);bytes memory _a = bytes(self);bytes memory _b = bytes(s);uint k = 0;uint i = 0;for (i = 0; i < _a.length; i++) {b[k++] = _a[i];}for (i = 0; i < _b.length; i++) {b[k++] = _b[i];}return string(b);}}

这里我们定义了一个库合约,用于提供字符串拼接的函数。然后在SmartScore合约中通过using..for语法将库合约引入进来。

using StringUtils for string;

上面就是智能评分合约的代码介绍。

四、拍卖合约

主要功能点:1)卖方发布商品;2)读取商品信息;3)投标;4)揭标;5)仲裁者确定中标者;6)获取赢家信息;7)获取参与竞标的人数;8)管理投标合约资金的发放;

发布商品者(卖方):发布商品;
投标者或出价者(买方):进行投标和揭标操作;
仲裁者:负责确定中标者;

4.1 定义合约

// 竞拍合约
contract Auction {// 用于统计竞标商品数量,作为IDuint public productIndex;// 该mapping存储了商品Id与竞标获得者地址的对应关系mapping(uint => address payable) productIdInStore;// 该mapping存储了竞标获得者参与过的拍卖商品之间的关系mapping(address => mapping(uint => Product)) stores;   // 竞标商品的状态,0代表开始拍卖,1代表交易成功,2代表交易不成功enum ProductStatus {Open, Sold, Unsold}// 竞标商品的使用状态,0代表未使用过,1代表使用过enum ProductCondition {New,  Used}// 竞标人信息struct Bid {// 投标人address bidder;// 竞标商品IDuint productId;// 虚拟投标价格uint value;//是否已经揭标bool revealed; }// 商品信息struct Product {// 商品iduint id;    // 商品名称             string name;    // 商品类别         string category ;   // 图片Hash  string imageLink ;// 图片描述信息的Hash       string descLink;   // 竞标开始时间     uint auctionStartTime; // 竞标结束时间uint auctionEndTime;  // 竞标初始价格  uint startPrice;       // 出价最高者address payable highestBidder; // 赢家得标的价格uint highestBid ; // 竞标价格第二名      uint secondHighestBid ; // 竞标总人数uint totalBids ;   // 竞标商品的状态     ProductStatus status;// 竞标商品的新旧标识ProductCondition condition;// 存储所有竞标人的信息mapping(address => mapping(bytes => Bid)) bids;}
}    

4.2 发布商品

// 发布商品
function addProductToStore(string memory _name, string memory _category, string memory _imageLink, string memory _descLink, uint _auctionStartTime, uint _auctionEndTime ,uint _startPrice, uint _productCondition) public  {// 开始时间需要小于结束时间require(_auctionStartTime < _auctionEndTime, "开始时间不能晚于结束时间");// 商品ID自增productIndex += 1;// 创建Product实例Product memory product = Product(productIndex,_name,_category,_imageLink,_descLink,_auctionStartTime,_auctionEndTime,_startPrice,address(0x0),0,0,0,ProductStatus.Open,ProductCondition(_productCondition));// 保存商品stores[msg.sender][productIndex] = product;productIdInStore[productIndex] = msg.sender;
}

4.3 读取商品信息

// 通过商品ID读取商品信息
function getProduct(uint _productId)  public view returns (uint,string memory, string memory,string memory,string memory,uint ,uint,uint, ProductStatus, ProductCondition)  {Product memory product = stores[productIdInStore[_productId]][_productId];return (product.id, product.name,product.category,product.imageLink,product.descLink,product.auctionStartTime,product.auctionEndTime,product.startPrice,product.status,product.condition);
}

4.4 投标

投标必须要满足以下条件:
1)必须在竞拍时间内;
2)投标价格必须大于等于商品的拍卖价格;
3)投标人没有该商品的投标记录;

// 投标, 其中_bid参数代表投标人的ID,由外部生成传入
function bid(uint _productId, bytes memory _bid) payable public returns (bool) {Product storage product = stores[productIdInStore[_productId]][_productId];require(now >= product.auctionStartTime, "商品竞拍时间未到,暂未开始,请等待...");require(now <= product.auctionEndTime,"商品竞拍已经结束");require(msg.value >= product.startPrice,"设置的虚拟价格不能低于开标价格");require(product.bids[msg.sender][_bid].bidder == address (0x0), "bidder的值必须为空"); // 设置投标人product.bids[msg.sender][_bid] = Bid(msg.sender, _productId, msg.value, false);// 投标人数递增product.totalBids += 1;// 返回投标成功return true;
}

4.5 揭标

竞标结束后,由买方公告价格。最后以买方公告价格的最高者作为赢家。

// 揭标(买方公告价格)
function revealBid(uint _productId, string memory _amount, bytes memory _bid) public {// 通过商品ID获取商品信息Product storage product = stores[productIdInStore[_productId]][_productId];// 检查条件:投标必须要结束了require(now > product.auctionEndTime,"竞标尚未结束,未到公告价格时间");// 获取投标人信息Bid memory bidInfo = product.bids[msg.sender][_bid];// 检查条件:投标人不为空require(bidInfo.bidder > address (0x0), "钱包地址不存在");// 检查条件:必须是未揭标状态require(bidInfo.revealed == false, "已经揭标");// 退款金额uint refund;// 公告价格uint amount = stringToUint(_amount);// 如果买方设置的虚拟价格低于公告价格,则执行退款操作if (bidInfo.value < amount) {refund = bidInfo.value;} else {// 如果第一个参与公告价格者,那么更新商品竞标信息,并将虚拟价格与实际竞标价格之间的差额退还给买方if (address(product.highestBidder) == address (0x0)) {// 设置当前出价者为最高价的竞拍者product.highestBidder = msg.sender;// 将公告价格作为最高价格product.highestBid = amount;// 将商品的起始拍卖价格作为第二高价格product.secondHighestBid = product.startPrice;// 将虚拟价格与公告价格之间的差额作为退款refund = bidInfo.value - amount;} else { // 如果参与者不是第一个揭标,那么分为三种情况:// 第一种情况:实际竞标价大于商品的最高竞标价;// 第二种情况:实际竞标价小于商品的最高竞标价,但是大于第二高竞标价;// 第三种情况:实际竞标价小于第二高竞标价;if (amount > product.highestBid) {// 将原来的最高价竞拍者修改为第二高价竞拍者product.secondHighestBid = product.highestBid;// 将原来最高竞拍价退还给最高价竞拍者product.highestBidder.transfer(product.highestBid);// 将当前出价者作为最高价竞拍者product.highestBidder = msg.sender;// 将当前出价作为最高价product.highestBid = amount;// 将虚拟价格与公告价格之间的差额作为退款refund = bidInfo.value - amount;} else if (amount > product.secondHighestBid) {product.secondHighestBid = amount;// 退还所有竞标款refund = amount;} else { // 如果出价比第二高价还低的话,直接退还竞标款refund = amount;}}// 更新状态为已揭标product.bids[msg.sender][_bid].revealed = true;// 退款if (refund > 0){ msg.sender.transfer(refund);}}
}

下面是stringToUint函数的实现:

function stringToUint(string memory s) pure private returns (uint) {bytes memory b = bytes(s);uint result = 0 ;for (uint i = 0; i < b.length; i++ ){if (uint(uint8(b[i])) >= 48 && uint(uint8(b[i])) <= 57){result = result * 10  + (uint(uint8(b[i])) - 48);}}return result;
}

4.6 确定中标者

仲裁者可以确定最终的中标方。

function finalizeAuction(uint _productId) public {Product memory product = stores[productIdInStore[_productId]][_productId];require(now > product.auctionEndTime, "当前时间必须大于竞拍结束时间");require(product.status == ProductStatus.Open, "竞拍状态必须是开始状态");require(product.highestBidder != msg.sender, "仲裁者不能够是最高出价者");require(productIdInStore[_productId] != msg.sender, "仲裁者不能够是卖方");// 如果竞拍人数为0,则无需做任何操作if (product.totalBids == 0) {product.status = ProductStatus.Unsold;} else {// 创建托管合约实例Escrow escrow = (new Escrow).value(product.secondHighestBid)(_productId, product.highestBidder, productIdInStore[_productId], msg.sender);// 竞拍合约包含了托管合约的引用productEscrow[_productId] = address(escrow);// 更新状态product.status = ProductStatus.Sold;// 中标方只需要支付第二高投标价格,差额会退还给中标方uint refund = product.highestBid - product.secondHighestBid;// 退还差额product.highestBidder.transfer(refund);}// 更新商品信息stores[productIdInStore[_productId]][_productId] = product;
}

4.7 管理资金发放

上面代码创建了一个Escrow合约实例,该合约主要负责管理合约资金的发放。

contract Escrow {// 商品IDuint public productId;// 买房(中标者)address payable public buyer;// 卖方address payable public seller;    // 仲裁者address public arbiter;// 投标金额uint public amount;// 是否已经将投标金额支付给卖方或买方bool public isDisbursed;// 是否同意支付给卖方mapping(address => bool) isReleased;// 同意支付人数uint public releaseCount;// 是否同意退还给买方mapping(address => bool) isRefunded;// 同意退还人数uint public refundCount;event CreateEscrow(uint _productId, address _buyer, address _seller, address _arbiter);event UnlockAmount(uint _productId, string _operation, address _operator);event DisburseAmount(uint _productId, uint _amount, address _beneficiary);constructor(uint _productId, address _buyer, address _seller, address _arbiter) payable public {productId = _productId;buyer = _buyer;seller = _seller;arbiter = _arbiter;amount = msg.value;isRefunded= false;emit CreateEscrow(_productId, _buyer, _seller, _arbiter);}// 获取Escrow合约的详情function getEscrowInfo() public view returns(address, address, address, bool, uint, uint) {return(buyer, seller, arbiter, isDisbursed, releaseCount, refundCount);} // 只要有两位任意买方、卖方或仲裁者同意,那么就会向卖方发放投标金额function releaseToSeller(address caller) public {require(!isDisbursed, "支付状态必须是未支付");if ((caller == buyer || caller == seller || caller == arbiter) && !isReleased[caller]) {isReleased[caller] = true;releaseCount += 1;emit UnlockAmount(productId, "release", caller);}if (releaseCount == 2) {seller.transfer(amount);isDisbursed = true;emit DisburseAmount(productId, amount, seller);}}// 只要有两位任意买方、卖方或仲裁者同意,那么就会向买方退还投标金额function refundToBuyer(address caller) public {require(!isDisbursed, "支付状态必须是未支付");if ((caller == buyer || caller == seller || caller == arbiter) && !isFunded[caller]) {isRefunded[caller] = true;refundCount += 1;emit UnlockAmount(productId, "refund", caller); }if (releaseCount == 2) {buyer.transfer(amount);isDisbursed = true;emit DisburseAmount(productId, amount, buyer);}}
}

4.8 获取竞标赢家信息

// 获取竞标赢家信息
function getWinnerInfo(uint _productId) public view returns (address, uint ,uint) {Product memory product = stores[productIdInStore[_productId]][_productId];return (product.highestBidder, product.highestBid, product.secondHighestBid);
}// 获取竞拍人数
function getTotalBids(uint _productId) public view returns(uint) {Product memory product = stores[productIdInStore[_productId]][_productId];return (product.highestBidder, product.highestBid, product.secondHighestBid);
}

上面就是竞标合约的所有代码介绍。

Solidity智能合约开发(应用篇)相关推荐

  1. Solidity智能合约开发 — 1-以太坊开发工具和部署

    Solidity简介 solidity 是为实现智能合约而创建的一个高阶编程语言.也是以太坊虚拟机(EVM)智能合约的语言. Solidity开发工具remix remix是以太坊官方推荐的在线开发工 ...

  2. 以太坊智能合约开发第二篇:理解以太坊相关概念

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 很多人都说比特币是区块链1.0,以太坊是区块链2.0.在以太坊平台上,可以开发各种各样的去中心化应用,这些应用构成了以太 ...

  3. solidity智能合约开发简介

    1.solodity简介 Solidity语言是一种以太坊智能合约高级编程语言,运行在以太坊(Ethereum)虚拟机(EVM)之上. Solidity语言是一种语法类似JavaScript的高级编程 ...

  4. 区块链开发之Solidity智能合约开发

    在编写智能合约之前,需要有Solidity的开发环境,我将使用Remix来进行Solidity的学习,大家可以访问 Remix在线Solidity集成开发环境 其界面主要分三部分,左半本分是合约目录, ...

  5. Solidity智能合约开发 — 3.4-抽象智能合约和接口

    1. 抽象智能合约 假如一个智能合约中至少一个函数缺省实现时,即某个函数缺少{}中的内容,这个智能合约就当做抽象智能合约. 当我们有一个函数没想好怎么写时,必须将该合约标为abstract,不然编译会 ...

  6. Solidity智能合约开发(入门篇)

    一.版本声明 合约文件开头需要声明编译器的版本号,目的是为了该合约在未来版本的升级中引入了不兼容的编译器,其语法为: pragma solidity 版本号 版本号应该遵循"0.x.0&qu ...

  7. Solidity智能合约开发(提高篇)

    一.函数 1.1 函数定义 函数的定义格式: function 函数名(参数类型 参数名, ...) 修饰符 [returns(返回类型, ...)] {函数体 }示例: function sum(i ...

  8. Solidity智能合约开发 基础语法 | 文档 | 编译器 汇总

    文章目录 前言 Solidity源文件布局 Solidity源文件布局-- import Solidity值类型 Solidity引用类型 Solidity地址类型 地址类型成员变量 地址成员变量用法 ...

  9. solidity智能合约开发环境Atom下载及配置

    在Linux ubuntu 16.04系统中,几个文本编辑器对solidity支持都不好,没有语法高亮与自动缩进,使用起来很不方便.这里介绍针对solidity的Atom的安装及插件下载. 新版本的A ...

最新文章

  1. java中如何应对读改写场景
  2. (2)JavaScript数据类型
  3. 一梦江湖卡在获取服务器信息,一梦江湖小技巧,不氪金,卡级玩家怎么获取资源提升修为...
  4. java构造器_Java构造器就是这么简单!
  5. 华为5G微交易修复版源码 K线/结算全修复 去短信+去邀请码
  6. 程序员提高编程能力万无一失的办法
  7. Boost Asio Work类
  8. join()方法与CSV格式文件
  9. JavaEE笔记:第十九次课之AJAX
  10. 前阿里P10员工赵海平加入字节跳动,职级或为4+
  11. 捋一捋这些我记不清的python概念
  12. 看DeepMind如何用Reinforcement learning玩游戏
  13. 前端怎么画三角形_css如何画三角形?
  14. C语言鼠标病毒,鼠标也中毒Windows系统中鼠标乱动是否中了病毒
  15. 今天win10弹出了flash助手,禁用它
  16. 请问nj文件如何用html的解析,nj.renderH
  17. Sentinel Dashboard轻松流控
  18. 高斯混合模型参数估计的EM算法
  19. 使用mclust进行聚类分析
  20. php socket wss,websocket客户端无法建立wss连接

热门文章

  1. 不知道为什么输入12345,不能输出54321(c语言)
  2. 快餐店装修材料之石膏板吊顶的施工
  3. Java并发:乐观锁
  4. 最简单的RPC框架实现
  5. 前端学习笔记-07post请求和get请求,样式以及CSS
  6. 【python实现网络爬虫(3)】最简单的网络爬虫(笑话大全网冷笑话标题爬取)
  7. 一个老玩家对蛋蛋的认识
  8. 域名解析,一个域名可以对应多个IP地址(基于DNS的负载均衡)
  9. 中国5G、新能源汽车领先全球,将引领第四次工业革命
  10. Linux iptable