Instalar código byte de WebAssembly (Wasm) usando código
Este proceso sube el código del contrato a la Stellar Testnet en una transacción, el blob Wasm subido es una fuente del contrato, que se puede considerar como la 'clase' de un contrato. Se pueden desplegar múltiples instancias de un contrato que comparten la misma fuente, pero tienen su propio estado.
Prerrequisitos
Antes de comenzar, asegúrate de tener instalado lo siguiente para compilar un contrato inteligente:
- Rust y Cargo (para compilar contratos inteligentes)
- La CLI de Stellar
Inicializar y desarrollar un contrato Rust de ejemplo
stellar contract init hello-world
cd hello-world
# use rust compiler to compile Rust project into a WebAssembly (Wasm) dynamic library (cdylib).
stellar contract build
# cargo rustc --manifest-path=contracts/hello_world/Cargo.toml --crate-type=cdylib --target=wasm32v1-none --release
Estamos inicializando el contrato hello_world por defecto en soroban_examples en el directorio hello-world. Puedes usar la opción -w para crear con otro ejemplo como account.
Después de desarrollar el contrato para producción, el archivo .wasm generado está en la ruta hello-word/target/wasm32v1-none/release/hello_world.wasm
Subir Wasm a la blockchain Stellar
Podemos usar uno de los SDKs, instala las dependencias necesarias para el lenguaje de programación que elijas:
Crea un nuevo directorio para tu proyecto y navega dentro de él:
mkdir install-wasm
cd install-wasm
Ejecutar el script de instalación
Se pueden usar diferentes lenguajes de programación para subir el archivo .wasm, su hash SHA256 se usa para desplegar el contrato.
- JavaScript
- Python
- Rust
Esta guía te llevará a través de la instalación del Wasm del contrato usando el SDK de JavaScript: js-stellar-sdk.
Crea un nuevo proyecto Node.js con un archivo JavaScript e instala las dependencias necesarias:
touch index.js
npm init es6 -y
npm install @stellar/stellar-sdk fs
Ejecuta el script con node index.js, lee el archivo Wasm, obtiene detalles de la cuenta y sube el contrato en una transacción:
// 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.rpc.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/wasm32v1-none/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);
}
Esta guía te llevará a través de la instalación del Wasm del contrato usando el SDK de Python: py-stellar-base.
Crea un nuevo script en Python e instala las dependencias necesarias:
touch install.py
pip install stellar-sdk
Ejecuta el script con python3 install.py, lee el archivo Wasm, obtiene detalles de la cuenta y sube el contrato en una transacción:
import asyncio
import time
from stellar_sdk import Keypair, Network, SorobanServer, TransactionBuilder, xdr as stellar_xdr
from stellar_sdk.exceptions import PrepareTransactionException
from stellar_sdk.soroban_rpc import GetTransactionStatus
import hashlib
def print_wasm_hash(wasm_bytes):
# Create a SHA256 hash object
sha256_hash = hashlib.sha256()
# Update the hash object with the WASM bytes
sha256_hash.update(wasm_bytes)
# Get the digest and convert it to a stellar_sdk.xdr.Hash object
hash_bytes = sha256_hash.digest()
xdr_hash = stellar_xdr.Hash(hash_bytes)
hash_hex_str = xdr_hash.hash.hex()
print(f"Wasm Hash: {hash_hex_str}")
async def upload_wasm(file_path):
# Read the compiled Wasm file
with open(file_path, 'rb') as file:
wasm_bytes = file.read()
# Retrieve account details from the network
account = server.load_account(source_keypair.public_key)
# print wasm hash for later deployment
print_wasm_hash(wasm_bytes)
# Install the bytes with an 'uploadContractWasm' Stellar operation
return await build_and_send_transaction(account, wasm_bytes)
async def build_and_send_transaction(account, bytes):
transaction = (
TransactionBuilder(
source_account=account,
network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE,
)
.append_upload_contract_wasm_op(bytes)
.set_timeout(30)
.build()
)
print("Preparing transaction...")
try:
tx = server.prepare_transaction(transaction)
except PrepareTransactionException as e:
print(f"Got exception: {e}")
return None
tx.sign(source_keypair)
print("Submitting transaction...")
response = server.send_transaction(tx)
hash = response.hash
print(f"Transaction hash: {hash}")
print("Awaiting confirmation...")
while True:
response = server.get_transaction(hash)
if response.status != GetTransactionStatus.NOT_FOUND:
break
time.sleep(1)
if response.status == GetTransactionStatus.SUCCESS:
print("Transaction successful.")
return response
else:
print("Transaction failed.")
raise Exception("Transaction failed")
# Upload contract to the testnet
server = SorobanServer("https://soroban-testnet.stellar.org:443")
# Replace 'Your_Secret_Key' with your actual secret key
source_keypair = Keypair.from_secret("Your_Secret_Key")
# Adjust this path as necessary
wasm_file_path = "../target/wasm32v1-none/release/hello_world.wasm"
async def main():
try:
await upload_wasm(wasm_file_path)
except Exception as error:
print(f"Error: {error}")
# Run the main function
asyncio.run(main())
Esta guía te llevará a través de la subida del Wasm del contrato usando el SDK de Rust: rs-soroban-client.
Crea un nuevo proyecto Cargo e instala las dependencias necesarias:
cargo init
cargo add soroban_client
cargo add tokio -F macros,full
Copia el código abajo en src/main.rs y luego ejecuta el programa con cargo run, lee el archivo Wasm, obtiene detalles de la cuenta y sube el contrato en una transacción:
use std::time::Duration;
use soroban_client::{
account::{Account, AccountBehavior},
keypair::{Keypair, KeypairBehavior},
network::{NetworkPassphrase, Networks},
operation::Operation,
soroban_rpc::TransactionStatus,
transaction::{TransactionBehavior, TransactionBuilder, TransactionBuilderBehavior},
Options, Server,
};
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server_url = "https://soroban-testnet.stellar.org";
let server = Server::new(server_url, Options::default())?;
// Adjust this path as necessary
let wasm_file_path = "../target/wasm32v1-none/release/hello_world.wasm";
// Read the wasm file
let wasm_bytes = std::fs::read(wasm_file_path)?;
// Build the xdr::HostFunction::UploadContractWasm operation
let upload_wasm_op = Operation::new()
.upload_wasm(&wasm_bytes, None)
.expect("Cannot create upload_wasm operation");
// Replace Your_Secret_Key with your actual secret key
let source_keypair = Keypair::from_secret("Your_Secret_Key")?;
let source_public_key = &source_keypair.public_key();
// Get account information from server
let account_data = server.get_account(source_public_key).await?;
// Build the Account to use in the transaction
let mut source_account = Account::new(source_public_key, &account_data.sequence_number())?;
// Build the operation
let tx = TransactionBuilder::new(&mut source_account, Networks::testnet(), None)
.fee(1000u32)
.add_operation(upload_wasm_op)
.build();
let mut ptx = server.prepare_transaction(&tx).await?;
ptx.sign(&[source_keypair]);
println!("> Uploading WASM executable");
let response = server.send_transaction(ptx).await?;
let hash = &response.hash;
println!(">> Tx hash: {hash}");
let wasm_hash = match server.wait_transaction(hash, Duration::from_secs(15)).await {
Ok(tx_result) if tx_result.status == TransactionStatus::Success => {
let (_meta, ret_val) = tx_result.to_result_meta().expect("No meta found");
if let Some(scval) = ret_val {
let bytes: Vec<u8> = scval.try_into().expect("Cannot convert ScVal to Vec<u8>");
*bytes.last_chunk::<32>().expect("Not 32 bytes")
} else {
return Err(">> None return value".into());
}
}
_ => {
println!(">> Failed to upload the WASM executable");
return Err(">> Failed to upload the wasm".into());
}
};
let hex_wasm_hash: String = wasm_hash.iter().map(|b| format!("{:02x}", b)).collect();
println!(">> Wasm hash: {hex_wasm_hash}");
println!();
Ok(())
}
Reemplaza "Your_Secret_Key" con tu clave secreta real.
stellar keys generate --global hello --network testnet
stellar keys show hello
La CLI de Stellar se puede usar para generar identidades, por ejemplo hello, y mostrar su clave secreta.
Asegúrate de manejar las claves secretas y privadas de forma segura en entornos de producción y nunca las expongas en tus repositorios de código.
Submitting transaction...
Transaction hash: cef7a63667fe5b0ddcde5562d90e0a40bc04c69616916d1d7fa74a8571bbd82f
Awaiting confirmation...
Transaction successful.
Wasm hash: 275405755441e4be59555bb5c5fd81e84ed21659015d8f3594796c1cf3f380db
El hash de la transacción de carga devuelto puede verse con herramientas en línea: stellar.expert/explorer/testnet/tx/cef7a63667fe5b0ddcde5562d90e0a40bc04c69616916d1d7fa74a8571bbd82f
Los contratos cargados se almacenan en entradas ledger ContractCodeEntry. Estas entradas están indexadas por el hash del Wasm usado para cargarlos.
Puedes usar el hash del Wasm para desplegar con la CLI de Stellar:
stellar contract deploy \
--source-account hello \
--network testnet \
--wasm-hash 275405755441e4be59555bb5c5fd81e84ed21659015d8f3594796c1cf3f380db
# CC6NAQE3ZHRQV3NPQB3F3NYEFBAMEABA4KQTM6A2V5V7PBR5H3UEU3MW
Visualiza el contrato desplegado usando el identificador devuelto con herramientas en línea: stellar.expert/explorer/testnet/contract/CC6NAQE3ZHRQV3NPQB3F3NYEFBAMEABA4KQTM6A2V5V7PBR5H3UEU3MW
Guías en esta categoría:
📄️ Crear una cuenta
Aprende sobre cómo crear cuentas Stellar, pares de llaves, financiamiento y conceptos básicos de las cuentas.
📄️ Enviar y recibir pagos
Aprende a enviar pagos y estar atento a los pagos recibidos en la red Stellar.
📄️ Cuentas canalizadas
Crea cuentas canalizadas para enviar transacciones a la red a una alta velocidad.
📄️ Saldos reclamables
Divide un pago en dos partes creando un saldo reclamable.
📄️ Recuperaciones
Usa las recuperaciones para quemar una cantidad específica de un activo habilitado para recuperación desde una trustline o un saldo reclamable.
📄️ Transacciones de suplemento de tarifa
Usa transacciones fee-bump para pagar las comisiones de transacción en nombre de otra cuenta sin volver a firmar la transacción.
📄️ Reservas patrocinadas
Utiliza las reservas patrocinadas para pagar las reservas base en nombre de otra cuenta.
📄️ Pagos con rutas
Enviar un pago donde el activo recibido sea diferente del activo enviado.
📄️ Cuentas agrupadas: cuentas muxed y memos
Usa cuentas muxed para diferenciar entre cuentas individuales dentro de una cuenta agrupada.
📄️ Instalar y desplegar un contrato inteligente con código
Instalar y desplegar un contrato inteligente con código.
📄️ Invocar una función de contrato en una transacción usando SDKs
Usa el Stellar SDK para crear, simular y ensamblar una transacción.
📄️ guía del método RPC simulateTransaction
Guía de ejemplos y tutoriales de simulateTransaction.
📄️ Enviar una transacción a Stellar RPC utilizando el SDK de JavaScript
Utiliza un mecanismo de repetición para enviar una transacción al RPC.
📄️ Subir código byte de WebAssembly (Wasm) usando código
Sube el Wasm del contrato usando js-stellar-sdk.