I'm trying to understand the correct way to Deploy
and then Import
multiple Smart-Contracts
and a Library
when creating one big project.
As an example, the project will have the following Library
and three Smart-Contracts.
We begin with:
The Library
pragma solidity >=0.4.0 <0.8.0;
library PizzaLib {
struct Pizza {
uint256 pieSize;
string ingredients;
}
function mix(Pizza calldata pizza, uint256 pSize, string theIngredients) external pure returns (Pizza memory) {
Pizza memory newPizza = pizza;
newPizza.pieSize = pSize;
newPizza.ingredients = theIngredients;
return newPizza;
}
}
This library
will be used by all three upcoming smart-contracts (and perhaps more contracts to come) so I'm therefore going to deploy it independently. That way it's sitting in it's own address on the Blockchain and any contract can access it (which I believe is how this should work - but if I'm wrong even about this much, please let me know.)
Next is: Contract # 1
// Note that I'm putting an "import" statement here for the Library I just created,
// but do I actually need this statement? Or will my migration/deployment
// file - below - take care of linking the Library to this Contract
// anyway? (That's question #1)
//
// For now I'll put the import statement in:
import "PizzaLib.sol";
using PizzaLib for PizzaLib.Pizza;
contract MakePizza {
// -Has functions to make various Types of Pizza
// etc.
}
Now we move on to Contract # 2
This contract will also need to use the 'library', so question # 1 applies here as well (do I import
or not?)
But here I have an additional question - question #2 - which is: this contract needs to not only access the 'library', but also contract # 1 (MakePizza
), which was deployed independently, meaning it too resides in its own unique address on the Blockchain.
So, how do I instantiate MakePizza
here, in the following DeliverPizza
contract?
I'm thinking that at this point I need to NOT use import
statements and NOT use the is
syntax, as follows:
import "MakePizza.sol";
contract DeliverPizza is MakePizza {
. . .
}
Instead, I should just create the contract as follows - omitting both the import
and is MakePizza
statements:
contract DeliverPizza {
// This contract only handles the Deliveries of Pizzas. So it:
// 1. Defines a “Customer” Struct (customer’s name, phone number, etc.)
// 2. Defines a “CustomerAddress” Struct (street address, city, zip-code, etc.)
// 3. Has “delivery” type functions
}
Up next is Contract # 3
This guy needs to reference/instantiate everything we've done up until now: the PizzaLib
library and the MakePizza
and DeliverPizza
contracts:
Contract HandleTheMoney {
// Defines all things having to do with funds:
// 1. Acceptable Payment methods
// 2. Defines various Fees
// 3. Declares the Permissions re who’s allowed to withdraw funds from the contract, etc.
}
Question here again is: how do I instantiate / reference those other contracts in this contract?
The last contract is Contract # 4
Same thing. It needs to reference everything we spoke of up until now.
Usually I would use the is
syntax, as follows....
contract JoesPizzaShop is MakePizza, DeliverPizza, HandleTheMoney {
// The “master” contract, bringing everything together
}
...but I don't think that's the way to go what with all the contracts being deployed independently, so it'd just be:
contract JoesPizzaShop {
// Need to instantiate all the other contracts here...
}
FINALLY, we have the migration
file - which I'm pretty sure I've got right:
module.exports = async function(deployer, network, accounts) {
await deployer.deploy(PizzaLib, { overwrite: false });
await deployer.link(PizzaLib, [MakePizza, DeliverPizza, HandleTheMoney, JoesPizzaShop]);
await deployer.deploy(MakePizza);
await deployer.deploy(DeliverPizza);
await deployer.deploy(HandleTheMoney);
await deployer.deploy(JoesPizzaShop);
}
Here's what I'm doing there:
- Deploying the
PizzaLib
first. Then, Linking
it to all mycontracts
- which are listed in anarray
. And finally,- Deploying each and every one of those
contracts
, one at a time.
So to recap my questions:
- Do I use
import
or not? - Do I need to put the
using PizzaLib for PizzaLib.Pizza;
in everycontract
? - Do I need the
is
statement in all mycontract
declaration statements or not? - How do I reference / instantiate the different
contracts
in each-other so I can call methods from one in another?
using NN for xx
is only allowed inside a contract. Also it is just a syntax sugar for writingobj.func(param)
instead oflibrary.func(obj, param)
. I suggest writing examples and asking here if you have found a problem that can't solve.constructor(address myContractAddr) { _myContractInstance = MyContractInstance(myContractAddr) }