Smart Contracts using Solidity
Solidity is the most popular and de-facto programming language for developing smart contracts which run on the Ethereum network. Theoretically you can develop these smart contracts in other programming languages such as Serpent and LLL, however, the support for Solidity is far better.
Solidity follows a syntax similar to javascript, however, it has its own set of keywords and data-types. I would recommend everyone to read the Solidity language documentation to understand the basics of the language.
In this blog/tutorial, we will:
Solidity follows a syntax similar to javascript, however, it has its own set of keywords and data-types. I would recommend everyone to read the Solidity language documentation to understand the basics of the language.
In this blog/tutorial, we will:
- Build a smart contract to implement the royalty payout scenario, I had described earlier.
- Compile this smart contract.
- Deploy the contract to the test network.
- Going forward in future tutorials, we will be re-using the same smart contract for the complete development.
As with any programming language, there are numerous tools and frameworks that can be used for building an app. At times these can get too confusing and frustrating. I too had my share of confusion and frustration while evaluating the various tools required for building an Ethereum Dapp. After many trials and errors, I narrowed down to the following list of tools for the development. For this tutorial, we will be using the following software.
- Atom editor for all development work.
- Mist Ethereum Wallet.
- solc - the solidity CLI compiler.
I would also recommend installing npm and nodejs as these tools will be useful for development tasks that we will be doing in later tutorials.
Now let's revisit the use-case for which we are creating the smart contract. The plan was to create an audio fingerprint for each artifact that is published. Every time this artifact is played and used from any of the existing audio/video players, the ownership will be validated by a call to the Ethereum blockchain and the royalty will automatically be paid out.
In an enterprise solution, we would ideally need to slice out each audio file into several small pieces (say 5 seconds or 10 seconds long) and then audio fingerprint each of these slices and map them accordingly to the royalty payout structure. However, that would be too complicated an example for our tutorial. So let's treat each audio file as a whole and map this with the royalty structure corresponding to it. We will fingerprint the audio file using an SHA checksum. sha512sum is a utility which will return a sha512 hash for any file that you pass as input.
$ sha512sum 001-Yathiraja\ Vimsati-01.mp3
0e04a4d066d97b268731861cde93ab4086f5bba3c72824a5787bf4a055dd62e46c5e6d4034e33b5b7c2bac2dcb46050084cc67ca98e7de70a15b51a05a965396 001-Yathiraja Vimsati-01.mp3
The output of this command will be the sha512 hash string for the file provided as inpupt. Please make a note of the returned string. We will be needing this later on.
Now let's get on with the smart contract development. The contents of the artefact contract will be
- A human-readable name of the artifact.
- The sha512 checksum that represents the artifact. This will be used for identification of ownership.
- The owner of the artifact represented by an Ethereum address (which will basically be a wallet's address).
- And finally the royalty (commission) payout structure. This will usually be represented as which person (address) receives how much royalty (commission).
The smart contract for the above structure can be represented as follows:
pragma solidity ^0.4.0;
contract Artefact {
address owner;
string ARTEFACT_NAME;
string ARTEFACT_SIGNATURE;
//we have assumed a simple commission structure for this contract
address commReceiver;
uint commAmount;
modifier onlyOwner {
if (msg.sender != owner)
throw;
_;
}
function Aretfact(string _name,string _hash,address _receiver,uint _commAmount) {
owner = msg.sender;
ARTEFACT_NAME = _name;
ARTEFACT_SIGNATURE = _hash;
commReceiver = _receiver;
commAmount = _commAmount;
}
function getArtefactName() returns (string) {
return ARTEFACT_NAME;
}
function transferOwner(address _newOwner) onlyOwner {
if(msg.sender != owner) {
throw;
}
owner = _newOwner;
}
function payout() payable returns (bool){
if(msg.sender.balance != commAmount) {
throw;
}
return commReceiver.send(msg.value);
}
}
This is a very simple royalty contract where we have assumed only one royalty receiver per artifact. In a real life scenario, these contract hierarchies will be more complicated. We shall update the same smart contract to more complex logic during later phases of development.
I have declared a smart contract called Artefact, which contains the name of the artefact, its unique sha512 hash, the owner address, the royalty receiver address followed by the royalty amount. I have also declared a constructor for the Artefact, which will be called when a new object of this contract is created in the Ethereum block chain.
There are two methods in the contract. The first one transferOwner can be called if the ownership of the artefact can be transferred to another person. However please note that this method has the modifier onlyOwner, this means that the method call will work only if this function is called by the owner of the artefact. The second method payout, is called to payout the royalty. Ideally this method will be called everytime an instance of the artefact is sold or played.
In Ethereum parlance each method can be identified by two names. Any method that modifies the data in the block chain is called as transaction. Ethereum ensures that calls to such methods in smart contracts are chargeable. ie. a user needs to burn some ether to call such methods. The methods transferOwner and payout are transactions as they modify data on the Ethereum blockchain.
A method that doesn't modify data but only retrieves information from a block in the blockchain is known as a call. Calls do not require any ether to be burnt and they can be executed multiple times without spending any money. In the above example the method getArtefactName is and example of a call. This method doesn't require any ether to be spent.
The above smart contract can be compiled in many ways. We shall attempt to compile this using the solidity CLI compiler called solc. The solc compiler comes with various options. However we need to pay attention to 3 main options which are --gas --abi and --bin
$ solc --abi --gas --bin Artefact.sol
======= Artefact.sol:Artefact =======
Gas estimation:
construction:
339 + 301800 = 302139
external:
transferOwner(address): 20520
payout(): [???]
getArtefactName(): [???]
Aretfact(string,string,address,uint256): [???]
internal:
Binary:
6060604052341561000c57fe5b5b6105e58061001c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634fb2e45d1461005c57806363bd1d4a146100925780639f6d9e96146100b4578063da14920f1461014d575bfe5b341561006457fe5b610090600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610212565b005b61009a610310565b604051808215151515815260200191505060405180910390f35b34156100bc57fe5b6100c4610399565b6040518080602001828103825283818151815260200191508051906020019080838360008314610113575b805182526020831115610113576020820191506020810190506020830392506100ef565b505050905090810190601f16801561013f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015557fe5b610210600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610442565b005b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561026e57610000565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102ca57610000565b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b60006004543373ffffffffffffffffffffffffffffffffffffffff163114151561033957610000565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051809050600060405180830381858888f1935050505090505b90565b6103a1610500565b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104375780601f1061040c57610100808354040283529160200191610437565b820191906000526020600020905b81548152906001019060200180831161041a57829003601f168201915b505050505090505b90565b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360019080519060200190610499929190610514565b5082600290805190602001906104b0929190610514565b5081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806004819055505b50505050565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061055557805160ff1916838001178555610583565b82800160010185558215610583579182015b82811115610582578251825591602001919060010190610567565b5b5090506105909190610594565b5090565b6105b691905b808211156105b257600081600090555060010161059a565b5090565b905600a165627a7a7230582079c703f91d340746db078234dc880a9c2293cfa061a10dc01e0fe42e3f984f200029
Contract JSON ABI
[{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"payout","outputs":[{"name":"","type":"bool"}],"payable":true,"type":"function"},{"constant":false,"inputs":[],"name":"getArtefactName","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_hash","type":"string"},{"name":"_receiver","type":"address"},{"name":"_commAmount","type":"uint256"}],"name":"Aretfact","outputs":[],"payable":false,"type":"function"}]
--gas : will print estimate of gas usage for each function.
--abi : will generate a JSON string specifying all the variables and methods in the smart contract. This will be used by the web3 interface for invoking this smart contract from Dapps.
--bin : will generate the Ethereum Virtual Machine bytecode of the smart contract.
The output from this is necessary as we would be using this while deploying the contract to Ethereum blockchain. However if we are using the Mist wallet for contract deployment, these wont be required. Now that we have coded the contract, let's deploy it.
1. Open up Mist/Ethereum wallet. Ensure you are on TEST-NET
--abi : will generate a JSON string specifying all the variables and methods in the smart contract. This will be used by the web3 interface for invoking this smart contract from Dapps.
--bin : will generate the Ethereum Virtual Machine bytecode of the smart contract.
The output from this is necessary as we would be using this while deploying the contract to Ethereum blockchain. However if we are using the Mist wallet for contract deployment, these wont be required. Now that we have coded the contract, let's deploy it.
1. Open up Mist/Ethereum wallet. Ensure you are on TEST-NET
2. Click on CONTRACTS
3. Click on Deploy Contract and copy the source code of the contract from your Atom editor and paste it "SOLIDITY CONTRACT SOURCE CODE". Once you do this you will notice that the code automatically compiles and the contract name will appear on the right within the select box "Pick a contract".
4. Select your contract name (Artefact in this case) in the select box and then click on "DEPLOY" button present at the bottom of the screen. Once you click on the button, the deployment to the blockchain will take approximately 1 minute (the time taken for a new block to be mined and deployed). This would return an address of the contract location example
0x82ff2c0fc3abb2aa2db70c2d82914284fae8f29e2a127948010dadf7cee69266
Now that the contract has been deployed, we can start using it in Dapp application that we create next. In the next blog, I will demonstrate how to create a simple Dapp using which we shall create a new instance of the Smart Contract directly from our website.
The source code for this blog is available on github