W
W
Wethio
Search…
Smart Contract Development
Influenced by Python and JavaScript, Solidity is a contract-oriented, high-level programming language for the implementation of smart contracts. It runs the Ethereum Virtual Machine (EVM) both Ethereu

Solidity

Influenced by Python and JavaScript, Solidity is a contract-oriented, high-level programming language for the implementation of smart contracts. It runs the Ethereum Virtual Machine (EVM) both Ethereum and Wethio.
Features:
  • Statically typed
  • Supports libraries and inheritances
  • Underpins complex user-defined types
Solidity makes contract creation possible for crowdfunding, blind auctions, voting, multi-signature wallets, etc.
The next sections will take you through the Solidity in detail.

Demonstration

Solidity interprets contract as a collection of code (its functions) and data (its state) and stores it at a specific address on the Wethio blockchain.
In the code written, uint storedData declares a state variable storedData of type uint (u_nsigned int_eger of 256 bits). Understand it as a single slot in a database that you can query and make changes to by simply calling out the functions of the code that manages the database.

Compiler installation

Versioning

Solidity follows a semantic versioning pattern. All the releases and nightly development builds are made available. For the compiler to work smoothly, we recommend you to install Solidity compiler versions <=0.5.0.

Learning Solidity

Remix is recommended for small contracts and learning Solidity on-the-go. Remix is available for online access and no extra installation is required. If you do not have an internet connection, you can still use Remix by visiting https://github.com/ethereum/remix-live/tree/gh-pages and downloading the .zip file as instructed. One more advantage of Remix is that developers can test nightly builds without installing multiple Solidity versions.
In case you require further compilation options or if you are working on a larger contract, you can install commandline Solidity compiler software on your system. The above page provides detailed instructions about installing the software.
For using Remix with Wethio, you can start by connecting your Metamask to Wethio using Wethio’s RPC and follow this tutorial: (link)

Installing solcjs

With the use of npm/Node.js, you can install the solcjs, a Solidity compiler conveniently. The solcjs comprises fewer features and its usage is documented inside its own repository.

Samples

Voting

The following section talks about implementing a voting contract by using Solidity’s features. The major problem with electronic voting is assigning the voting rights to the correct persons and preventing manipulation. Instead of providing the complete solution here, we will showcase the process of conducting delegated voting so that vote counting is automatic and completely transparent.
The proceeding begins by creating one contract per ballot i.e. providing a short name for each option. The creator of the contract, i.e. chairperson, grants the right to vote to each address individually. Now the person behind the addresses has the option to either vote themselves or delegate their vote to a person they trust.
The winningProposal at the end of the voting time will return the proposal with the largest number of votes.
The below code is subject to change.
1
pragma solidity &gt;=0.4.22 &lt;=0.5.0;
2
3
/// @title Voting with delegation.
4
5
contract Ballot {
6
7
// This declares a new complex type which will
8
9
10
// be used for variables later.
11
12
// It will represent a single voter.
13
14
struct Voter {
15
16
uint weight; // weight is accumulated by delegation
17
18
bool voted; // if true, that person already voted
19
20
address delegate; // person delegated to
21
22
uint vote; // index of the voted proposal
23
24
}
25
26
// This is a type for a single proposal.
27
28
struct Proposal {
29
30
bytes32 name;
31
32
// short name (up to 32 bytes)
33
34
uint voteCount; // number of accumulated
35
36
votes
37
38
}
Copied!
1
address public chairperson;
2
// This declares a state variable that
3
// stores a `Voter` struct for each possible address.
4
mapping(address => Voter) public voters;
Copied!
1
// A dynamically-sized array of `Proposal` structs.
2
Proposal[] public proposals;
3
4
5
/// Create a new ballot to choose one of `proposalNames`.
6
constructor(bytes32[] memory proposalNames) public {
7
chairperson = msg.sender;
8
voters[chairperson].weight = 1;
Copied!
1
// For each of the provided proposal names,
2
// create a new proposal object and add it
3
// to the end of the array.
4
for (uint i = 0; i < proposalNames.length; i++) {
5
// `Proposal({...})` creates a temporary
6
// Proposal object and `proposals.push(...)`
7
// appends it to the end of `proposals`.
8
proposals.push(Proposal({
9
name: proposalNames[i],
10
voteCount: 0
11
}));
12
}
13
}
Copied!
1
// Give `voter` the right to vote on this ballot.
2
// May only be called by `chairperson`.
3
function giveRightToVote(address voter) public {
4
// If the first argument of `require` evaluates
5
// to `false`, execution terminates and all
6
// changes to the state and to ZYN balances
7
// are reverted.
8
// This used to consume all gas in old EVM versions, but
9
// not anymore.
10
// It is often a good idea to use `require` to check if
11
// functions are called correctly.
12
// As a second argument, you can also provide an
13
// explanation about what went wrong.
14
require(
15
msg.sender == chairperson,
16
"Only chairperson can give right to vote."
17
);
18
require(
19
!voters[voter].voted,
20
"The voter already voted."
21
);
22
require(voters[voter].weight == 0);
23
voters[voter].weight = 1;
24
}
Copied!
1
/// Delegate your vote to the voter `to`.
2
function delegate(address to) public {
3
// assigns reference
4
Voter storage sender = voters[msg.sender];
5
require(!sender.voted, "You already voted.");
6
7
8
require(to != msg.sender, "Self-delegation is disallowed.");
9
10
11
// Forward the delegation as long as
12
// `to` also delegated.
13
// In general, such loops are very dangerous,
14
// because if they run too long, they might
15
// need more gas than is available in a block.
16
// In this case, the delegation will not be executed,
17
// but in other situations, such loops might
18
// cause a contract to get "stuck" completely.
19
while (voters[to].delegate != address(0)) {
20
to = voters[to].delegate;
21
22
23
// We found a loop in the delegation, not allowed.
24
require(to != msg.sender, "Found loop in delegation.");
25
};
26
// Since `sender` is a reference, this
27
// modifies `voters[msg.sender].voted`
28
sender.voted = true;
29
sender.delegate = to;
30
Voter storage delegate_ = voters[to];
31
if (delegate_.voted) {
32
// If the delegate already voted,
33
// directly add to the number of votes
34
proposals[delegate_.vote].voteCount += sender.weight;
35
} else {
36
// If the delegate did not vote yet,
37
// add to her weight.
38
delegate_.weight += sender.weight;
39
}
40
}
Copied!
1
/// Give your vote (including votes delegated to you)
2
/// to proposal `proposals[proposal].name`.
3
function vote(uint proposal) public {
4
Voter storage sender = voters[msg.sender];
5
require(sender.weight != 0, "Has no right to vote");
6
require(!sender.voted, "Already voted.");
7
sender.voted = true;
8
sender.vote = proposal;
9
10
11
// If `proposal` is out of the range of the array,
12
// this will throw automatically and revert all
13
// changes.
14
proposals[proposal].voteCount += sender.weight;
15
}
16
17
18
/// @dev Computes the winning proposal taking all
19
/// previous votes into account.
20
function winningProposal() public view
21
returns (uint winningProposal_)
22
{
23
uint winningVoteCount = 0;
24
for (uint p = 0; p winningVoteCount) {
25
winningVoteCount = proposals[p].voteCount;
26
winningProposal_ = p;
27
}
28
}
29
}
30
31
32
// Calls winningProposal() function to get the index
33
// of the winner contained in the proposals array and then
34
// returns the name of the winner
35
function winnerName() public view
36
returns (bytes32 winnerName_)
37
{
38
winnerName_ = proposals[winningProposal()].name;
39
}
40
}
Copied!

Blind Auction

Another sample we will talk about is creating a blind auction contract on Wethio. We will showcase how at first we start with an open auction, where every bid that is made is visible to everyone and then extend it into a blind auction where it is not possible to see the actual bid till the end of the bidding process.

Understanding simple open auction

A simple open auction contract means everyone can send their bids during the bidding period. Sending ZYN/money is necessary to bid in order to bind the bidders to their bid. When the highest bid is made, the previously highest bidder gets their money back. Contact has to be called manually for the beneficiary to receive the money at the end of the bidding period as contracts cannot activate themselves.
The below code is subject to change.
1
pragma solidity >=0.4.22 <=0.5.0;
2
3
contract SimpleAuction {
4
// Parameters of the auction. Times are either
5
// absolute unix timestamps (seconds since 1970-01-01)
6
// or time periods in seconds.
7
address payable public beneficiary;
8
uint public auctionEndTime;
9
10
// Current state of the auction.
11
address public highestBidder;
12
uint public highestBid;
13
14
// Allowed withdrawals of previous bids
15
mapping(address => uint) pendingReturns;
16
17
// Set to true at the end, disallows any change.
18
// By default initialized to `false`.
19
bool ended;
20
21
// Events that will be emitted on changes.
22
event HighestBidIncreased(address bidder, uint amount);
23
event AuctionEnded(address winner, uint amount);
24
25
// The following is a so-called natspec comment,
26
// recognizable by the three slashes.
27
// It will be shown when the user is asked to
28
// confirm a transaction.
29
30
/// Create a simple auction with `_biddingTime`
31
/// seconds bidding time on behalf of the
32
/// beneficiary address `_beneficiary`.
33
constructor(
34
uint _biddingTime,
35
address payable _beneficiary
36
) public {
37
beneficiary = _beneficiary;
38
auctionEndTime = now + _biddingTime;
39
}
40
41
/// Bid on the auction with the value sent
42
/// together with this transaction.
43
/// The value will only be refunded if the
44
/// auction is not won.
45
function bid() public payable {
46
// No arguments are necessary, all
47
// information is already part of
48
// the transaction. The keyword payable
49
// is required for the function to
50
// be able to receive ZYN.
51
52
// Revert the call if the bidding
53
// period is over.
54
require(
55
now <= auctionEndTime,
56
"Auction already ended."
57
);
58
59
// If the bid is not higher, send the
60
// money back (the failing require
61
// will revert all changes in this
62
// function execution including
63
// it having received the money).
64
require(
65
msg.value > highestBid,
66
"There already is a higher bid."
67
);
68
69
if (highestBid != 0) {
70
// Sending back the money by simply using
71
// highestBidder.send(highestBid) is a security risk
72
// because it could execute an untrusted contract.
73
// It is always safer to let the recipients
74
// withdraw their money themselves.
75
pendingReturns[highestBidder] += highestBid;
76
}
77
highestBidder = msg.sender;
78
highestBid = msg.value;
79
emit HighestBidIncreased(msg.sender, msg.value);
80
}
81
82
/// Withdraw a bid that was overbid.
83
function withdraw() public returns (bool) {
84
uint amount = pendingReturns[msg.sender];
85
if (amount > 0) {
86
// It is important to set this to zero because the recipient
87
// can call this function again as part of the receiving call
88
// before `send` returns.
89
pendingReturns[msg.sender] = 0;
90
91
if (!msg.sender.send(amount)) {
92
// No need to call throw here, just reset the amount owing
93
pendingReturns[msg.sender] = amount;
94
return false;
95
}
96
}
97
return true;
98
}
99
100
/// End the auction and send the highest bid
101
/// to the beneficiary.
102
function auctionEnd() public {
103
// It is a good guideline to structure functions that interact
104
// with other contracts (i.e. they call functions or send ZYN)
105
// into three phases:
106
// 1. checking conditions
107
// 2. performing actions (potentially changing conditions)
108
// 3. interacting with other contracts
109
// If these phases are mixed up, the other contract could call
110
// back into the current contract and modify the state or cause
111
// effects (ZYN payout) to be performed multiple times.
112
// If functions called internally include interaction with external
113
// contracts, they also have to be considered interaction with
114
// external contracts.
115
116
// 1. Conditions
117
require(now >= auctionEndTime, "Auction not yet ended.");
118
require(!ended, "auctionEnd has already been called.");
119
120
// 2. Effects
121
ended = true;
122
emit AuctionEnded(highestBidder, highestBid);
123
124
// 3. Interaction
125
beneficiary.transfer(highestBid);
126
}
127
}
Copied!

Blind Auction

Here we will extend the open auction into the blind auction. Cryptography enables a fair mechanism of creating a blind auction on a transparent computing platform. One major advantage of a blind auction is the absence of any time pressure at the end of the bidding period.
When the bidding is on, the bidder doesn’t actually send their bid, but only a hashed version of it. Since it is currently considered practically impossible to find two (sufficiently long) values whose hash values are equal, the bidder commits to the bid by that. Once the bidding period ends, the bidders have to reveal their bids by sending their values unencrypted. The contract then matches if the hash value is the same as the one provided during the auction.
Making the auction binding and blind at the same time is a difficult task. Value transfers cannot be blinded with Wethio and anyone can see the value. This makes it possible to prevent the bidder from sending the money after they won the auction and make them send it together with the bid.
The below contract showcases how to solve this problem by accepting any value that is larger than the highest bid.
The below code is subject to change
1
pragma solidity >0.4.23 <=0.5.0;
2
3
contract BlindAuction {
4
struct Bid {
5
bytes32 blindedBid;
6
uint deposit;
7
}
8
9
address payable public beneficiary;
10
uint public biddingEnd;
11
uint public revealEnd;
12
bool public ended;
13
14
mapping(address => Bid[]) public bids;
15
16
address public highestBidder;
17
uint public highestBid;
18
19
// Allowed withdrawals of previous bids
20
mapping(address => uint) pendingReturns;
21
22
event AuctionEnded(address winner, uint highestBid);
23
24
/// Modifiers are a convenient way to validate inputs to
25
/// functions. `onlyBefore` is applied to `bid` below:
26
/// The new function body is the modifier's body where
27
/// `_` is replaced by the old function body.
28
modifier onlyBefore(uint _time) { require(now < _time); _; }
29
modifier onlyAfter(uint _time) { require(now > _time); _; }
30
31
constructor(
32
uint _biddingTime,
33
uint _revealTime,
34
address payable _beneficiary
35
) public {
36
beneficiary = _beneficiary;
37
biddingEnd = now + _biddingTime;
38
revealEnd = biddingEnd + _revealTime;
39
}
40
41
/// Place a blinded bid with `_blindedBid` =
42
/// keccak256(abi.encodePacked(value, fake, secret)).
43
/// The sent ZYN is only refunded if the bid is correctly
44
/// revealed in the revealing phase. The bid is valid if the
45
/// ZYN sent together with the bid is at least "value" and
46
/// "fake" is not true. Setting "fake" to true and sending
47
/// not the exact amount are ways to hide the real bid but
48
/// still make the required deposit. The same address can
49
/// place multiple bids.
50
function bid(bytes32 _blindedBid)
51
public
52
payable
53
onlyBefore(biddingEnd)
54
{
55
bids[msg.sender].push(Bid({
56
blindedBid: _blindedBid,
57
deposit: msg.value
58
}));
59
}
60
61
/// Reveal your blinded bids. You will get a refund for all
62
/// correctly blinded invalid bids and for all bids except for
63
/// the totally highest.
64
function reveal(
65
uint[] memory _values,
66
bool[] memory _fake,
67
bytes32[] memory _secret
68
)
69
public
70
onlyAfter(biddingEnd)
71
onlyBefore(revealEnd)
72
{
73
uint length = bids[msg.sender].length;
74
require(_values.length == length);
75
require(_fake.length == length);
76
require(_secret.length == length);
77
78
uint refund;
79
for (uint i = 0; i < length; i++) {
80
Bid storage bidToCheck = bids[msg.sender][i];
81
(uint value, bool fake, bytes32 secret) =
82
(_values[i], _fake[i], _secret[i]);
83
if (bidToCheck.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) {
84
// Bid was not actually revealed.
85
// Do not refund deposit.
86
continue;
87
}
88
refund += bidToCheck.deposit;
89
if (!fake && bidToCheck.deposit >= value) {
90
if (placeBid(msg.sender, value))
91
refund -= value;
92
}
93
// Make it impossible for the sender to re-claim
94
// the same deposit.
95
bidToCheck.blindedBid = bytes32(0);
96
}
97
msg.sender.transfer(refund);
98
}
99
100
/// Withdraw a bid that was overbid.
101
function withdraw() public {
102
uint amount = pendingReturns[msg.sender];
103
if (amount > 0) {
104
// It is important to set this to zero because the recipient
105
// can call this function again as part of the receiving call
106
// before `transfer` returns (see the remark above about
107
// conditions -> effects -> interaction).
108
pendingReturns[msg.sender] = 0;
109
110
msg.sender.transfer(amount);
111
}
112
}
113
114
/// End the auction and send the highest bid
115
/// to the beneficiary.
116
function auctionEnd()
117
public
118
onlyAfter(revealEnd)
119
{
120
require(!ended);
121
emit AuctionEnded(highestBidder, highestBid);
122
ended = true;
123
beneficiary.transfer(highestBid);
124
}
125
126
// This is an "internal" function which means that it
127
// can only be called from the contract itself (or from
128
// derived contracts).
129
function placeBid(address bidder, uint value) internal
130
returns (bool success)
131
{
132
if (value <= highestBid) {
133
return false;
134
}
135
if (highestBidder != address(0)) {
136
// Refund the previously highest bidder.
137
pendingReturns[highestBidder] += highestBid;
138
}
139
highestBid = value;
140
highestBidder = bidder;
141
return true;
142
}
143
}
Copied!

Modular Contracts

Identifying bugs and vulnerabilities during development and code review can be a challenging task. Taking a modular approach in building your contracts can solve this problem by reducing the complexity and improving the readability of the code.
Specifying and controlling the behavior of each module in isolation restricts the interactions between the module specifications and not every other moving part of the contract. The below example shows how the contract uses the move method of the Balances library to check and match the balances sent between addresses. In this way, the Balances library provides an isolated component that properly tracks balances of accounts.
Due to which, it becomes easy to verify that the Balances library never produces negative balances or overflows and the sum of all balances is an invariant across the lifetime of the contract.
The below code is subject to change
1
pragma solidity >=0.4.22 <=0.5.0;
2
3
library Balances {
4
function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal {
5
require(balances[from] >= amount);
6
require(balances[to] + amount >= balances[to]);
7
balances[from] -= amount;
8
balances[to] += amount;
9
}
10
}
11
12
13
contract Token {
14
mapping(address => uint256) balances;
15
using Balances for *;
16
mapping(address => mapping (address => uint256)) allowed;
17
18
event Transfer(address from, address to, uint amount);
19
event Approval(address owner, address spender, uint amount);
20
21
function transfer(address to, uint amount) public returns (bool success) {
22
balances.move(msg.sender, to, amount);
23
emit Transfer(msg.sender, to, amount);
24
return true;
25
26
}
27
28
function transferFrom(address from, address to, uint amount) public returns (bool success) {
29
require(allowed[from][msg.sender] >= amount);
30
allowed[from][msg.sender] -= amount;
31
balances.move(from, to, amount);
32
emit Transfer(from, to, amount);
33
return true;
34
}
35
36
function approve(address spender, uint tokens) public returns (bool success) {
37
require(allowed[msg.sender][spender] == 0, "");
38
allowed[msg.sender][spender] = tokens;
39
emit Approval(msg.sender, spender, tokens);
40
return true;
41
}
42
43
function balanceOf(address tokenOwner) public view returns (uint balance) {
44
return balances[tokenOwner];
45
}
46
}
Copied!
Last modified 1yr ago