Third Party Dependencies
Third party dependencies are external modules that a controlled module interacts with. Typically, these external modules exist under different accounts.
Multi-DEX router example
A multi-DEX router actively utilizes third party dependencies. Instead of submitting multiple transactions to interact with different DEXs and their individual entry functions within a swap route, a module (or script) can consolidate all independent DEX invocations into a single, atomic transaction. The multi-DEX router references and calls to functions present in each of the third party DEX modules to achieve this.
Sources
Third party dependencies will have varying amounts of reliability and available information based on where they’re sourced from. Specifically, documentation for a few instances will be non-existant, as well as logic potentially being refactored.
Source code that is verified against the on-chain deployed module, like the Git Repository and Local Source Code, should always be preferred. If neither of those are available, there are other options to depend on usable code, like decompiled code, bytecode, and ABI-crafted code.
Git Repository
The default Move.toml
includes AptosFramework
as a git repository dependency:
[dependencies.AptosFramework]
git = "<https://github.com/aptos-labs/aptos-core.git>"
rev = "mainnet"
subdir = "aptos-move/framework/aptos-framework"
When Aptos CLI commands are ran, updates to the dependency are automatically retrieved and compiled against.
Local Source Code
Third party source code can be included in the sources
directory. Essentially treating it the same as custom code.
- {ControlledCode}.move
- {ThirdPartyCode}.move
- Move.toml
Any upgrades to the Third Party dependency will need to be retrieved, manually.
Decompiled code
Move code can be reconstructed by using the Revela Compiler against a package’s bytecode:
aptos move decompile --package-path ./bytecode_modules
Corresponding {ModuleName}.mv.move
files will be generated in bytecode_modules
.
- {ModuleName}.mv
- {ModuleName}.mv.move
- Move.toml
Reference it as a local source file after changing the file type to {ModuleName}.move
and placing it in the workspace’s sources
directory.
- {ModuleName}.move
- Move.toml
Decompiled code will keep behaviors of on-chain execution, but will be refactored.
Bytecode
The Aptos CLI allows for downloading a package’s bytecode.
aptos move download --account {account_addr} --bytecode --package {package_name}
Each bytecode dependency requires their own package, with a structure of:
Move.toml
file, with the package address pre-defined.build/{ModuleName}/bytecode_modules
directory with the bytecode inside.- Empty sources directory.
The controlled module can then reference the dependency, upon it’s inclusion in the controlled package’s Move.toml
.
Aptos Token example
A controlled invoking_code.move
module interacts with the external aptos_token
module:
module invoker::invoking_code {
use aptos_token_objects_addr::aptos_token;
public entry fun wrapper_add_property(): u64 {
aptos_token::add_property(...);
}
}
The below command retrieves the necessary AptosTokenObjects package bytecode from the Mainnet.
aptos move download --account 0x4 \
--bytecode --package AptosTokenObjects \
--output-dir ./aptos_token_bytecode_output/
- aptos_token.mv
- Move.toml
The created dependency package structure and contents for aptos_token
is:
- aptos_token.mv
- Move.toml
[package]
name = "aptos_token"
version = "0.0.0"
[addresses]
aptos_token_module_addr = "0x4"
The dependency list from the controlled invoking_code.move
module will include a local reference to the bytecode package, allowing for compilation.
[package]
name = "invoking_code"
[addresses]
invoker = "_"
[dependencies]
aptos_token = { local = "../aptos_token_objects_addr" }
ABI
Move interface code can be manually crafted by reading a package’s ABI. Notably, while the function header is required to be exact, the logic within is not.
All available public and entry methods are defined with their name, arguments, return values, and more, within the ABI. Structs and resources will also be included.
Afterwards, the interface code is treated equivalent to local source code.
Aptos Token example
Below is a portion of the AptosTokenObjects
ABI, gathered from the Aptos Explorer:
{
"address": "0x4",
"name": "aptos_token",
"friends": [],
"exposed_functions": [
{
"name": "add_property",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [
{
"constraints": [
"key"
]
}
],
"params": [
"&signer",
"0x1::object::Object<T0>",
"0x1::string::String",
"0x1::string::String",
"vector<u8>"
],
"return": []
},
...
]
}
An interface Move file can be handwritten and treated as a source file. Looking similar to:
module 0x4::aptos_token {
// ...
public entry fun add_property<T: key>(
creator: &signer,
token: Object<T>,
key: String,
type: String,
value: vector<u8>,
) acquires AptosCollection, AptosToken {
abort 0
}
}
- {ControlledCode}.move
- aptos_token.move
- Move.toml