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

Resolves Docs bounty issue 619 #694

Merged
merged 4 commits into from
Jul 2, 2024
Merged
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---
title: Install and deploy a smart contract with code
hide_table_of_contents: true
draft: true
---

<head>
<title>Install and deploy a smart contract with code</title>
<meta charSet="utf-8" />
<meta
property="og:title"
content="Install and deploy a smart contract with code"
/>
<meta
property="og:description"
content="This guide will walk you through the process of installing and deploying a smart contract using js-stellar-sdk. We will cover the setup of a sample Rust contract, creating a Node.js project to manage the deployment, and finally, installing the wasm of the contract and deploying it to the network"
/>
</head>

This guide will walk you through the process of installing and deploying a smart contract using [js-stellar-sdk](https://github.com/stellar/js-stellar-sdk). We will cover the setup of a sample Rust contract, creating a Node.js project to manage the deployment, and finally, installing the wasm of the contract and deploying it to the network

# Prerequisites

Before you begin, ensure you have the following installed:

1. [Rust](https://www.rust-lang.org/) and Cargo (for compiling smart contracts)
2. [Node.js](https://nodejs.org/en) and npm (for running JavaScript deployment scripts)
3. [Soroban CLI](../../getting-started/setup.mdx#install-the-soroban-cli)

# Initialize a sample Rust Contract

```bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command kicks back the following errors:

cd: no such file or directory: hello-world
error: the following required arguments were not provided:
  <PROJECT_PATH>

Usage: soroban contract init <PROJECT_PATH>

For more information, try '--help'.

Could you please step through the tutorial and let me know when it has been updated? Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I see that the mkdir command creates a directory in the home directory which can be confusing. Maybe it would be better to remove ~/

soroban contract init hello-world
cd hello-world
soroban contract build
```

This sequence of commands creates a new directory for your project, initializes a new Soroban smart contract within that directory, and builds the contract. The build generates .wasm file in the path `hello-word/target/wasm32-unknown-unknown/release/hello_world.wasm`

# Create a Node Project

1. Create a new directory for your Node.js project and navigate into it:

```bash
mkdir deploy-contract
cd deploy-contract
```

2. Initialize a new Node.js project and install necessary dependencies:

```bash
npm init -y
npm install @stellar/stellar-sdk fs
```

# Set Up Deployment Scripts

## Imports

Import necessary modules in your JavaScript file:

```javascript
import * as StellarSDK from "@stellar/stellar-sdk";
import fs from "fs";
```

## Installing the WASM on the network

Create a function to upload the compiled WASM file:

```javascript
async function uploadWasm(filePath) {
const bytecode = fs.readFileSync(filePath);
const account = await server.getAccount(sourceKeypair.publicKey());
const operation = StellarSDK.Operation.uploadContractWasm({ wasm: bytecode });
return await buildAndSendTransaction(account, operation);
}
```

This function reads the compiled WASM file, retrieves account details from the network, and installs the bytecode using `uploadContractWasm` Stellar operation, which when wrapped in a transaction is sent to the network.

## Deploy contract

Deploy the contract by referencing the WASM hash:

```javascript
async function deployContract(response) {
const account = await server.getAccount(sourceKeypair.publicKey());
const operation = StellarSDK.Operation.createCustomContract({
wasmHash: response.returnValue.bytes(),
address: StellarSDK.Address.fromString(sourceKeypair.publicKey()),
salt: response.hash,
});
const responseDeploy = await buildAndSendTransaction(account, operation);
const contractAddress = StellarSDK.StrKey.encodeContract(
StellarSDK.Address.fromScAddress(
responseDeploy.returnValue.address(),
).toBuffer(),
);
console.log(contractAddress);
}
```

This function uses the WASM hash to deploy the contract using the `createCustomContract` stellar operation, which when wrapped in a transaction is sent to the network, generating a contract address.

## Building, Signing and Sending the Transaction

Handle the building, signing, and sending of transactions:

```javascript
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");
}
}
```

This function constructs a transaction, signs it, and submits it to the network, handling any necessary retries for transaction confirmation.

# Running the Script

Execute the deployment script:

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

try {
let uploadResponse = await uploadWasm(wasmFilePath);
await deployContract(uploadResponse);
} catch (error) {
console.error(error);
}
```

Replace "Your_Secret_Key" with your actual secret key. This script initiates the upload of the WASM file and deploys the contract, resulting in a contract address where the contract is deployed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NICLEY DONE! The script works great

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be helpful to show all of the scripts stacked together in a single file at the end.

import * as StellarSDK from "@stellar/stellar-sdk";
import fs from "fs";
async function uploadWasm(filePath) {
    const bytecode = fs.readFileSync(filePath);
    const account = await server.getAccount(sourceKeypair.publicKey());
    const operation = StellarSDK.Operation.uploadContractWasm({ wasm: bytecode });
    return await buildAndSendTransaction(account, operation);
}
async function deployContract(response) {
    const account = await server.getAccount(sourceKeypair.publicKey());
    const operation = StellarSDK.Operation.createCustomContract({
      wasmHash: response.returnValue.bytes(),
      address: StellarSDK.Address.fromString(sourceKeypair.publicKey()),
      salt: response.hash,
    });
    const responseDeploy = await buildAndSendTransaction(account, operation);
    const contractAddress = StellarSDK.StrKey.encodeContract(
      StellarSDK.Address.fromScAddress(
        responseDeploy.returnValue.address(),
      ).toBuffer(),
    );
    console.log(contractAddress);
}
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");
    }
}
  
const server = new StellarSDK.SorobanRpc.Server(
    "https://soroban-testnet.stellar.org:443",
  );
  const sourceKeypair = StellarSDK.Keypair.fromSecret("Your_Secret_Key");
  const wasmFilePath =
    "../hello-world/target/wasm32-unknown-unknown/release/hello_world.wasm"; // Adjust this path as necessary
  
  try {
    let uploadResponse = await uploadWasm(wasmFilePath);
    await deployContract(uploadResponse);
  } catch (error) {
    console.error(error);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay @Julian-dev28 I have added the Complete Script at the end as you said.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thanks so much


This is just demo code, so ensure that you handle secrets and private keys securely in production environments and never expose them in your code repositories. This guide should provide you with a clear path to installing and deploying your smart contracts using Javascript code.
Loading