# Contract Interactions

While we are beginning to write more sophisticated smart contracts, the one thing that holds back our contracts is the inability to *interact* with other smart contracts. Almost every popular contract on EVM-compatible chains contain logic which allows it to call the functions of other smart contracts.&#x20;

To understand how contract interactions might look like, consider the following examples:

* **Uniswap**: Assume you place a trade which swaps USDC for WETH on [app.uniswap.org](https://app.uniswap.org/). Your trade is first sent to the Uniswap V3 [SwapRouter.sol ](https://github.com/Uniswap/v3-periphery/blob/main/contracts/SwapRouter.sol)which then calls the relevant USDC-WETH pool contract necessary to conduct the desired swap.
* **MultiSig Wallet**: All multi-signature wallets (multisigs) on Ethereum and similar chains are smart contracts. Therefore, contract-to-contract interactions are an inherent feature of multisigs.

### Primer: Address Type Methods

Before discussing the logistics on contract interactions, we will first discuss the types that allow us to call other contracts in the first place - the address type and *contract* types.

The address type, as previously discussed in [Primitive Values & Types](https://cs4998.cornellblockchain.org/introduction/hello-world/primitive-values-and-types), represents the addresses of accounts. What is unique about the address type is that it comes with built-in methods that allows us to interact with values of the address type.

To motivate our understanding, consider the following variable:

```solidity
address vitalik = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045;
```

As the name might suggest, this is the address of Vitalik Buterin's Ethereum account. To get an idea of the functions that the address type provide, we can, as an example, get the balance of Vitalik's account.

```
vitalik.balance;
```

At the time of writing this, `vitalik.balance` returns `4119625876629850684131`, which is the amount of Wei in his account.

### Contract Types and Calling Other Contracts

The address type provides many functions that we will soon see, but with our current understanding of Solidity, it is useful mainly when dealing with EOAs since there is no *nice* way to call functions of contracts under the address type. Thankfully, Solidity provides us with *contract* types which allow us to treat contracts like their own types. To understand what we mean by contract types, consider the following code:

```solidity
contract A {

    uint num = 5;

    function getNum() public view returns(uint) {
        return num;
    }

}
```

Furthermore, let's assume that address that contract `A` is deployed at is as follows:

```solidity
address contractAccount = 0x2D4d2d096375FCc1503DA59c5B7FB4f69EAdf1e3;
```

Our goal is to be able to call the `getNum` function of the contract located at `contractAccount`. Ideally, we want to be able to call `getNum` directly; using contract types, we first *convert* `contractAccount` to type `A`:

```solidity
A convertedContract = A(contractAccount);
```

Having now defined `convertedContract`, we can now call `getNum` as follows:

```
convertedAccount.getNum();
```

Since contract types are types, we can use them wherever regular types are also used. An example of this can be found below:

```solidity
contract A {

    function getFive() public pure returns(uint){
        return 5;
    }

}

contract B {

    function callGetFive(A contractToCall) public pure {
        contractToCall.getFive();
    }

}
```

### Sending Ether

While we are now able to call the functions of other smart contracts, there is still one question remaining: how can we send ether to other contracts?

It is trivially known that users can send ether to each other. Since contracts are also accounts, we can send ether to and from contracts as well. In this last section, we will cover how to write code that allows our contracts to send ether to other Ethereum accounts and how to specify our functions to be able to receive ether.

#### The `call` Function

Assume we want to send `x` ether to an account (EOA or contract) with address `y`.  Assuming that the contract we are sending from has enough ether, the syntax below demonstrates how we can send ether via smart contracts:

```solidity
y.call{value: x}("");
```

The `call` function is available to all values of type address. Although we will see later in the course that `call` is a powerful function, for our current purposes, we will treat `call` as a function that allows us to send ether to any account.

There are two types of parameters that are used in the `call` function:

* *Special Parameters*: consists of the `value` field and the `gas` field. `value` is the amount of wei we are sending to the account, while `gas` specifies the maximum amount of gas that can be used when calling the account.
* *Data Parameter*: consists of a hexadecimal value to be sent when calling the account

Note that special parameters go inside curly brackets and use colon-notation, while the data parameter goes in rounded brackets and uses equality-notation.

The `call` function, furthermore, returns two values; these values are as follows:

```solidity
(bool success, bytes memory data) = y.call{value: x}("");
```

where `success` indicates where the call function was successful (i.e. whether the transfer of ether was successful) and `data` is the data returned from the `call` function.

{% hint style="info" %}

#### Checking for Success

Although a successful `call` function does not imply that the logic that we intended to occur occurred, it is *always* a good idea to check that the `success` return value of a `call` function is equal to `true`.
{% endhint %}

#### The `Payable` Keyword

Now that we know how to program our smart contracts to send ether to other accounts (EOAs or contracts), its natural to ask whether if we can include ether as part of function calls. To motivate our curiousity, consider the following example:

{% code lineNumbers="true" %}

```solidity
contract Club {

    mapping(address => bool) isMember;

    uint membershipFee = 1;

    function becomeMember() public returns(bool) {
        require(msg.value == 1, "Did not pay exact fee!");
        isMember[msg.sender] = true;
        return true;
    }

}
```

{% endcode %}

The contract above represents a club where anyone can obtain membership if they pay the require 1 wei membership fee. Examining our contract line-by-line, we have the following:

* Line 8: we are checking if the user has sent the required 1 wei with the function call
* Line 9: we are setting the user's membership status to true
* Line 10: we are return `true` (indicating to the caller that the membership was successfully obtrained)

To send ether alongside a contract call, we again can attach special parameters like we did for the `call` function; the syntax for attaching special parameters in the case of the `becomeMember` function is as follows:

```solidity
becomeMember{value: 1}();
```

Tying this all together, the following code example consists of the `Club` contract and a `User` contract which applies for club membership:

```solidity
contract Club {

    mapping(address => bool) isMember;

    uint membershipFee = 1;

    function becomeMember() public returns(bool) {
        require(msg.value == 1, "Did not pay exact fee!");
        isMember[msg.sender] = true;
        return true;
    }

}

contract User {

    function applyForMembership(Club club) public {
        club.becomeMember{value: 1}();
    }

}
```

If you try to compile this code, however, you will arrive at an angry compiler telling you that you cannot send value to a "nonpayable" function. What we are missing is to specify that `becomeMember` can receive ether. To do this, we need to attach the `payable` keyword to the function header of `becomeMember`. The following code includes the `payable` keyword:

```solidity
contract Club {

    mapping(address => bool) isMember;

    uint membershipFee = 1;

    function becomeMember() public payable returns(bool) {
        require(msg.value == 1, "Did not pay exact fee!");
        isMember[msg.sender] = true;
        return true;
    }

}

contract User {

    function applyForMembership(Club club) public {
        club.becomeMember{value: 1}();
    }

}
```

{% hint style="info" %}

#### Note on `payable` and Visibility

Since sending ether inherently changes the state of the blockchain, any function that receives ether *cannot* be marked as `pure` or `view`. Furthermore, any functions related to the sending of ether (i.e. functions that send ether) also cannot be marked as `pure` or `view`.
{% endhint %}

#### Preview: Responding to Ether Received

In the case that we send ether alongside a function call, the logic of the function involved will be triggered. However, what if we send ether to a contract without calling a specific function (i.e. sending ether via the `call` function)? Intuitively, one would guess that nothing happens, just like when we send ether to an EOA. However, as it turns out, contracts can be programmed to respond when they receive ether. Via [*default functions*](https://cs4998.cornellblockchain.org/introduction/hello-world-pt.-2/default-functions), developers can dictate what a contract does when it receives ether.
