Anyone can interact with them, depending on the business-layer permissions we program into the contracts. "Anyone" includes other "people" – accounts which are submitting transactions to the blockchain – but more importantly also includes other contracts, themselves.
As you design your smart contracts, it's important to keep in mind the interface that you're defining. Since smart contracts have the unique constraint that they can't be edited after deployment (there are ways to work around this through the concept of "proxy contracts"), as more and more contracts build upon each other, a hard layer of logic will ossify at the base. Let's make sure we get it right.
In this tutorial we'll describe how to design your smart contracts so that others can easily interact with them, and how to interact with other smart contracts from your own.
The most well known "interface" in Ethereum is by far the ERC-20 token. ERC-20 is simply a set of "function signatures" (or "type signatures") which define the functions that a contract must implement in order to "be" an ERC-20 token on Ethereum.
Let's see what that looks like, in Solidity
Used in an actual project: https://github.com/decentorganization/coinflation/blob/develop/contracts/token/ERC20/IERC20.sol
This <code>IERC20 interface<code> definition, when included in a Solidity project, allows any contract in that project to implement <code>IERC20<code> and immediately be compatible with the hundreds of other contracts and tools in the wild that support ERC20 tokens.
Let's take a look at what a simple implementation looks like:
Used in an actual project: https://github.com/decentorganization/coinflation/blob/develop/contracts/token/ERC20/ERC20.sol
Without getting into the details of this implementation, we can see that this <code>ERC20 contract<code> (which is <code>IERC20<code>) provides implementations for all of the functions defined in the <code>IERC20 interface<code> above.
Great! This is pretty simple so far, but it provides an excellent base on which to build.
Let's say we compile this Solidity project, deploy it to the Ropsten testnet, and it receives an address at <code>0xee70B92dCC35fcEfB2d51fC1ad08Ae2611439CBa<code>.
There are a plethora of on-and-off-chain ERC20 wallets out there which can now natively interact with our token.
Get it? Since the <code>IERC20<code> interface is well known, external tools and contracts can just call <code>balanceOf()<code> or <code>approve()<code> or <code>totalBalance()<code> or <code>transfer()<code> on any contract that implements the interface.
So how do we write another smart contract that interacts with this ERC20 token which we've deployed at <code>0xee70B92dCC35fcEfB2d51fC1ad08Ae2611439CBa<code>?
Easy! Declare the existing contract's interface into your new contract, instantiate an instance of it given the deployed address, and start calling functions.
Let's take a deeper look at this terribly simple terrible contract.
First, we define the same ERC20 interface from above. This is just so that we can call these functions from within our new contract here. Need to have those function signatures defined somewhere so the Solidity compiler knows what's going on.
Next, we create a contract called <code>InsecurePublicWallet<code>. Lol, this thing. Don't deploy or try to use this please.
Within this contract, we create a variable called <code>myTokenContract<code>, which is a reference to the deployed ERC20 contract from above. In the constructor we have the token's address hardcoded, and then "instantiate" a reference to the existing token contract "using" the <code>IERC20<code> interface.
Now the <code>myTokenContract<code> object has all of the <code>IERC20<code> functions available to it! We'll implement two contract-level functions in <code>InsecurePublicWallet<code>, each one of those functions will call a different function on the deployed <code>ERC20<code> token, through the <code>myTokenContract<code> object.
<code>getInsecurePublicWalletBalance()<code> is a function that checks the balance of our deployed token, for <code>this<code> <code>InsecurePublicWallet<code>. Our new contract here can own tokens from the original token contract, and this function simply checks it's own balance and returns the result.
<code>stealTheTokens()<code> is a function that allows anyone to steal any tokens owned by <code>InsecurePublicWallet<code>. It does that by first checking the token balance of <code>InsecurePublicWallet<code> (through <code>getInsecurePublicWalletBalance()<code>), then calling the <code>transfer<code> function on <code>myTokenContract<code> in order to transfer all of the <code>InsecurePublicWallet<code>'s tokens to the person executing this function call (<code>msg.sender<code>).
As an example, this contract is pretty simple and displays the ways in which you can build contracts which use and build upon other contracts. But practically speaking, it's really silly, for reasons which should be obvious at this point. Any tokens (from the <code>0xee70B92dCC35fcEfB2d51fC1ad08Ae2611439CBa<code> contract) which are transferred to <code>InsecurePublicWallet<code> can be stolen by anyone.
You should now have a better understanding of how to: