In this lesson, we will
write a contract and execute it on a test blockchain. The Ownable contract uses solidity 0.4.8, which is not the current
version of solidity. For this reason we will debug the contract, replacing
deprecated terms and syntax.
If you have not, you
will need to download Visual Studio Code and install
Juan Blanco’s Solidity
compiler. You will need to download and install Node.js. This will
allow you to download and install truffle with the command:
npm install truffle
You will also need to
download and install Ganache, which will
automatically set up the test blockchain.
To start, open
PowerShell to start a new project with Truffle. Navigate to your desired
directory and create a new folder with the mkdir
command. Since we will build the Ownable contract in this folder, name
the folder ownable:
mkdir ownable
cd ownable
Once you have navigated
to the new folder, create a new project using truffle:
truffle init
The console should
return the following text:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
Now that you have initialized a project with
truffle, it is time to create a contract. We are going to copy a contract from
Chapter 7, page 148, of Blockchain: A PracticalGuide to Developing Business, Law, and Technology Solutions.
Write the following code in a Visual Studio file
and save it as Ownable.sol under the contracts folder, created during the truffle
initialization of the ownable folder.
pragma solidity ^0.4.8;
// module handling and transfer of contract ownership
contract Ownable {
address public owner;
function Ownable() {
owner = msg.sender;
}
modifier onlyOwner {
if(msg.sender != owner) revert();
_;
}
function transferOwnership(address _newOwner) external onlyOwner {
owner = _newOwner;
TransferOwnership(msg.sender, _newOwner);
}
event TransferOwnership(address indexed _from, address indexed _to);
}
Now compile your code. You may use the short-cut F5 for this. Make sure that you have
opened the file explorer. If not, you can use the command CTRL + SHIFT + E.
Upon compiling the code, you should see a list of errors, under the PROBLEMS
tab. We will solve these one at a time.
Debugging
The first error is not significant to the
execution of the program. To make it disappear, we can enter a command above
the first line:
//solium-disable linebreak-style
pragma solidity ^0.4.8;
// module handling and
transfer of contract ownership
...
The next two errors appear on line 6:
The first error indicates we should have specified
and access keyword like: public, private, internal or external. The second
error notes that constructor() should
be used to define a constructor for the class instead of function Ownable(). Edit the script to reflect this:
contract Ownable {
address public owner;
constructor() public {
owner =
msg.sender;
...
We change function
Ownable() to constructor(). We
also add the term public after the
constructor. This allows the constructor to be called from both inside and outside
of the contract.
A comprehensive list of visibility keywords for
functions and state variables:
·
public - all can access the referenced object
·
external – The object cannot be accessed from outside
of the contract
·
internal - only this contract and contracts deriving
from it can access the object
·
private – the object can only be accessed only from
this contract
After making the edits for the constructor, the
errors for line 6 have disappeared.
Next is an error concerning the calling of revert(). The error suggests that a string should be
passed into the revert function. We could pass one like this:
modifier onlyOwner {
if (msg.sender != owner) revert(“Error: non-owner access
denied”);
_;
...
The error disappears, but when we upload the
contract to the blockchain, this will require more gas than if we do not pass a
string to revert(). For now, we can
leave this blank. The error will not affect anything.
To solve the next error, we need to call the event
on line 15 using the term emit. This
is required by more recent versions of solidity:
function transferOwnership(address
_newOwner) external onlyOwner {
owner = _newOwner;
emit TransferOwnership(msg.sender, _newOwner);
}
...
If you have followed the instructions to this point, there
should remain only the error concerning require() from line 6. The contract is ready
to be executed. Before we do this, we will need to create a migration file for
the Ownable contract and modify the Truffle.js file to point to a private
blockchain.
Compile and Migrate
In order to upload the contract, we need to first convert
the contract to a form that is readable in javascript. Then, this will be
converted to byte code which is uploaded to the blockchain.
Using Visual Studio let’s create a javascript file
called 2_ownable_migration.js , and save
it under the ownable/migrations folder.
var Ownable = artifacts.require('./Ownable.sol');
module.exports = function(deployer) {
deployer.deploy(Ownable);
};
When the files are compiled using truffle, this script will
be used to upload to the blockchain the json file representing the compiled
contract.
Next, edit the truffle.js file, located in the ownable folder.
This file identifies the network that will be used to locate the test
blockchain to which we will upload the contract. Replace this code:
module.exports = {
// See
<http://truffleframework.com/docs/advanced/configuration>
// to customize your
Truffle configuration!
};
With the following:
module.exports = {
networks: {
development: {
host: 'localhost',
port: 7545,
network_id: '*'
}
}
};
This points to the test blockchain on your local machine, that
is created when you launch Ganache.
Now that everything is ready, make sure that you have
navigated in the PowerShell to the ownable
folder. Compile the contract using the commands:
truffle compile
If you were successful, you should see the
following text:
Compiling .\contracts\Migrations.sol...
Compiling .\contracts\Ownable.sol...
Writing artifacts to .\build\contracts
Next, migrate the contracts to the blockchain.
First, we will need to open Ganache so that there is a blockchain with which we
can interact through truffle. When you launch Ganache, you will see the
accounts created for the test blockchain:
Only the genesis block has been created. We will
now upload the contract to the test blockchain by using the command:
truffle migrate
This will yield the following in the PowerShell
Using network 'development'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x2bcc6f737e1244ee9be0db52bf59dd0e954b4c3c9ae2028b3f4479bd13d57cd6
Migrations: 0xe9ab13bb64959432cf38416759cc2e4c0db7d6be
Saving successful migration to network...
... 0x661b37c2202a45457151ec65f23f15080f23238724c8d665db12df4bb67a6afc
Saving artifacts...
Running migration: 2_ownable_migration.js
Deploying Ownable...
... 0x6603eaf64060e817a202810c5b6f717f3492a2f5d07fcef221b2af45057f5773
Ownable: 0xcea93908c932064d61cd2dd1f72c974b190cc3ce
Saving successful migration to network...
... 0x6bfd670baad0f28816e6d0df7f2b9cd40e64b32fa70d2e3da73c241edcb09f47
Saving artifacts...
This reflects that blocks have been added to the
genesis block. We also observe this in Ganache:
Create an
Instance of the Contract
Now we can call the truffle console. Since we have
already edited the truffle.js file, truffle will automatically connect to the
network housing the test blockchain.
truffle console
If you have successfully connected the network
provided by Ganache, you should see the following:
truffle(development)>
To create an instance of the contract, we must
first create a variable using javascript commands. Enter the following lines
one by one into the truffle console:
var ownable;
Ownable.deployed().then(function(instance){ownable = instance;})
ownable.transferOwnership(web3.eth.accounts[1]);
The command var
ownable; creates a new
object called ownable. The next line
defines this object as an instance of the contract that we created.
After both commands the truffle console will
return the result ‘undefined’.
If you are familiar with programming already, you
will see that the contract is essentially a class. Finally we transfer
ownership of the contract from the account identified by index [0] to the
account identified by index[1].
The event is executed and logged, yielding the
following text in the console:
{ tx: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
receipt:
{ transactionHash: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
transactionIndex: 0,
blockHash: '0xa433b974f3ea4ae87aa94229263f64b2b3947056d77ca7be6212a569a5d8cf27',
blockNumber: 5,
gasUsed: 29986,
cumulativeGasUsed: 29986,
contractAddress: null,
logs: [ [Object] ],
status: '0x1',
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000400000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000800000000000004010002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000060000000000000000000000000000100000' },
logs:
[ { logIndex: 0,
transactionIndex: 0,
transactionHash: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
blockHash: '0xa433b974f3ea4ae87aa94229263f64b2b3947056d77ca7be6212a569a5d8cf27',
blockNumber: 5,
address: '0xcea93908c932064d61cd2dd1f72c974b190cc3ce',
type: 'mined',
event: 'TransferOwnership',
args: [Object] } ] }
Congratulations, you have successfully built and
executed your first contract!
*Ingrid Caton shares credit for this post
No comments:
Post a Comment