Skip to content

Instantly share code, notes, and snippets.

@subhodi
Last active April 25, 2023 04:05
Show Gist options
  • Save subhodi/0cdec0ddbef26890d2b976aef04ee799 to your computer and use it in GitHub Desktop.
Save subhodi/0cdec0ddbef26890d2b976aef04ee799 to your computer and use it in GitHub Desktop.
Solidity

1. Online solidity compiler


Online IDE with solidity compiler https://remix.ethereum.org/#version=soljson-v0.4.15+commit.bbb8e64f.js

Accounts:

0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c

0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C

0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB

0x583031D1113aD414F02576BD6afaBfb302140225

0xdD870fA1b7C4700F2BD7f44238821C26f7392148

2. Smart contract


pragma solidity ^0.4.15; // Compiler version

contract SimpleStorage { // Contract declartion
    uint storedData;     // State variable

	 //Write Transaction
    function setStoredData(uint x) {    
        storedData = x;
    }

	//Read State data
    function getStoredData() constant returns (uint) {
        return storedData;
    }
}

3. Data types in solidity


pragma solidity ^0.4.15;
contract Data {
    
    uint public  number=90;  
    bool public flag=true;
    address public addr=0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;  
    bytes32 public welcomeMsg="Hi there";
    string public str="Welcome to Smart contract class";

    enum ActionChoices { GoLeft, GoRight, GoStraight }
    ActionChoices public choice;
    uint[10] public array=[1,2,3,4,5,6,7,8,9,10];
    uint[] public dynamicArray=[11,12,13];

    mapping(address=>uint) public balances; // mapping(key=>value) variableName;
    struct User {
        uint id;
        uint balance;
    }
    User public user;
    
    function Data() {  // constructor
        user=User(101,1000);
        balances[addr]=50;
        choice = ActionChoices.GoRight;
    }

}

4. Loan


pragma solidity ^0.4.15;
contract  Bank {
    
        address public owner;  // owner of the contract
        
        struct Loan {  // Loan structure
           uint id;
           address borrower;
           string name;
           uint amount;
           string reason;
           string status;
       }
       
        uint totalLoan=0;  // count of total loans
        
        mapping(address => Loan) loans; // mapping address to loan
        
        // constructor executed when deploying the contract into network
        // `msg.sender` is the account creating this contract.
        function Bank() payable {
            owner = msg.sender; 
        }
        
        // transaction to request Loan
        function requestLoan(string username, uint amount, string loanReason) { 
            loans[msg.sender] = Loan(totalLoan, msg.sender, username, amount, loanReason, "Requested"); // add Loan object to mapping
            totalLoan++;
        }
        
        // get loan details
        function getLoan(address addr) constant returns(uint, string, uint, string, string) {
            Loan memory l = loans[addr];
            return (l.id, l.name, l.amount, l.reason, l.status);
        }
        
        // transaction to approve Loan based on key address 
        function approveLoan(address addr) {
            require(msg.sender == owner);
            loans[addr].status="Accepted";
            addr.transfer(loans[addr].amount);
        }
    
        // reject 
        function rejectLoan(address addr) {
            require(msg.sender == owner);
            loans[addr].status="Rejected";
        }
        
        // get Balance
        function getBalance() constant returns(uint){
            return this.balance;
        }
}

5. Access control using modifiers


pragma solidity ^0.4.15;

contract AccessRestriction {
    // `msg.sender` is the account creating this contract.
    address public owner = msg.sender;
    
    modifier onlyBy() {
        require(msg.sender == owner); // Equal to if(msg.sender != account ) throw;
        _; // It returns the flow of execution
    }

    // Make `newOwner` the new owner of this contract
    function changeOwner(address newOwner) onlyBy  {
        owner = newOwner;
    }

}

Multiple modifiers usage : Contract as a middleman

pragma solidity ^0.4.15;
// PSLkart  : contract as a escrow between buyer and seller
contract PSLkart {
    // State of Product
    enum ProductState {
        OnSale,
        PaymentReceived,
        Delivered
    }
    // Strcuture for Product
    struct Product {
        string name;  
        uint price;   
        address seller; 
        address buyer;
        ProductState productState; // Product state : OnSale, PaymentReceived, Delivered
    }
    mapping(address => Product) public products; // Mapping seller address to selling item , one to one mapping
                        
    
    modifier checkForSale(uint _price) { // modifier for sell function
        require( _price >0 &&   // Check price of the selling product
                 products[msg.sender].productState != ProductState.PaymentReceived); // product state should be either Onsale or Delivered
        _; // continue 
    }
    
     modifier checkForBuy(address _seller) { // modifer for buy function
        require( msg.value == products[_seller].price  &&   // msg.value(Ether sent along with function) should be equal to price of the selling product
                 products[_seller].productState == ProductState.OnSale); // can only buy if the product is on sale
        _;
    }
    
     modifier checkConfirmedReceived(address _seller) {  // modifier for confirmReceived function
        require( products[_seller].productState == ProductState.PaymentReceived &&  // buyer can confirm only if product state is PaymentReceived
                 msg.sender == products[_seller].buyer); // msg.sender(trasnaction origin account) should be eqal to buyer; only buyer can confirm
        _;
    }
    
    
    function sell(string _name, uint _price) public checkForSale(_price){ // seller posting product on sale
        products[msg.sender] = Product(_name, _price, msg.sender, 0x0, ProductState.OnSale );
    }
    
    function buy(address _seller) public payable checkForBuy(_seller) { // buyer- buys the product by sending product price amount of ethers along with transaction
        products[_seller].buyer = msg.sender;
        products[_seller].productState = ProductState.PaymentReceived;
    }
    
    function confirmReceived(address _seller) public checkConfirmedReceived(_seller) { // Buyer confirms the product delivery
        products[_seller].productState = ProductState.Delivered; 
        uint  price = products[_seller].price - 100; // 100 as a  fixed brokerage
        _seller.transfer(price); // contract sends the fund to the seller 
    }
    

}

Default access modifiers

pragma solidity ^0.4.15;
contract c1 {
    
    uint internal a; 
    uint public b;
    uint private c;

    function setA(uint  x) private   {
        a=x;
    }
    
    function setB(uint  x) external{
        b=x;
    }
    
    function setC(uint  x)  public {
        c=x;
    }
    
     function setD(uint  x)  internal {
        c=x;
    }

}

contract c2 is c1{ // inheritance using keyword `is` 
   
    function c2() {
      setC(10);
      setD(10);
  //  setA(10);  // Error-`private` function:  cannot be called by derived contracts or external accounts
  //  setB(10);  // Error-`external` function: only by external accounts
      
       a=10; // internal variable   
       b=10; // public variable
   //  c=10; //Error-private variable 
    
    }
}

6. Contract as State machine


pragma solidity ^0.4.15;

contract StateMachine {
    
    enum Stages {  // State flow from applied to Finished
        Applied,
        Initiated,
        Approved,
        Received,
        Finished
        
    }

    // This is the current stage of the contract
    Stages public stage = Stages.Applied;

    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    // Forward state of enum stage by 1
    function nextStage() internal {
        stage = Stages(uint(stage) + 1);
    }

    // This modifier goes to the next stage
    // after the function is done.
    modifier transitionNext() {
        _;
        nextStage();
    }

    function initiate()
        atStage(Stages.Applied) // initialize requires current state to be `Applied`
        transitionNext {        // Forward state

    }

    function approve()
        atStage(Stages.Initiated) // initialize requires current state to be `Initiated`
        transitionNext {          // Forward state    

    }

    function receive()
        atStage(Stages.Approved) // initialize requires current state to be `Approved`
        transitionNext {         // Forward state

    }
    
     function finish()
        atStage(Stages.Received) // initialize requires current state to be `Received`
        transitionNext {         // Forward state

    }
}

7. Withdrawal pattern re-entrancy


Malicious code

  pragma solidity ^0.4.15;
    contract  Bank {

            mapping(address=>uint) public userBalances; // mapping account=>amount

            function Bank() payable {   // constructor 
                
            }

            function deposit() payable {   // deposit ethers to the contract and update balanne
               userBalances[msg.sender] += msg.value; // `msg.value` : Number of ethers sent in uint wei
            }
        
            function withdraw() {   // withdraw total amount deposited
                uint amountToWithdraw = userBalances[msg.sender];  // read total amount deposited
                if (amountToWithdraw>0){   // check if it is greater than 0
                    msg.sender.call.value(amountToWithdraw)();  // send back ethers to the sender `msg.sender`
                }
                userBalances[msg.sender] = 0; // update map to zero
            }
            
            function getContractBalance() constant returns(uint) {
                return this.balance; // returns number of ethers contract is holding
            }

    }

        contract Attacker { 

            Bank  bank; //  Defining Balance contract
            
            function Attacker(address addr)  payable {
                bank=Bank(addr);   // Reference: Bank at address `addr`
            } 
            
            function deposit()  payable {
                bank.deposit.value(msg.value)(); // transfer the `msg.value` number of ethers to `Bank`
            }
            
            function withdraw() {
                bank.withdraw();  // call withdrawBalance of Bank to withdraw deposited ethers
            }

            // fallback function - is called when someone just sent Ether to the contract
            function() payable {  
                bank.withdraw();
        
            }

        }
  

Solution

   pragma solidity ^0.4.15;
   contract  Bank {

         mapping(address=>uint) public userBalances; // mapping account=>amount

         function Bank() payable {   // constructor 
             
         }

         function deposit() payable {   // deposit ethers to the contract and update balanne
            userBalances[msg.sender] += msg.value; // `msg.value` : Number of ethers sent in uint wei
         }
     
         function withdraw() {   // withdraw total amount deposited
             uint amountToWithdraw = userBalances[msg.sender];  // read total amount deposited
             userBalances[msg.sender] = 0; // update map to zero
             if (amountToWithdraw>0){   // check if it is greater than 0
                 msg.sender.call.value(amountToWithdraw)();  // send back ethers to the sender `msg.sender`
             }
         }
         
         function getContractBalance() constant returns(uint) {
             return this.balance; // returns number of ethers contract is holding
         }

 }

     contract Attacker { 

         Bank  bank; //  Defining Balance contract
         
         function Attacker(address addr)  payable {
             bank=Bank(addr);   // Reference: Bank at address `addr`
         } 
         
         function deposit()  payable {
             bank.deposit.value(msg.value)(); // transfer the `msg.value` number of ethers to `Bank`
         }
         
         function withdraw() {
             bank.withdraw();  // call withdrawBalance of Bank to withdraw deposited ethers
         }

         // fallback function - is called when someone just sent Ether to the contract
         function() payable {  
             bank.withdraw();
     
         }

     }

8. Prepare for failure


pragma solidity ^0.4.15;
contract  Bank {
    
        address owner;
    
        bool status;    // contract status-active if true 
       
        mapping(address=>uint) userBalances; // mapping address to uint balance

        modifier onlyActive {
            require(status==true); // check contract status==true
            _;
        }        
        function Bank() payable  {
            owner = msg.sender;
            status = true;
        }
        
        // change status to false
        function disableContract() onlyActive {
            require(msg.sender==owner); // only owner can change
            status=false;
            owner.send(this.balance);  // send contract ethers to owner's account
        }

        function getBalance(address user) onlyActive  constant returns(uint) {  
            return userBalances[user];
        }

        function addToBalance() payable onlyActive {  
            userBalances[msg.sender] += msg.value;
        }
    
     
        function withdrawBalance() onlyActive {  
            uint amountToWithdraw = userBalances[msg.sender];
            msg.sender.call.value(amountToWithdraw)();
            userBalances[msg.sender] = 0;
        }
        
        function get()  constant returns(uint) {
            return this.balance;
        }
        
        
}

9. Digital locker contract


contract DocumentContract {  
 
    //  Document structure
    struct Document {
        bytes32 name;
        bytes32 referenceURL1;
        bytes32 referenceURL2;
        uint256 date;

    }

    struct Tag {
        bytes32[] documentTags;
    }

    //map of documents
    mapping(address => mapping(bytes32 => Document)) documents;
    mapping(address => Tag) tags;

    // Events for document
    event AddDocument(address indexed from, bytes32 indexed docName);
    event UpdateDocument(address indexed from, bytes32 indexed docName);
    event DeleteDocument(address indexed from, bytes32 indexed docName);

    // add document function
    function addDocument(bytes32 name, bytes32 pReferenceURL1, bytes32 pReferenceURL2) {
        documents[msg.sender][name] = Document({
            name: name,
            date: now,
            referenceURL1: pReferenceURL1,
            referenceURL2: pReferenceURL2
        });
        tags[msg.sender].documentTags.push(name);
        AddDocument(msg.sender, name); //Log event
    }

    // update document function
    function updateDocument(bytes32 name, bytes32 pReferenceURL1, bytes32 pReferenceURL2) {
        documents[msg.sender][name] = Document({
            name: name,
            date: now,
            referenceURL1: pReferenceURL1,
            referenceURL2: pReferenceURL2
        });
        UpdateDocument(msg.sender, name); // Log event
    }

    // delete document function
    function deleteDocument(bytes32 name) {
        for (uint i = 0; i < tags[msg.sender].documentTags.length; i++) {
            if (tags[msg.sender].documentTags[i] == name) {
                delete tags[msg.sender].documentTags[i];
            }
        }
        delete documents[msg.sender][name];
        DeleteDocument(msg.sender, name); // Log event
    }

    // get document data
    function getDocument(bytes32 pName) constant returns(bytes32[4]) {
        bytes32[4] memory temp;
        temp[0] = documents[msg.sender][pName].name;
        temp[1] = documents[msg.sender][pName].referenceURL1;
        temp[2] = documents[msg.sender][pName].referenceURL2;
        temp[3] = bytes32(documents[msg.sender][pName].date);
        return temp;
    }

    // get document list
    function getDocumentTags() constant returns(bytes32[]) {
        return tags[msg.sender].documentTags;
    }

}

contract RequestContract { 
    
    struct Request { // Request structure
        uint reqId;
        address requester;
        address user;
        bytes32 status;
        bytes32 documentName;
        uint256 date;
        bytes32 selectedDocument;
        string key;
        string pubKey;
        bytes32 referenceURL1;
        bytes32 referenceURL2;
    }
   
    uint totalReq = 0;
   
    // map of Requests
    mapping(uint => Request) request;
    mapping(address => uint[]) incomingRequest;
    mapping(address => uint[]) outgoingRequest;

    //Events for requests
    event RequestDocument(address indexed to, address indexed from, bytes32 indexed docName);
    event AcceptRequest(uint indexed reqId, address indexed  from, address indexed to);
    event RejectRequest(uint indexed reqid, address indexed from, address indexed to);
    event Shared(address indexed from, address indexed to, bytes32 indexed docName);

    // get incoming request function
    function getIncomingRequests() constant returns(uint[]) {
        return incomingRequest[msg.sender];
    }
    // get Outgoing request function
    function getOutgoingRequests() constant returns(uint[]) {
        return outgoingRequest[msg.sender];
    }

    // share Document function
    function shareDocument(address userId, bytes32 selectedDoc, string key, string pubKey, bytes32 pReferenceURL1, bytes32 pReferenceURL2) {
        totalReq++;
        request[totalReq] = Request({
            reqId: totalReq,
            requester: userId,
            user: msg.sender,
            status: "shared",
            documentName: selectedDoc,
            date: now,
            selectedDocument: selectedDoc,
            key: key,
            pubKey: pubKey,
            referenceURL1: pReferenceURL1,
            referenceURL2: pReferenceURL2
        });
        outgoingRequest[msg.sender].push(totalReq);
        incomingRequest[userId].push(totalReq);
        Shared(msg.sender,userId, selectedDoc); // Log event
    }

    // get all requests
    function getAllRequestDetails(uint reqid) external constant returns(bytes32[8]) {
        bytes32[8] memory temp;
        if (request[reqid].requester == msg.sender || request[reqid].user == msg.sender) {
            temp[0] = bytes32(request[reqid].requester);
            temp[1] = request[reqid].status;
            temp[2] = request[reqid].documentName;
            temp[3] = bytes32(request[reqid].date);
            temp[4] = bytes32(request[reqid].user);
            temp[5] = request[reqid].selectedDocument;
            temp[6] = request[reqid].referenceURL1;
            temp[7] = request[reqid].referenceURL2;
        }
        return temp;
    }

    // get session key
    function getSessionKey(address userId, uint reqId) external constant returns(string) {
        if (request[reqId].requester == msg.sender && (request[reqId].status == "accepted" || request[reqId].status == "shared")) {
            return request[reqId].key;
        }
    }

    // get public key
    function getPublicKey(uint reqId) external constant returns(string) {
        return request[reqId].pubKey;
    }

    // get document data
    function getDocument(address userId, uint reqId) constant returns(bytes32[2]) {
        if (request[reqId].requester == msg.sender && (request[reqId].status == "accepted" || request[reqId].status == "shared")) {
            bytes32[2] memory link;
            link[0] = request[reqId].referenceURL1;
            link[1] = request[reqId].referenceURL2;
            return link;
        }
    }
}

contract AccountContract { 

     // Account structure
    struct Account {
        bytes32 name;
        uint256 totalreq;
        string publicKey;
        string documentKey;
        bytes32[] documentTags;

    }

    // map of accounts
    mapping(address => Account) accounts;

    function checkAccountExists() constant returns(bool) {
        if (accounts[msg.sender].name == "") {
            return false;
        } else {
            return true;
        }
    }

    // new account function
    function newAccount(bytes32 name, string publicKey, string documentKey) {
        if (accounts[msg.sender].name == "") {
            accounts[msg.sender].name = name;
            accounts[msg.sender].totalreq = 0;
            accounts[msg.sender].publicKey = publicKey;
            accounts[msg.sender].documentKey = documentKey;
        } else {
            throw;
        }
    }

    // get key function
    function getKeyHash() constant returns(string) {
         return accounts[msg.sender].publicKey;
    }

    //get specific key function
    function getSpecificKey(address addr) constant returns(string) {
        return accounts[addr].publicKey;
    }

    // get Document key
    function getDocumentKey() constant returns(string) {
        return accounts[msg.sender].documentKey;
    }

    // get name function
    function getName() constant returns(bytes32) {
        return accounts[msg.sender].name;
    }
    
    function getUserName(address id) constant returns(bytes32) {
        return accounts[id].name;
    }
    
    // test function
    function getSender() constant returns(address) {
        return msg.sender;
    }

}

// Digital locker contract
contract DigitalLocker is DocumentContract, AccountContract, RequestContract {
    
        address owner = msg.sender;

        function kill() {
            require(msg.sender == owner);
            selfdestruct(owner);
        }
}

10. Solidity libraries


String Util

Ethereum stackoverflow solidity

Solidity repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment