In the last section we looked at a candy store package made up of several blueprints. This section will show how to do the same thing in a different way. We will still have a candy store component containing a gumball machine component. The difference this time, will be the gumball machine will be owned by the candy store.
There are two broad ways to modularise your components, each with distinct advantages.
- Global components: Like all the components from the previous sections, these are created at the global level and are accessible to all other components on the ledger.
- Owned components: Internal to other components, they are only accessible to their parent components.
Global and Owned Components
All components are initially local. In this state they are not addressable by or accessible to others. To change this we globalize them. This is done after instantiation by first calling prepare_to_globalize (setting the component access rules and reserving an address) on the new component, then calling the globalize method like so:
.instantiate()
.prepare_to_globalize(OwnerRole::None)
.globalize();
Without these steps, to use a component it must be internal to another. This is done by adding the component in a parent component's struct, with the wrapping Owned type, e.g.
struct CandyStore {
gumball_machine: Owned<GumballMachine>,
}
The owned component's methods, can then be called by it's parent, but no other components. e.g.
self.gumball_machine.buy_gumball(payment);
Let's compare how this looks in our example packages.
| Package with Owned GumballMachine | Package with Global GumballMachine |
|
|
|
Owned vs Global GumballMachine
The global GumballMachine is the same as from previous examples. The owned version is where we see several changes.
Restricted methods
| Owned | Global |
|
|
Instantiation function start
| Owned | Global |
|
|
Owner badge
| Owned | Global |
|
|
Gumball mint roles
| Owned | Global |
|
|
Instantiation function end
| Owned | Global |
|
|
The owned version is simpler, as we're able to remove much of the access and control code. The possible downside is the owned component no longer has a global address so cannot be accessed by components other than it's owner, such as those in other packages. For some purposes this is ideal though.
Owner vs Non-owner CandyStore
The CandyStore is globalized in both (this and the previous sections) version of our package. The code for its blueprint is simpler here, where it owns the GumballMachine. In this version there's no need for a GumballMachine owner badge stored in this component. The only methods accessible on either blueprint are those of the CandyStore, so we restricted access to necessary methods on the CandyStore and we don't need add restrictions to the GumballMachine. No method restrictions in the GumballMachine means no needs to hold the GumballMachine owner badge to pass proof of ownership to the GumballMachine to call it's restricted methods. This is done with the authorize_with_amount method for the previous global GumballMachine, which we don't have to use at all in this version.
Component state
| Owner (owned GumballMachine) | Non-owner (global GumballMachine) |
|
|
Address reservation
| Owner (owned GumballMachine) | Non-owner (global GumballMachine) |
|
|
Gumball machine instantiation
| Owner (owned GumballMachine) | Non-owner (global GumballMachine) |
|
|
Globalizing
| Owner (owned GumballMachine) | Non-owner (global GumballMachine) |
|
|
Calling restricted GumballMachine methods
| Owner (owned GumballMachine) | Non-owner (global GumballMachine) |
|
|
Owned components make for simpler code that is easier to read and maintain. But you will have to decide if removing global accessibility of some component works for your applications.

