- 10 Apr 2024
- 2 Minutes to read
- DarkLight
- PDF
Use External Blueprints
- Updated on 10 Apr 2024
- 2 Minutes to read
- DarkLight
- PDF
Blueprints and components do not exist on the radix network in isolation. They are addressable and can interact with each other if allowed. In this section we show you how to allow and enable blueprint to blueprint interactions other than transactions.
Contents
- External Blueprints
- Multiple instantiation functions
- Using the Candy Store with an External Gumball Machine
External Blueprints
As the Radix ecosystem continues to mature there will be more and more blueprints available to use. These blueprints are created by many different teams and individuals and some are intended for external use, with the possibility of royalties given to the blueprint owner. You may work on some of these yourself.
Using external blueprints is a little different to using your own. We need to import the blueprint into our own using the extern_blueprint!
macro. This macro describes the external blueprint with its address, name, function and method signatures.
mod candy_store {
extern_blueprint! {
// import the GumballMachine package from the ledger using its package address
"<YOUR_GUMBALL_MACHINE_PACKAGE_ADDRESS>",
GumballMachine {
// Blueprint Functions
fn instantiate_global(price: Decimal) -> ( Global<GumballMachine>, Bucket);
fn instantiate_owned(price: Decimal, component_address: ComponentAddress) -> Owned<GumballMachine>;
// Component Methods
fn get_status(&self) -> Status;
fn buy_gumball(&mut self, payment: Bucket) -> (Bucket, Bucket);
fn set_price(&mut self, price: Decimal);
fn withdraw_earnings(&mut self) -> Bucket;
fn refill_gumball_machine(&mut self);
}
}
When publishing the package, the package address is checked for an existing blueprint. Publishing will fail if none exists.
The description in the macro gives us access to the external blueprint's functions in ours. In our Candy Store blueprint we use this to instantiate a component from a separately and previously published Gumball Machine package.
let gumball_machine =
Blueprint::<GumballMachine>::instantiate_owned(gumball_price, component_address);
Note the Blueprint::<GumballMachine>
type. This is generated by the extern_blueprint!
macro. The syntax is a little odd if you have not worked with Rust before, but is hopefully clear.
The new Gumball Machine component is now owned by our Candy Store giving it access to the Gumball Machine's methods.
Multiple instantiation functions
So as to allow for both an owned and global gumball machine, we have two instantiation functions. instantiate_owned
:
pub fn instantiate_owned(
price: Decimal,
component_address: ComponentAddress,
) -> Owned<GumballMachine> {
// --snip--
.instantiate()
}
And instantiate_global
:
pub fn instantiate_global(price: Decimal) -> (Global<GumballMachine>, Bucket) {
// --snip--
let gumball_machine = Self::instantiate_owned(price, component_address)
// assign the component owner role to the possessor of the owner_badge resource
.prepare_to_globalize(OwnerRole::Fixed(rule!(require(
owner_badge.resource_address()
))))
// apply the address reservation
.with_address(address_reservation)
.globalize();
(gumball_machine, owner_badge)
}
This is a good demonstration of component instantiation producing owned components initially, which can subsequently be globalized. instantiate_global
calls instantiate_owned
then globalizes the returned component.
We use it here, so the same version of the blueprint can also be used in this and the next section.
Having multiple instantiation functions can serve several other purposes as well. Allowing for a standard default component to be created, while also allowing for a more complex or customized component versions, potentially using input arguments to decide on metadata or more complex access rules.