Skip to main content

Install WebAssembly (Wasm) bytecode using code

This process uploads the contract code to the Stellar Testnet in a transaction, the uploaded Wasm blob is a contract source, which can be thought of as a 'class' of a contract. Multiple instances of a contract can be deployed which share the same source, but have their own state.

Prerequisites

Before you begin, ensure you have the following installed to compile a smart contract:

  1. Rust and Cargo (for compiling smart contracts)
  2. The Stellar CLI

Initialize and build a sample Rust contract

soroban contract init hello-world
cd hello-world

# use rust compiler to compile Rust project into a WebAssembly (Wasm) dynamic library (cdylib).
soroban contract build
# cargo rustc --manifest-path=contracts/hello_world/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release

We are initializing the default hello_world contract in soroban_examples to the directory hello-world. You may use the -w option to create with another example like account.

After building the contract for release, the generated .wasm file is at the path hello-word/target/wasm32-unknown-unknown/release/hello_world.wasm

Upload Wasm to the Stellar blockchain

We can use one of the SDKs, install necessary dependencies for your chosen programming language:

Create a new directory for your project and navigate into it:

mkdir install-wasm
cd install-wasm

Running the install script

Different programming languages can be used to upload the .wasm file, its SHA256 hash is used for deploying the contract.

This guide will walk you through installing the Wasm of the contract using the JavaScript SDK: js-stellar-sdk.

Create a new Node.js project with a JavaScript file, and install necessary dependencies:

touch index.js
npm init es6 -y
npm install @stellar/stellar-sdk fs

Run the script with node index.js, it reads the Wasm file, gets account details, and uploads the contract in a transaction:

// Import necessary modules in your JavaScript file:
import * as StellarSDK from "@stellar/stellar-sdk";
import fs from "fs";

async function uploadWasm(filePath) {
// reads the compiled Wasm file to buffer
const bytecode = fs.readFileSync(filePath);

// retrieves account details from the network
const account = await server.getAccount(sourceKeypair.publicKey());

// installs the bytecode with a `uploadContractWasm` Stellar operation wrapped in a transaction sent to the network
const operation = StellarSDK.Operation.uploadContractWasm({ wasm: bytecode });
return await buildAndSendTransaction(account, operation);
}

// constructs a transaction, signs it, and submits it to the network, handling any necessary retries for transaction confirmation.
async function buildAndSendTransaction(account, operations) {
const transaction = new StellarSDK.TransactionBuilder(account, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET,
})
.addOperation(operations)
.setTimeout(30)
.build();

const tx = await server.prepareTransaction(transaction);
tx.sign(sourceKeypair);

console.log("Submitting transaction...");
let response = await server.sendTransaction(tx);
const hash = response.hash;
console.log(`Transaction hash: ${hash}`);
console.log("Awaiting confirmation...");

while (true) {
response = await server.getTransaction(hash);
if (response.status !== "NOT_FOUND") {
break;
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}

if (response.status === "SUCCESS") {
console.log("Transaction successful.");
return response;
} else {
console.log("Transaction failed.");
throw new Error("Transaction failed");
}
}

// Upload contract to the testnet
const server = new StellarSDK.SorobanRpc.Server(
"https://soroban-testnet.stellar.org:443",
);
// Replace `Your_Secret_Key`
const sourceKeypair = StellarSDK.Keypair.fromSecret("Your_Secret_Key");
// Adjust this path as necessary
const wasmFilePath =
"../target/wasm32-unknown-unknown/release/hello_world.wasm";

try {
let uploadResponse = await uploadWasm(wasmFilePath);
const byteArray = uploadResponse.returnValue.bytes();
const wasmHash = byteArray.toString("hex");
console.log(`Wasm hash: ${wasmHash}`);
} catch (error) {
console.error(error);
}

Replace "Your_Secret_Key" with your actual secret key.

stellar keys generate --global hello --network testnet
stellar keys show hello

The Stellar CLI can be used to generate identities, e.g. hello, and show its secret key.

tip

Ensure that you handle secret and private keys securely in production environments and never expose them in your code repositories.

Submitting transaction...
Transaction hash: cef7a63667fe5b0ddcde5562d90e0a40bc04c69616916d1d7fa74a8571bbd82f
Awaiting confirmation...
Transaction successful.
Wasm hash: 275405755441e4be59555bb5c5fd81e84ed21659015d8f3594796c1cf3f380db

The returned upload transaction hash can be viewed with online tools: stellar.expert/explorer/testnet/tx/cef7a63667fe5b0ddcde5562d90e0a40bc04c69616916d1d7fa74a8571bbd82f

Uploaded contracts are stored in ContractCodeEntry ledger entries. These entries are keyed by the hash of the Wasm used to upload them.

You may use the Wasm hash for deployment with the Stellar CLI:

stellar contract deploy \
--source hello \
--network testnet \
--wasm-hash 275405755441e4be59555bb5c5fd81e84ed21659015d8f3594796c1cf3f380db
# CC6NAQE3ZHRQV3NPQB3F3NYEFBAMEABA4KQTM6A2V5V7PBR5H3UEU3MW

View the deployed contract using the returned identifier with online tools: stellar.expert/explorer/testnet/contract/CC6NAQE3ZHRQV3NPQB3F3NYEFBAMEABA4KQTM6A2V5V7PBR5H3UEU3MW