External Contracts & Interfaces in Ethereum


#1

Welcome to the thread about External Contracts & Interfaces in Ethereum. Here you can discuss everything about this chapter.


External Contracts & Interfaces assignment
#2

Hi Filip,

The way the BankContract.deposit() is called within transferDog() is a little confusing for me.

BankContract.deposit.value(msg.value)();

can you break down each step involved above? given the definition of “deposit()” iin BankContract does not take in any argument in the first place.

Thanks!


#3

Yes, absolutely. I understand that it can look complex. I think it’s critical to understand that the parenthesis, when placed after a function name, executes the function. Just putting the function name without the parenthesis doesn’t execute the function.

A normal function call to the deposit function in the BankContract would look like this

BankContract.deposit()

The deposit function doesn’t take any arguments. So we don’t input any value in between the parenthesis. However, the deposit function is a payable function, which means we can and should send it ether. We do that by calling the value function on the deposit function. After we have added the value we call the function by putting the parenthesis in the end. The value that we want to send is the value that was sent to transferDog, which is stored in msg.value.

BankContract.deposit.value(msg.value)()

Let me know if you understand my explanation or if something is still unclear.


#4

Filip, thanks a lot for the clarification.

I see similarity between your code and the code in this link https://medium.com/daox/three-methods-to-transfer-funds-in-ethereum-by-means-of-solidity-5719944ed6e9 . Over there, an unnamed function “function () payable { balance += msg.value;}” , is deployed this way: " _receiver.call.value(msg.value).gas(20317)();"

So, is it fair to say that the way to read “receiver.call.value(msg.value).gas(20317)()” is “receiver.call{.value(msg.value).gas(20317)}()”, where inside { } are two bindings of the unnamed “call” function (binding on two internal properties for a payable function: value binding, and gas binding)?

A separate question: forget about BankContract (therefore no deposit function which can accrue payments that invoked transferDog() over time), can “transferDog() payable costs(100)” function on its own have a way to keep track of payment history or the accrued total?


#5

To your first question, yes, that could be a fair way to look at it.

If you didn’t have any call to the bankContract, you could just keep the money in the Kennel contract. As long as the function is payable, that money will accrue in that contract. If you have multiple payable functions in one contract and you want to keep track of which function collected most money. You could simply have a couple of state variables that keep count. But otherwise the contract will hold all of the balance.


#6

Thanks Filip. Will test it out too.


#7

I need to re-watch this lecture couple of times too
I know it should be logical and relatively easy,
IF you GET it!
working with more files and contacts are realllllllly mind-bending!

greetZz.. Fabrice


#8

this is awesome. now we can execute functions in contract (service) and the money goes to an external contract. you just need function headers of that contract to make an interface

GreetZz.


#9

Hi Filip,

Great video explanation. I enjoyed learning about it.
In this example, the Kennel contract calls a public function that exists in the Ethereum blockchain as an address.
Question 1: Is it possible to call a function from a GitHub address or from somewhere else outside the blockchain? If yes…how do you call an external function if it doesn’t have an address?
Question 2: Do contracts need to pay gas to use public functions that are already deployed in Ethereum?

Super thanks!

Cheers,

Juliana

PS: thanks for the tip of the += in the code :wink:


#10

Thank you! Those are good questions.

  1. You can’t call a function with only a github address. The contract needs to be deployed on the blockchain and you need the contracts ethereum address. You also need to now what the function looks like, what parameters it takes and what it returns. This can be found in the contracts ABI file, which often times the auther publish if he/she wants people to interact with the contract.

  2. Gas is always payed by the original sender. So if an account calls a contract function which in turn calls another external contract. The original account will pay the gas costs of both calls.

I hope I answered your questions. Good luck!


#11

Hi Filip.

So, I followed your exact steps and I managed to transfer the dog to another address successfully, however the wei is not deposited into the bank, as upon clicking ‘getBankBalance’ it’s showing ‘0’ … i’m not sure where the wei is being sent to :slight_smile: please help


#12

Can you share your code?


#13

Hey. Yes, sure I can:

so this is the kennel:

pragma solidity ^0.4.25;

import ‘./DogContract.sol’;

contract BankInterface {
function getBalance () view returns (uint);
function deposit () payable;
}

contract Kennel is DogContract {

modifier costs(uint value){
    require(msg.value >= value);
        _;
}

address externalAddress = 0xbbf289d846208c16edc8474705c748aff07732db;
BankInterface BankContract = BankInterface(externalAddress);

function initBank(address _bankAddress) onlyOwner {
BankContract = BankInterface(_bankAddress);
}

function transferDog(address _newOwner) payable costs(100) {
    address owner = msg.sender;
    require (owner != _newOwner);
    uint dogId = ownerToDog[owner];
    delete(ownerToDog[owner]);
    ownerToDog[_newOwner] = dogId;
    assert(ownerToDog[owner] == 0);
    BankContract.deposit.value(msg.value)();
}

function getBankBalance() view returns (uint){
    return BankContract.getBalance();
}

function addKennelDog(string _name, uint _age) {
    addDog(_name, _age);
}

}


#14

bank contract:

pragma solidity ^0.4.25;

contract BankContract {
uint balance;

function deposit () payable {
    balance += msg.value;
}

function getBalance () view returns (uint){
    
}

}


#15

dog contract:

pragma solidity ^0.4.25;

import “./Ownable.sol”;

contract DogContract is Ownable {

struct Dog {
    string name;
    uint age;
}

Dog[] dogs;
mapping(address => uint) ownerToDog;

event addedDog(address owner, string name, uint dogId);


function addDog(string _name, uint _age) {
    address owner = msg.sender;
    uint id = dogs.push(Dog(_name, _age));
    ownerToDog[owner] = id;
    addedDog(owner, _name, id);
}

function getDog() returns (string) {
    address owner = msg.sender;
    uint id = ownerToDog[owner];
    return dogs[id-1].name;
}

}


#16

You getBalance function doesn’t contain any code. That’s why it doesn’t return anything. It needs to return the balance.


#17

Hi Filip,

I don’t understand why you have the function call for the deposit function as:

BankContract.deposit.value(msg.value)();

I understand that you need the final () to make the function call but I would expect the function call to be:

BankContract.deposit();

because the deposit function doesn’t have a parameter. In the deposit function the state variable ‘balance’ is incremented by msg.value.
I don’t understand where ‘.value(msg.value)’ comes from or why we are allowed to insert it into the function call or why we need it. Shouldn’t BankContract.deposit() work?

Thank you


#18

Well, this is a question about the design of the solidity language. The problem is that if we only had BankContract.deposit(), which would make sense, then where would we put the amount that we want to send? It wouldn’t make sense to send it as an argument, since the function doesn’t take any argument.

So we need another way of calling a function which is payable, where we can specify the amount that we want to send. Solidity chose to do that with the value() function. So we attach the value function to our normal function and as a parameter to that we can send the amount that we want to send.

It’s only a question of design, and solidity thought this was the best and easiest way to do it.


#19

A couple of questions:

  1. In this case we have a function in the Kennel contract transferring funds to another contract (the BankContract). Is this why we need to explicitly provide the amount being sent using the value function?

  2. Could the Kennel contract inherit from an external contract? In the case of an inherited contract would we no longer need to add the value function because the BankContract functions would then be inherited by the Kennel contract? For example if we had a payable deposit function in the Dog contract would we be able to call deposit() from the Kennel contract without adding a value function?

  3. Also, the body of the deposit function is
    {
    balance += msg.value;
    }

and we input 100 wei into the value field in Kennel Contract so msg.value is 100. why can’t the deposit function perform the operation balance += msg.value without adding the value function. It looks like the deposit function should have all the information it needs.

  1. Would it make more sense to write the deposit function in the bank contract with an input argument?

function deposit(uint _value) {
balance += _value;
}

then in function transferDog we would have the call:

BankContract.deposit(msg.value)();

would that work?

  1. Do we only use the payable modifier when we want a contract to receive Ether? In other words when a user call s a contract function that transfers Ether to another external account instead of to a contract itself then I assume the function does not have the payable modifier. Is that correct?

Thank you for your help. I know I am asking a lot of questions


#20

One more question:

  1. When an Ethereum address accesses the Kennel contract and inputs 100 wei in the value field when it calls the transferDog function is the msg.value variable a local variable whose scope applies just to the call between the Ethereum address and the Kennel contract? In other words, when the transferDog function of the Kennel contract then calls the deposit function of the external BankContract is the variable msg.value in the BankContract (i.e. in the statement: balance += msg.value;) separate from, and not within the scope of, the msg.value variable in the Kennel contract (that has 100 wei)?
    And is it for this reason the 100 wei must be passed by the Kennel contract in an argument to the deposit function?