Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

e2e non-native token payable to governed gas pool #989

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4e7e085
test: initial structure for governed_gas_pool test
0xmovses Jan 8, 2025
ff2f159
update: add test_token module
0xmovses Jan 8, 2025
4a05854
feat: create test modules and Move.toml
0xmovses Jan 8, 2025
6a0a633
fix: Move.toml
0xmovses Jan 8, 2025
dc9a8ae
update: aptos-framework version
0xmovses Jan 8, 2025
92ccee8
fix: module
0xmovses Jan 8, 2025
77fe8d6
fix: acquire capability
0xmovses Jan 8, 2025
100bb82
fix: gitignore move build
0xmovses Jan 8, 2025
226438b
fix: Remove build files from remote repository
0xmovses Jan 8, 2025
25f89ed
feat: define process-compose
0xmovses Jan 8, 2025
d9ba267
update: aptos with ggp genesis
0xmovses Jan 8, 2025
89adf25
update: aptos
0xmovses Jan 8, 2025
ebbdc49
update: aptos ver
0xmovses Jan 9, 2025
256273a
update: proces-compose and fund
0xmovses Jan 9, 2025
e56828f
fix: fund steps and move mod build
0xmovses Jan 9, 2025
ca1fc18
fix: move dir build and skip deps
0xmovses Jan 13, 2025
e35cc54
update .gitignore
0xmovses Jan 13, 2025
85d6135
update: add init for config.yaml
0xmovses Jan 13, 2025
fe30085
remove: build files
0xmovses Jan 13, 2025
d3f5e43
fix: deploy
0xmovses Jan 13, 2025
6b9857a
init
0xmovses Jan 14, 2025
ef10eef
update: improve build flow and error handling
0xmovses Jan 15, 2025
8ca412f
fix: init cmd
0xmovses Jan 15, 2025
8b51ac2
update: mod build
0xmovses Jan 15, 2025
f843cf8
fix: merge conflict
0xmovses Jan 15, 2025
c8350d6
fix: merge conflict
0xmovses Jan 15, 2025
2111c86
fix: toml aptos rev
0xmovses Jan 15, 2025
ef0e30a
fix: public address args and flags
0xmovses Jan 16, 2025
47431d3
feat: add script and create write utils
0xmovses Jan 16, 2025
7327741
update: payload build and test-token init
0xmovses Jan 16, 2025
6b452d2
update: rev hash on git deps Move.toml
0xmovses Jan 17, 2025
d2f0b6e
fix: script args
0xmovses Jan 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ protocol-units/bridge/contracts/out/*
protocol-units/bridge/contracts/cache/*
protocol-units/bridge/move-modules/build/*
protocol-units/bridge/move-modules/.aptos/*
networks/movement/movement-client/src/move-modules/build/*
.idea/
target/
ledger_db/
Expand All @@ -26,4 +27,4 @@ venv
*.pem
*.jot.*
*.jot
*.env
*.env
269 changes: 135 additions & 134 deletions Cargo.lock

Large diffs are not rendered by default.

64 changes: 32 additions & 32 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,40 +141,40 @@ borsh = { version = "0.10" } # todo: internalize jmt and bump

### We use a forked version so that we can override dependency versions. This is required
### to be avoid dependency conflicts with other Sovereign Labs crates.
aptos-api = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-api-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-bitvec = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-block-executor = { git = "https://github.com/movementlabsxyz/aptos-core.git", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-cached-packages = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-config = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-consensus-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-crypto = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e", features = [
aptos-api = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-api-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-bitvec = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-block-executor = { git = "https://github.com/movementlabsxyz/aptos-core.git", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-cached-packages = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-config = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-consensus-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-crypto = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb", features = [
"cloneable-private-keys",
] }
aptos-db = { git = "https://github.com/movementlabsxyz/aptos-core.git", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-executor = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-executor-test-helpers = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-executor-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-faucet-core = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-framework = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-language-e2e-tests = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-mempool = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-proptest-helpers = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-sdk = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-state-view = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-storage-interface = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-temppath = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-vm = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-vm-genesis = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-vm-logging = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-vm-validator = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-logger = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-vm-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-indexer = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-indexer-grpc-fullnode = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-indexer-grpc-table-info = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-protos = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "8b8eb8fd0a3fa78086522bda7886ecd86fc6d24e" }
aptos-db = { git = "https://github.com/movementlabsxyz/aptos-core.git", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-executor = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-executor-test-helpers = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-executor-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-faucet-core = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-framework = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-language-e2e-tests = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-mempool = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-proptest-helpers = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-sdk = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-state-view = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-storage-interface = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-temppath = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-vm = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-vm-genesis = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-vm-logging = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-vm-validator = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-logger = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-vm-types = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-indexer = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-indexer-grpc-fullnode = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-indexer-grpc-table-info = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }
aptos-protos = { git = "https://github.com/movementlabsxyz/aptos-core", rev = "a22a721f036c03e1e9109d8f62f7bcc5be144fcb" }

# Indexer
processor = { git = "https://github.com/movementlabsxyz/aptos-indexer-processors", rev = "7658338eb9224abd9698c1e02dbc6ca526c268ce" }
Expand Down
6 changes: 6 additions & 0 deletions networks/movement/movement-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ path = "src/bin/e2e/whitelist.rs"
name = "movement-tests-e2e-ggp-gas-fee"
path = "src/bin/e2e/ggp_gas_fee.rs"

[[bin]]
name = "movement-tests-e2e-ggp-non-native-token"
path = "src/bin/e2e/ggp_non_native_token.rs"

[dependencies]
aptos-sdk = { workspace = true }
Expand All @@ -57,6 +60,7 @@ serde = { workspace = true }
serde_yaml = { workspace = true }
chrono = { workspace = true }
bcs = { workspace = true }
hex = { workspace = true }
rayon = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
Expand All @@ -73,6 +77,7 @@ movement-da-light-node-client = { workspace = true }
movement-da-light-node-proto = { workspace = true, features = ["client"] }
movement-types = { workspace = true }


[dev-dependencies]
reqwest = { workspace = true }
serde_json = { workspace = true }
Expand All @@ -84,5 +89,6 @@ dot-movement = { workspace = true }
aptos-protos = { workspace = true }
tracing-test = { workspace = true }


[lints]
workspace = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
use anyhow::Context;
use aptos_sdk::move_types::ident_str;
use aptos_sdk::move_types::language_storage::ModuleId;
use aptos_sdk::rest_client::Transaction;
use aptos_sdk::types::account_address::AccountAddress;
use aptos_sdk::{move_types::language_storage::TypeTag, transaction_builder::TransactionFactory};
use aptos_types::chain_id::ChainId;
use aptos_types::transaction::{EntryFunction, TransactionPayload};
use movement_client::{
coin_client::CoinClient,
rest_client::{Client, FaucetClient},
types::LocalAccount,
};
use once_cell::sync::Lazy;
use std::env;
use std::path::PathBuf;
use std::str::FromStr;
use tokio::process::Command;
use url::Url;

/// limit of gas unit
const GAS_UNIT_LIMIT: u64 = 100000;
/// minimum price of gas unit of aptos chains
pub const GAS_UNIT_PRICE: u64 = 100;
const ACCOUNT_ADDRESS: &str = "30005dbbb9b324b18bed15aca87770512ec7807410fabb0420494d9865e56fa4";
//
// NB: This is a determinisitic privake key generated from the init command
// used for testing purposes only
const PRIVATE_KEY: &str = "0x97121e4f94695b6fb65a24899c5cce23cc0dad5a1c07caaeb6dd555078d14ba7";

static SUZUKA_CONFIG: Lazy<movement_config::Config> = Lazy::new(|| {
let dot_movement = dot_movement::DotMovement::try_from_env().unwrap();
let config = dot_movement.try_get_config_from_json::<movement_config::Config>().unwrap();
config
});

// :!:>section_1c
static NODE_URL: Lazy<Url> = Lazy::new(|| {
let node_connection_address = SUZUKA_CONFIG
.execution_config
.maptos_config
.client
.maptos_rest_connection_hostname
.clone();
let node_connection_port = SUZUKA_CONFIG
.execution_config
.maptos_config
.client
.maptos_rest_connection_port
.clone();

let node_connection_url =
format!("http://{}:{}", node_connection_address, node_connection_port);

Url::from_str(node_connection_url.as_str()).unwrap()
});

static FAUCET_URL: Lazy<Url> = Lazy::new(|| {
let faucet_listen_address = SUZUKA_CONFIG
.execution_config
.maptos_config
.client
.maptos_faucet_rest_connection_hostname
.clone();
let faucet_listen_port = SUZUKA_CONFIG
.execution_config
.maptos_config
.client
.maptos_faucet_rest_connection_port
.clone();

let faucet_listen_url = format!("http://{}:{}", faucet_listen_address, faucet_listen_port);

Url::from_str(faucet_listen_url.as_str()).unwrap()
});

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let rest_client = Client::new(NODE_URL.clone());
let faucet_client = FaucetClient::new(FAUCET_URL.clone(), NODE_URL.clone());
let coin_client = CoinClient::new(&rest_client);

let crate_dir = env::var("CARGO_MANIFEST_DIR").expect(
"CARGO_MANIFEST_DIR is not set. Make sure to run this inside a Cargo build context.",
);

println!("Node URL: {:?}", NODE_URL.as_str());
println!("Faucet URL: {:?}", FAUCET_URL.as_str());

// Use the account value generated from the init command
// found in ./movement/config.yaml
let init_status = Command::new("movement")
.args([
"init",
"--network",
"custom",
"--rest-url",
NODE_URL.as_str(),
"--faucet-url",
FAUCET_URL.as_str(),
"--assume-yes",
"--private-key",
PRIVATE_KEY,
])
.status()
.await
.expect("Failed to execute `movement init` command");

if !init_status.success() {
anyhow::bail!("Initializing Move module failed. Please check the `movement init` command.");
}

let target_dir = PathBuf::from(crate_dir).join("src").join("move-modules");
let target_dir_clone = target_dir.clone();

println!("target_dir: {:?}", target_dir);

// account associated with private key used for init
let publish_status = Command::new("movement")
.args([
"move",
"publish",
"--skip-fetch-latest-git-deps",
"--sender-account",
ACCOUNT_ADDRESS,
"--assume-yes",
])
.current_dir(target_dir_clone)
.status()
.await
.expect("Failed to execute `movement move publish` command");

// Check if the publish succeeded
if !publish_status.success() {
anyhow::bail!(
"Publishing Move module failed. Please check the `movement move publish` command."
);
}

let args = vec![bcs::to_bytes(
&AccountAddress::from_hex_literal(&format!(
"0x{}",
hex::encode(AccountAddress::from_str(ACCOUNT_ADDRESS).unwrap().to_vec())
))
.unwrap(),
)
.unwrap()];

let init_payload = make_aptos_payload(
AccountAddress::from_str(
"0x97121e4f94695b6fb65a24899c5cce23cc0dad5a1c07caaeb6dd555078d14ba7",
)
.unwrap(),
"test_token",
"initialize_test_token",
vec![],
args,
);

let tx_response = send_aptos_transaction(
&rest_client,
&mut LocalAccount::from_private_key(PRIVATE_KEY, 0)?,
init_payload,
)
.await?;

println!("Transaction response: {:?}", tx_response);

// Create the proposer account and fund it from the faucet
let proposer = LocalAccount::generate(&mut rand::rngs::OsRng);
faucet_client
.fund(proposer.address(), 1_000_000)
.await
.context("Failed to fund proposer account")?;

// Create the beneficiary account and fund it from the faucet
let beneficiary = LocalAccount::generate(&mut rand::rngs::OsRng);
faucet_client
.fund(beneficiary.address(), 1_000_000)
.await
.context("Failed to fund beneficiary account")?;
let beneficiary_address = beneficiary.address().to_hex_literal();

// TODO: run some methods, collect some gas, and check the balance of the governed gas pool

let amount = 100_000; // TODO: replace with appropriate amount w.r.t. gas collection.

let pre_beneficiary_balance = coin_client
.get_account_balance(&beneficiary.address())
.await
.context("Failed to get beneficiary's account balance")?;

Ok(())
}

#[allow(dead_code)]
async fn send_aptos_transaction(
client: &Client,
signer: &mut LocalAccount,
payload: TransactionPayload,
) -> anyhow::Result<Transaction> {
let state = client
.get_ledger_information()
.await
.context("Failed in getting chain id")?
.into_inner();

let transaction_factory = TransactionFactory::new(ChainId::new(state.chain_id))
.with_gas_unit_price(100)
.with_max_gas_amount(GAS_UNIT_LIMIT);

let signed_tx = signer.sign_with_transaction_builder(transaction_factory.payload(payload));

let response = client
.submit_and_wait(&signed_tx)
.await
.map_err(|e| anyhow::anyhow!(e.to_string()))?
.into_inner();
Ok(response)
}

fn make_aptos_payload(
package_address: AccountAddress,
module_name: &'static str,
function_name: &'static str,
ty_args: Vec<TypeTag>,
args: Vec<Vec<u8>>,
) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(package_address, ident_str!(module_name).to_owned()),
ident_str!(function_name).to_owned(),
ty_args,
args,
))
}
16 changes: 16 additions & 0 deletions networks/movement/movement-client/src/move-modules/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "test-token"
version = "1.0.0"
authors = []

[addresses]
test_token = "0x30005dbbb9b324b18bed15aca87770512ec7807410fabb0420494d9865e56fa4"

[dev-addresses]

[dependencies.AptosFramework]
git = "https://github.com/movementlabsxyz/aptos-core.git"
rev = "governed-gas-pool"
subdir = "aptos-move/framework/aptos-framework"

[dev-dependencies]
10 changes: 10 additions & 0 deletions networks/movement/movement-client/src/move-modules/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Initializes an account if keys are not present
echo "Initializing account"
initialize_output=$(echo -ne '\n' | aptos init --network custom --rest-url $NODE_URL --faucet-url $FAUCET_URL --assume-yes)
echo "$initialize_output"

echo "Publishing the module"
aptos move clean --assume-yes
aptos move publish --package-dir src/tests/complex-alice --named-addresses resource_roulette=default --assume-yes
Loading
Loading