(Part 23) Ethereum Solidity - Solidity Contract API, Managing Unlimited External Contracts(PT 23)

in #utopian-io5 years ago

Repository

https://github.com/igormuba/EthereumSolidityClasses/tree/master/Class23

What Will I Learn?

  • What is a contract API and how/why it works
  • Making an API to call ERC20 transfer functions on any other ERC20 contract

Requirements

  • Internet connection
  • Code editor
  • Browser

Difficulty

  • Intermediate

Tutorial Contents

So far, we have been working only with contracts we have created ourselves. But in some cases, for example, if you are building a token wallet (contracts can work as wallets) for multiple tokens, or a decentralized exchange for multiple tokens, you will have to work with a contract for a token that was developed and already deployed by someone else. And that is often the case in many business models, even in some ICOs that accept tokens as payment.

Working with other contracts, by default, is not hard, but of course, it all depends on the complexity of the external contract you have to work with. And that can be done by using an internal "API" contract, to expose the signatures of the functions we want to call our main contract.

For this tutorial, we will assume we want to make a contract that has to call the functions from other contracts, and I will show you how can this be really useful on real-world projects.

We will use API contracts for this. API contracts are contracts that have only the "skeleton" of the functions you want to use from a third party. The reason why these contracts exist is just so that the compiler doesn't throw errors, it is as simple as that because all that matters for those contracts are their signatures. All the calls will be made to the real contract and the API contract will just provide the byte code (signature) for our "main" contract to be deployed successfully.

The external contract

I will use, for this example, a very simple contract, that is going to be considered as their "external" contract, let's suppose it was already deployed by someone else. Just like I will demonstrate in a later section of this contract with a real-world example.

The code from this contract does not matter for the didactics of this tutorial, only how we will interact with the code.

The created external contract for this is called externalContract.sol:

pragma solidity ^0.5.0;

contract externalContract{
//stores balances
    mapping(address=>uint) balance;
    
//creates 10 tokens
    function mint(address _caller) public{
        balance[_caller]+=10;
    }
  
//returns balance  
    function getBalance(address _caller) public view returns (uint){
        return balance[_caller];
    }
}

And is supposed to represent the contract we want to call the functions and let our contract manage.

The main contract

This is the code that will call the functions of the external contract (with the help of the API):

pragma solidity ^0.5.0;

//Our main contract
contract simpleContract{
//API contract (to be created)
    APIContract externalContract;

//sets the address our API will send calls to
    function setExternalContract(address _externalContract) public{
        externalContract=APIContract(_externalContract);
    }
    
//calls the mint function from the external contract with help of the API
    function mint() public{
        externalContract.mint(msg.sender);
    }
    
//gets balance from an external contract with help of API
    function getBalance() public view returns (uint){
        externalContract.getBalance(msg.sender);
    }
}

Notice that we haven't deployed the API contract yet, because there are 2 ways how you can create an API, as shown in the next section.

The API contract

This is the contract that is responsible for filling the signature of the functions we want to be able to use in the future. When Solidity compiles the code it has to "fill" all the byte code gaps, and what this contract does is exactly that.

contract APIContract{
//"dummy" function to fill the byte code space!
    function mint(address whatever) public{
        
    }
//dummy function to fill the compiled byte code
    function getBalance(address doesNotMatter) public view returns (uint){
        
    }
}

contract simpleContract{
//ommited code
}

Now, you have two ways of making this. The most common, probably, and most simple, is to make the API contract in the same file as the main contract, as I did:

Captura de Tela 20190124 às 22.15.25.png

The other way how you can do that is by creating another external contract and importing into the code of the main one, like this:
Captura de Tela 20190124 às 22.17.56.png

Both should work identically.

Working with a real external contract

On Etherscan you can find many ERC20 compatible tokens. I am mentioning ERC20 because it is the most widely used token design pattern, but of course, you could use APIs to work with other contract patterns.

Captura de Tela 20190124 às 22.22.58.png

When you open a "contract page" on Etherscan you can see two tabs, one to make calls to read from the contract, and other to write data to the contract.
In there you can see the functions that are accessible for external callers (that is us!), to make sure if the contract you expect to work with is ERC20 compatible.

So, suppose you want to write a contract that manages other contracts tokens, like the ones shown above, you would have to write an API (o more) to implement the signature of the real functions.

You can see the function names shared by all ERC20 compatible tokens in here:
https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol

The contract I have made for this is:

pragma solidity ^0.5.0;
//API contract to fill the byte code
contract APIContract{
    function totalSupply() public view returns (uint256) {}
    function balanceOf(address owner) public view returns (uint256) {}
    function transferFrom(address from, address to, uint256 value) public returns (bool) {}
}


//main contract to manage third-party tokens
contract manageOtherContract{
    APIContract erc20External; //to fill the byte code
    
//calls external transferFrom
    function transfer(address _externalContract, address _receiver, uint _value) public{
        erc20External=APIContract(_external);//points the address to the token contract
        erc20External.transferFrom(msg.sender, _receiver, _value); //calls the function on that contract
    }
}

The above is made of an API contract, to show the main contract what are the signatures of the functions. And the main contract, this one is allowed to call the transfer function from absolutely any ERC20 compatible contract (as long as the msg.sender have approved our contract as a spender!).

Also, on this example, the API is instantiated and point to the real contract in memory only, so, after the function is executed, other users can use the same function on other ERC20 contracts.

The same logic would apply to other functions and even other kinds of tokens (non-ERC20), as long as the API is correctly defined.

I can't demonstrate this on Remix because I am using a test environment, to work with a real contract, obviously, you are going to need real Ethereum. Unless you have the time to copy, deploy and copy the state of the external contract into your virtual environment.

Curriculum

First tutorial

Latest tutorial

Beneficiaries

This post has as beneficiaries
@utopian.pay with 5%
using the SteemPeak beneficiary tool
image.png

Sort:  

Thank you for your contribution.

I think the tutorial was a bit too short, I got lost in following the core logic behind the usefulness of APIs and inter-contract calls.

Perhaps giving more elaborate real life examples, with some sample function calls and transfer operations/screenshots, and most importantly the "WHY" should we indulge into this concept altogether would have helped further.

Looking forward to your future tutorials.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Thank you for your review, @mcfarhat! Keep up the good work!

Congratulations! Your post has been selected as a daily Steemit truffle! It is listed on rank 16 of all contributions awarded today. You can find the TOP DAILY TRUFFLE PICKS HERE.

I upvoted your contribution because to my mind your post is at least 10 SBD worth and should receive 122 votes. It's now up to the lovely Steemit community to make this come true.

I am TrufflePig, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, you can find an explanation here!

Have a nice day and sincerely yours,
trufflepig
TrufflePig

Hi @igormuba!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @igormuba!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.19
TRX 0.14
JST 0.030
BTC 60078.84
ETH 3197.52
USDT 1.00
SBD 2.45