1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//! suibase
//!
//! API to suibase mostly intended for development of Sui tool/test automation and production backends.
//!
//! This API is:
//! * multi-thread safe.
//! * UniFFI bindings compatible (Sync+Send)
//!
//! See <https://suibase.io> for more info.
//!
//! What is Suibase?
//!
//! Suibase makes it easy for Sui devs to simultaneously interact with multiple Sui
//! networks (localnet/devnet/testnet/mainnet) without having to "switch env".
//!
//! Your dev setup gains stability by having a client binary match every network version.
//!
//! How to use?
//!
//! Suibase is not available on crates.io. It is instead installed (github cloned) to your local machine and
//! your app references it. That way your app and the suibase installation are certainly matching versions.
//!
//! After installing suibase ([more info](https://suibase.io/how-to/install)), add to your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! suibase = { path = "../../suibase/rust/helper" }
//! ```
//!
//! You may have to adjust the number "../" depending on where your Cargo.toml is located relative to ~/suibase.
mod error;
pub use crate::error::Error;
mod suibase_helper_impl;
mod suibase_root;
mod suibase_workdir;
use crate::suibase_helper_impl::SuibaseHelperImpl;
use std::sync::{Arc, Mutex};
use sui_types::base_types::{ObjectID, SuiAddress};
#[cfg(feature = "build-with-uniffi")]
uniffi::include_scaffolding!("suibase");
/// A lightweight API to suibase. Multiple instance can be created within the same app.
///
/// You interact with Suibase in 3 steps:
///
/// 1. Check if suibase is_installed()
/// 2. Call select_workdir() to pick among "localnet", "devnet", "testnet", "mainnet" or the one currently set "active" by the user.
/// 3. You can now call any other API functions (in any order). Most calls will relate to the selected workdir.
///
/// You can call again select_workdir() to switch to another workdir.
pub struct Helper(Arc<Mutex<SuibaseHelperImpl>>);
/// This is the documentation for the impl Default
impl Default for Helper {
fn default() -> Self {
Self::new()
}
}
impl Helper {
/// Constructs a new `Helper`.
///
/// # Example
/// ```
/// use suibase::Helper;
/// let sbh = Helper::new();
/// if sbh.is_installed()? {
/// sbh.select_workdir("localnet")?;
/// println!("active address is {}", sbh.client_address("active"));
/// }
/// ```
pub fn new() -> Self {
Helper(Arc::new(Mutex::new(SuibaseHelperImpl::new())))
}
/// Check first if suibase is installed, otherwise
/// most of the other calls will fail in some ways.
pub fn is_installed(&self) -> Result<bool, Error> {
self.0.lock().unwrap().is_installed()
}
/// Select an existing workdir by name.
///
/// Possible values are:
/// "active", "cargobin", "localnet", "devnet", "testnet", "mainnet" and
/// other custom names might be supported in future.
///
/// Note: "active" is special. It will resolve the active workdir at the moment of the
/// call. Example: if "localnet" is the active, then this call is equivalent to
/// to be done for "localnet". The selection does not change even if the user
/// externally change the active after this call.
///
pub fn select_workdir(&self, workdir_name: &str) -> Result<(), Error> {
self.0.lock().unwrap().select_workdir(workdir_name)
}
/// Get the name of the selected workdir.
pub fn workdir(&self) -> Result<String, Error> {
self.0.lock().unwrap().workdir()
}
/// Get the pathname of the file keystore (when available).
///
/// Context: Selected Workdir by this API.
pub fn keystore_pathname(&self) -> Result<String, Error> {
self.0.lock().unwrap().keystore_pathname()
}
/// Get the ObjectID of the last successfully published "package_name".
///
/// package_name is the "name" field specified in the "Move.toml".
///
/// Related path: ~/suibase/workdirs/<workdir_name>/published-data/<package_name>/
pub fn package_object_id(&self, package_name: &str) -> Result<ObjectID, Error> {
self.0.lock().unwrap().package_object_id(package_name)
}
/// Alternative for string-based API.
pub fn package_id(&self, package_name: &str) -> Result<String, Error> {
let id = self.package_object_id(package_name)?;
Ok(id.to_string())
}
/// Get the ObjectID of the objects that were created when the package was published.
///
/// object_type format is the Sui Move "package::module::type".
///
/// Example:
///
/// module acme::Tools {
/// struct Anvil has key, drop { ... }
/// ...
/// fun init(ctx: &mut TxContext) {
/// Anvil::new(ctx);
/// ...
/// }
/// }
///
/// The object_type is "acme::Tools::Anvil"
///
/// Related path: ~/suibase/workdirs/<workdir_name>/published-data/<package_name>/
pub fn published_new_object_ids(&self, object_type: &str) -> Result<Vec<ObjectID>, Error> {
self.0.lock().unwrap().published_new_object_ids(object_type)
}
/// Alternative to published_new_object_ids() for string-based API.
pub fn published_new_objects(&self, object_type: &str) -> Result<Vec<String>, Error> {
let res = self.published_new_object_ids(object_type)?;
Ok(res.iter().map(|c| c.to_string()).collect())
}
/// Get an address by name.
///
/// Suibase localnet/devnet/testnet/mainnet workdir are created with a set of pre-defined client addresses.
/// These addresses are useful for testing. In particular, with a localnet, they are prefunded.
///
/// Values for the `address_name` argument can be: `active | sb-[1-5]-[ed25519|scp256k1|scp256r1]`
///
/// Examples: "active", "sb-1-ed25519", "sb-3-scp256r1", "sb-5-scp256k1" ...
///
/// Choosing "active" is same as doing "sui client active-address" for the selected workdir.
pub fn client_sui_address(&self, address_name: &str) -> Result<SuiAddress, Error> {
self.0.lock().unwrap().client_sui_address(address_name)
}
/// Alternative to client_sui_address() for string-based API.
pub fn client_address(&self, address_name: &str) -> Result<String, Error> {
let addr = self.client_sui_address(address_name)?;
Ok(addr.to_string())
}
/// Get a RPC URL for the selected workdir.
pub fn rpc_url(&self) -> Result<String, Error> {
self.0.lock().unwrap().rpc_url()
}
/// Get a Websocket URL for the selected workdir.
pub fn ws_url(&self) -> Result<String, Error> {
self.0.lock().unwrap().ws_url()
}
}