Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 33 additions & 6 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,15 +458,23 @@ If no keys are specified the contract itself is extended.

Deploy a wasm contract

**Usage:** `stellar contract deploy [OPTIONS] --source-account <SOURCE_ACCOUNT> <--wasm <WASM>|--wasm-hash <WASM_HASH>> [-- <CONTRACT_CONSTRUCTOR_ARGS>...]`
**Usage:** `stellar contract deploy [OPTIONS] --source-account <SOURCE_ACCOUNT> [-- <CONTRACT_CONSTRUCTOR_ARGS>...]`

###### **Arguments:**

- `<CONTRACT_CONSTRUCTOR_ARGS>` — If provided, will be passed to the contract's `__constructor` function with provided arguments for that function as `--arg-name value`

###### **Build Options:**

- `--package <PACKAGE>` — Package to build when auto-building without --wasm

###### **Metadata:**

- `--meta <META>` — Add key-value to contract meta (adds the meta to the `contractmetav0` custom section)

###### **Options:**

- `--wasm <WASM>` — WASM file to deploy
- `--wasm <WASM>` — WASM file to deploy. When neither --wasm nor --wasm-hash is provided inside a Cargo workspace, builds the project automatically. One of --wasm or --wasm-hash is required when outside a Cargo workspace
- `--wasm-hash <WASM_HASH>` — Hash of the already installed/deployed WASM file
- `--salt <SALT>` — Custom salt 32-byte salt for the token id
- `-s`, `--source-account <SOURCE_ACCOUNT>` [alias: `source`] — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a muxed account (--source MDA…), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` was NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail
Expand All @@ -482,6 +490,7 @@ Deploy a wasm contract

- `--alias <ALIAS>` — The alias that will be used to save the contract's id. Whenever used, `--alias` will always overwrite the existing contract id configuration without asking for confirmation
- `--build-only` — Build the transaction and only write the base64 xdr to stdout
- `--optimize` — Optimize the generated wasm

###### **Options (Global):**

Expand Down Expand Up @@ -788,7 +797,15 @@ This command will create a Cargo workspace project and add a sample Stellar cont

Install a WASM file to the ledger without creating a contract instance

**Usage:** `stellar contract upload [OPTIONS] --source-account <SOURCE_ACCOUNT> --wasm <WASM>`
**Usage:** `stellar contract upload [OPTIONS] --source-account <SOURCE_ACCOUNT>`

###### **Build Options:**

- `--package <PACKAGE>` — Package to build when --wasm is not provided

###### **Metadata:**

- `--meta <META>` — Add key-value to contract meta (adds the meta to the `contractmetav0` custom section)

###### **Options:**

Expand All @@ -799,12 +816,13 @@ Install a WASM file to the ledger without creating a contract instance
- `--sign-with-ledger` — Sign with a ledger wallet
- `--fee <FEE>` — ⚠️ Deprecated, use `--inclusion-fee`. Fee amount for transaction, in stroops. 1 stroop = 0.0000001 xlm
- `--inclusion-fee <INCLUSION_FEE>` — Maximum fee amount for transaction inclusion, in stroops. 1 stroop = 0.0000001 xlm. Defaults to 100 if no arg, env, or config value is provided
- `--wasm <WASM>` — Path to wasm binary
- `--wasm <WASM>` — Path to wasm binary. When omitted inside a Cargo workspace, builds the project automatically. Required when outside a Cargo workspace
- `-i`, `--ignore-checks` — Whether to ignore safety checks when deploying contracts

Default value: `false`

- `--build-only` — Build the transaction and only write the base64 xdr to stdout
- `--optimize` — Optimize the generated wasm

###### **Options (Global):**

Expand All @@ -826,7 +844,15 @@ Install a WASM file to the ledger without creating a contract instance

⚠️ Deprecated, use `contract upload`. Install a WASM file to the ledger without creating a contract instance

**Usage:** `stellar contract install [OPTIONS] --source-account <SOURCE_ACCOUNT> --wasm <WASM>`
**Usage:** `stellar contract install [OPTIONS] --source-account <SOURCE_ACCOUNT>`

###### **Build Options:**

- `--package <PACKAGE>` — Package to build when --wasm is not provided

###### **Metadata:**

- `--meta <META>` — Add key-value to contract meta (adds the meta to the `contractmetav0` custom section)

###### **Options:**

Expand All @@ -837,12 +863,13 @@ Install a WASM file to the ledger without creating a contract instance
- `--sign-with-ledger` — Sign with a ledger wallet
- `--fee <FEE>` — ⚠️ Deprecated, use `--inclusion-fee`. Fee amount for transaction, in stroops. 1 stroop = 0.0000001 xlm
- `--inclusion-fee <INCLUSION_FEE>` — Maximum fee amount for transaction inclusion, in stroops. 1 stroop = 0.0000001 xlm. Defaults to 100 if no arg, env, or config value is provided
- `--wasm <WASM>` — Path to wasm binary
- `--wasm <WASM>` — Path to wasm binary. When omitted inside a Cargo workspace, builds the project automatically. Required when outside a Cargo workspace
- `-i`, `--ignore-checks` — Whether to ignore safety checks when deploying contracts

Default value: `false`

- `--build-only` — Build the transaction and only write the base64 xdr to stdout
- `--optimize` — Optimize the generated wasm

###### **Options (Global):**

Expand Down
1 change: 1 addition & 0 deletions cmd/crates/soroban-test/tests/it/integration.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod auto_build;
mod bindings;
mod constructor;
mod contract;
Expand Down
249 changes: 249 additions & 0 deletions cmd/crates/soroban-test/tests/it/integration/auto_build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
use soroban_test::{AssertExt, TestEnv};
use std::path::PathBuf;

#[tokio::test]
async fn deploy_without_wasm_auto_builds() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// Deploy without --wasm flag should auto-build the contract
let contract_id = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("deploy")
.arg("--source-account")
.arg("test")
.assert()
.success()
.stdout_as_str();

// Verify contract was deployed by invoking a function
sandbox
.invoke_with_test(&["--id", &contract_id, "--", "hello", "--world=world"])
.await
.unwrap();
}

#[tokio::test]
async fn deploy_workspace_without_package_builds_all() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/workspace");

// Deploy in workspace without --wasm and without --package builds and deploys all contracts
sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("deploy")
.arg("--source-account")
.arg("test")
.assert()
.success()
.stderr(predicates::str::contains("Build Complete"));
}

#[tokio::test]
async fn deploy_workspace_with_package_auto_builds() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/workspace");

// Deploy in workspace with --package should auto-build the specified contract
let contract_id = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("deploy")
.arg("--source-account")
.arg("test")
.arg("--package")
.arg("add")
.assert()
.success()
.stdout_as_str();

// Verify contract was deployed
assert!(!contract_id.is_empty(), "Expected contract ID");
}

#[tokio::test]
async fn upload_without_wasm_auto_builds() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// Upload without --wasm flag should auto-build the contract
let wasm_hash = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("upload")
.arg("--source-account")
.arg("test")
.assert()
.success()
.stdout_as_str();

// Verify a hash was returned
assert_eq!(wasm_hash.len(), 64, "Expected 64-character hex hash");
}

#[tokio::test]
async fn upload_workspace_without_package_builds_all() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/workspace");

// Upload in workspace without --wasm and without --package builds and uploads all contracts
sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("upload")
.arg("--source-account")
.arg("test")
.assert()
.success()
.stderr(predicates::str::contains("Build Complete"));
}

#[tokio::test]
async fn upload_workspace_with_package_auto_builds() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/workspace");

// Upload in workspace with --package should auto-build the specified contract
let wasm_hash = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("upload")
.arg("--source-account")
.arg("test")
.arg("--package")
.arg("call")
.assert()
.success()
.stdout_as_str();

// Verify a hash was returned
assert_eq!(wasm_hash.len(), 64, "Expected 64-character hex hash");
}

#[tokio::test]
async fn deploy_outside_cargo_project_requires_wasm() {
let sandbox = TestEnv::new();

// Deploy outside a Cargo project without --wasm should fail
sandbox
.new_assert_cmd("contract")
.arg("deploy")
.arg("--source-account")
.arg("test")
.assert()
.failure()
.stderr(predicates::str::contains(
"--wasm or --wasm-hash is required when not in a Cargo workspace",
));
}

#[tokio::test]
async fn upload_outside_cargo_project_requires_wasm() {
let sandbox = TestEnv::new();

// Upload outside a Cargo project without --wasm should fail
sandbox
.new_assert_cmd("contract")
.arg("upload")
.arg("--source-account")
.arg("test")
.assert()
.failure()
.stderr(predicates::str::contains(
"--wasm is required when not in a Cargo workspace",
));
}

#[tokio::test]
async fn deploy_build_only_rejected_without_wasm() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// --build-only should fail when auto-building (no --wasm or --wasm-hash)
sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("deploy")
.arg("--source-account")
.arg("test")
.arg("--build-only")
.assert()
.failure()
.stderr(predicates::str::contains(
"--build-only is not supported without --wasm or --wasm-hash",
));
}

#[tokio::test]
async fn upload_build_only_rejected_without_wasm() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// --build-only should fail when auto-building (no --wasm)
sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("upload")
.arg("--source-account")
.arg("test")
.arg("--build-only")
.assert()
.failure()
.stderr(predicates::str::contains(
"--build-only is not supported without --wasm",
));
}

#[tokio::test]
async fn deploy_auto_build_with_meta() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// Deploy with --meta should pass metadata through to build
let contract_id = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("deploy")
.arg("--source-account")
.arg("test")
.arg("--meta")
.arg("key=value")
.assert()
.success()
.stdout_as_str();

assert!(!contract_id.is_empty(), "Expected contract ID");
}

#[tokio::test]
async fn upload_auto_build_with_meta() {
let sandbox = TestEnv::new();
let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let fixture_path = cargo_dir.join("tests/fixtures/test-wasms/hello_world");

// Upload with --meta should pass metadata through to build
let wasm_hash = sandbox
.new_assert_cmd("contract")
.current_dir(&fixture_path)
.arg("upload")
.arg("--source-account")
.arg("test")
.arg("--meta")
.arg("key=value")
.assert()
.success()
.stdout_as_str();

assert_eq!(wasm_hash.len(), 64, "Expected 64-character hex hash");
}
Loading