Creating Smart Contracts in RSK

Meri Herrera edited this page Oct 3, 2018 · 3 revisions

Structure of a smart contract

As we mentioned before RSK Smart contracts are compatible with Ethereum contracts, in this part we will show the basics about some key concept, it is not intented to teach all the details about Solidity or Smart contracts, it's just and introduction.

Let's start!

In order to learn the basics about smart contracts in Solidity we going take a look to a simple contract

pragma solidity ^0.4.4;

contract StoreSomeData {
    // the current state of the contract is represented
    // for the value of all it's data members in a given time
    uint storedData;

    // allows to set a value
    function set(uint i) {
        storedData = i;
    }

    // returns the current value
    function get() constant returns (uint) {
        return storedData;
    }
}

In this example there're some interesting details:

  • The storeData field is of type uint and by default it's private, so you can't access to it from the outside. In the other side if you don't add the private modifier all methods will be accesible from the outside.
  • The set function receives a uint paramater and assigns it's value to storeData, note that this function doesn't return any value.
  • The get function uses the returns keyword because it returns the storeData value, also includes the type unit additionally you can assign a name to the return value, something like that return (uint stored)
  • Last but not least the get function uses the constant modifier, it indicates that the function does not modify the state of the contract (since it is a getter) more details here

An important concept, if we do something that changes the contract (and the blockchain) status, that will costs us Gas and also will require a transaction.

Constructs

pragma solidity ^0.4.4;

contract CreatorAddress {

    // stores the address of the contract creator
    address creator;

    // contract constructos, it's executed once when the contracts is put into a transaction
    function CreatorAddress(){
      creator = msg.sender;
    }

    function getAddress() constant returns (address creatorAdress) {
        return creator;
    }
}

Deploy the contract in the blockchain.

var creatorAddress = null;
CreatorAddress.deployed().then(function(instance){ creatorAddress = instance;});
creatorAddress.getAddress();
0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826

We stored the address that puts the contract into a trasaction and the we can retrive it.

Killing a contract

If we create a contract then we don't want it to be used anymore we can suicide the contract and additionally get the unused funds back, considere the next example:

pragma solidity ^0.4.4;

contract CreatorAddress {

    // stores the address of the contract creator
    address creator;

    // contract constructos, it's executed once when the contracts is put into a transaction
    function CreatorAddress(){
      creator = msg.sender;
    }

    function getAddress() constant returns (address creatorAdress) {
        return creator;
    }
        
    function kill(){ 
        if (msg.sender == creator)
            suicide(creator);  // kills this contract and sends remaining funds back to creator
    }
}

Note that the kill function can be called in order to suicide this contract, we added a validation to only allow the creator to kill the contract.

More realistic example

One basic but interesting use of Smart Contracts is storing data forever without the possibility of changing, imagine this scenario: I want to register something I created, let's say an image, I can use some software application to get the SHA256 hash of the image, then store this value into a Smart Contract so this hash will last forever without the change to be changed by somebody else, in case someone try to copy mi work I can demostrate that I have the original image and the hash was registered some time ago before this other person copied it, cool. But, how can we implement that?

pragma solidity ^0.4.4;

contract StoreHash {

    // stores the address of the contract creator
    address creator;
    bytes32 storedHash;

    // the contract's creator sends the hash and it's stored forever
    function StoreHash(bytes32 hash){
      creator = msg.sender;
      storedHash = hash;
    }

    function getHash() constant returns (bytes32) {
        return storedHash;
    }
    
    function kill(){ 
        if (msg.sender == creator)
            suicide(creator);
    }
}

Quite simple, we stored a 32 bytes hash while constructing the contract (during the publish process) and then it cannot be modified, just queried.

Every transaction must specify a quantity of "gas" that it is willing to consume (called startgas), and the fee that it is willing to pay per unit gas (gasprice). At the start of execution, startgas x gasprice RBTC are removed from the transaction sender's account.

Step by step example

pragma solidity ^0.4.6;

contract WinnerTakesAll {

    uint minimumEntryFee;
    uint public deadlineProjects;
    uint public deadlineCampaign;
    uint public winningFunds;
    address public winningAddress;

    struct Project {
        address addr;
        string name;
        string url;
        uint funds;
        bool initialized;
    }

    mapping (address => Project) projects;
    address[] public projectAddresses;
    uint public numberOfProjects;

    event ProjectSubmitted(address addr, string name, string url, bool initialized);
    event ProjectSupported(address addr, uint amount);
    event PayedOutTo(address addr, uint winningFunds);

    function WinnerTakesAll(uint _minimumEntryFee, uint _durationProjects, uint _durationCampaign) public {
        
        if (_durationCampaign <= _durationProjects) {
            throw;
        }
        
        minimumEntryFee = _minimumEntryFee;
        deadlineProjects = now + _durationProjects* 1 seconds;
        deadlineCampaign = now + _durationCampaign * 1 seconds;
        winningAddress = msg.sender;
        winningFunds = 0;
    }

    function submitProject(string name, string url) payable public returns (bool success) {
        
        if (msg.value < minimumEntryFee) {
            throw;
        }
        
        if (now > deadlineProjects) {
            throw;
        }
        
        if (!projects[msg.sender].initialized) {
          
            projects[msg.sender] = Project(msg.sender, name, url, 0, true);
            projectAddresses.push(msg.sender);
            numberOfProjects = projectAddresses.length;
            ProjectSubmitted(msg.sender, name, url, projects[msg.sender].initialized);
            return true;
        }
        
        return false;
    }

    function supportProject(address addr) payable public returns (bool success) {
        
        if (msg.value <= 0) {
            throw;
        }
        
        if (now > deadlineCampaign || now <= deadlineProjects) {
            throw;
        }
        
        if (!projects[addr].initialized) {
            throw;
        }
        
        projects[addr].funds += msg.value;
        
        if (projects[addr].funds > winningFunds) {
            winningAddress = addr;
            winningFunds = projects[addr].funds;
        }
        
        ProjectSupported(addr, msg.value);
        return true;
    }
    
    function getProjectInfo(address addr) public constant returns (string name, string url, uint funds) {
        var project = projects[addr];
        
        if (!project.initialized) {
            throw;
        }
        
        return (project.name, project.url, project.funds);
    }
    
    function finish() {
        
        if (now >= deadlineCampaign) {
            PayedOutTo(winningAddress, winningFunds);
            selfdestruct(winningAddress);
        }
    }
}




Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.