-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deploy a Stellar Asset Contract (SAC) for a Stellar asset using code (#…
…887) * chores: initialization of SAC using code * chores: added code walk through * chores: code explanation git add . * chores: final code explaination * editorial * chores: updated code nitpicks * chores: editorial fix * Update docs/build/guides/conventions/deploy-sac-with-code.mdx * Update docs/build/guides/conventions/deploy-sac-with-code.mdx --------- Co-authored-by: Bri <[email protected]> Co-authored-by: Chris Anatalio <[email protected]>
- Loading branch information
Showing
1 changed file
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
--- | ||
title: Deploy a SAC for a Stellar asset using code | ||
description: Deploy a SAC for a Stellar asset using Javascript SDK | ||
--- | ||
|
||
<head> | ||
<title> | ||
{`Deploy a Stellar Asset Contract (SAC) for a Stellar asset using code`} | ||
</title> | ||
<meta charSet="utf-8" /> | ||
<meta | ||
property="og:title" | ||
content="Deploy a Stellar Asset Contract (SAC) for a Stellar asset using code" | ||
/> | ||
<meta | ||
property="og:description" | ||
content="This is a step-by-step guide to help you deploy a SAC for a Stellar asset using the Stellar SDK." | ||
/> | ||
</head> | ||
|
||
## Overview | ||
|
||
In this guide, you'll learn how to deploy a [Stellar Asset Contract (SAC)](../../../tokens/stellar-asset-contract.mdx) for a Stellar asset using the [Stellar SDK](../../../tools/sdks/library.mdx#javascript-sdk). The Stellar SDK is a set of tools and library designed to help developers build applications that interact with the Stellar blockchain network. | ||
|
||
### Prerequisites: | ||
|
||
- [Node.js ](https://nodejs.org/en) and npm installed. | ||
- Stellar SDK for [JavaScript](https://www.npmjs.com/package/@stellar/stellar-sdk) installed | ||
- [Knowledge about Issuing an Asset on Stellar](https://developers.stellar.org/docs/tokens/how-to-issue-an-asset) | ||
|
||
## Code overview | ||
|
||
```javascript title="deployassetcontract.js" | ||
import * as StellarSdk from "@stellar/stellar-sdk"; | ||
|
||
const networkRPC = "https://soroban-testnet.stellar.org"; | ||
const server = new StellarSdk.SorobanRpc.Server(networkRPC); | ||
const network_passphrase = StellarSdk.Networks.TESTNET; | ||
|
||
async function yeetTx(feedback, message) { | ||
try { | ||
if (feedback.status !== "PENDING") { | ||
throw feedback; | ||
} | ||
|
||
let status; | ||
let attempts = 0; | ||
while (attempts++ < 20) { | ||
// A maximum of 20 polls of transaction status | ||
const tmpStatus = await server.getTransaction(feedback.hash); | ||
switch (tmpStatus.status) { | ||
case "FAILED": | ||
throw tmpStatus; | ||
case "NOT_FOUND": | ||
await sleep(1000); // Wait for one minute | ||
continue; | ||
case "SUCCESS": | ||
status = tmpStatus; | ||
console.log(`${message}: Transaction succeeded`, status); | ||
break; | ||
} | ||
if (status) break; | ||
} | ||
|
||
if (attempts >= 20 || !status) { | ||
throw new Error( | ||
`Failed to find transaction ${feedback.hash} after ${attempts} attempts.`, | ||
); | ||
} | ||
|
||
return status; | ||
} catch (error) { | ||
console.error("Transaction failed:", error); | ||
throw error; | ||
} | ||
} | ||
function sleep(ms) { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
|
||
const deployStellarAssetContract = async () => { | ||
const sourceSecrets = | ||
"SASI6PA4K52GQJF6BC263GLYOADVKFJ4SZ7TFX4QQF2U76T3EJ54DT7Y"; // Replace with your Secret Key | ||
const sourceKeypair = StellarSdk.Keypair.fromSecret(sourceSecrets); | ||
const sourceAccount = await server.getAccount(sourceKeypair.publicKey()); | ||
|
||
try { | ||
const assetCode = "JOEBOY"; | ||
const issuerPublicKey = sourceKeypair.publicKey(); | ||
const customAsset = new StellarSdk.Asset(assetCode, issuerPublicKey); | ||
|
||
const transaction = new StellarSdk.TransactionBuilder(sourceAccount, { | ||
fee: StellarSdk.BASE_FEE, | ||
networkPassphrase: network_passphrase, | ||
}) | ||
.addOperation( | ||
StellarSdk.Operation.createStellarAssetContract({ | ||
asset: customAsset, | ||
}), | ||
) | ||
.setTimeout(30) | ||
.build(); | ||
|
||
const uploadTx = await server.prepareTransaction(transaction); | ||
uploadTx.sign(sourceKeypair); | ||
|
||
const result = await server.sendTransaction(uploadTx); | ||
const feedback = await yeetTx(result, `SACTransactionFeeback`); | ||
const contractBuffer = feedback.returnValue._value._value; | ||
const contractID = StellarSdk.StrKey.encodeContract(contractBuffer); | ||
console.log(`ContractID of Our ${customAsset.code} Asset`, contractID); | ||
} catch (e) { | ||
console.error("An error occurred while Deploying assets:", e); | ||
} | ||
}; | ||
|
||
await deployStellarAssetContract(); | ||
``` | ||
|
||
## Code explanation | ||
|
||
**Server Setup** | ||
|
||
```javascript | ||
import * as StellarSdk from "@stellar/stellar-sdk"; | ||
|
||
const networkRPC = "https://soroban-testnet.stellar.org"; | ||
const server = new StellarSdk.SorobanRpc.Server(networkRPC); | ||
const network_passphrase = StellarSdk.Networks.TESTNET; | ||
``` | ||
|
||
- `networkRPC`: The URL for the Soroban testnet. | ||
- `server`: A new instance of `SorobanRpc.Server` is created, which will be used to interact with the Soroban testnet. | ||
- `network_passphrase`: sets the network passphrase to the TESTNET | ||
|
||
**`yeetTx` function** | ||
|
||
```javascript | ||
async function yeetTx(feedback, message) { | ||
try { | ||
if (feedback.status !== "PENDING") { | ||
throw feedback; | ||
} | ||
|
||
let status; | ||
let attempts = 0; | ||
while (attempts++ < 20) { | ||
const tmpStatus = await server.getTransaction(feedback.hash); | ||
switch (tmpStatus.status) { | ||
case "FAILED": | ||
throw tmpStatus; | ||
case "NOT_FOUND": | ||
await sleep(1000); | ||
continue; | ||
case "SUCCESS": | ||
status = tmpStatus; | ||
console.log(`${message}: Transaction succeeded`, status); | ||
break; | ||
} | ||
if (status) break; | ||
} | ||
|
||
if (attempts >= 20 || !status) { | ||
throw new Error( | ||
`Failed to find transaction ${feedback.hash} after ${attempts} attempts.`, | ||
); | ||
} | ||
|
||
return status; | ||
} catch (error) { | ||
console.error("Transaction failed:", error); | ||
throw error; | ||
} | ||
} | ||
``` | ||
|
||
The `yeetTx` function handles checking the status of a transaction until it either succeeds, fails, or the number of attempts exceeds a limit. | ||
|
||
- `feedback`: The initial feedback object returned when a transaction is submitted. | ||
- `message`: A custom message to log when the transaction succeeds.. | ||
|
||
**`sleep` function** | ||
|
||
```javascript | ||
function sleep(ms) { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
``` | ||
|
||
This function is a helper that returns a promise that resolves after a specified number of milliseconds. It's used to delay the next check in yeetTx when the transaction status is "NOT_FOUND." | ||
|
||
**`DeployStellarAssetContract` function** | ||
|
||
```javascript | ||
const deployStellarAssetContract = async () => { | ||
const sourceSecrets = | ||
"SASI6PA4K52GQJF6BC263GLYOADVKFJ4SZ7TFX4QQF2U76T3EJ54DT7Y"; // Replace with your Secret Key | ||
const network_passphrase = StellarSdk.Networks.TESTNET; | ||
const sourceKeypair = StellarSdk.Keypair.fromSecret(sourceSecrets); | ||
const sourceAccount = await server.getAccount(sourceKeypair.publicKey()); | ||
|
||
try { | ||
const assetCode = "JOEBOY"; | ||
const issuerPublicKey = sourceKeypair.publicKey(); | ||
const customAsset = new StellarSdk.Asset(assetCode, issuerPublicKey); | ||
|
||
const transaction = new StellarSdk.TransactionBuilder(sourceAccount, { | ||
fee: StellarSdk.BASE_FEE, | ||
networkPassphrase: network_passphrase, | ||
}) | ||
.addOperation( | ||
StellarSdk.Operation.createStellarAssetContract({ | ||
asset: customAsset, | ||
}), | ||
) | ||
.setTimeout(30) | ||
.build(); | ||
|
||
const uploadTx = await server.prepareTransaction(transaction); | ||
uploadTx.sign(sourceKeypair); | ||
|
||
const result = await server.sendTransaction(uploadTx); | ||
const feedback = await yeetTx(result, `SACTransactionFeeback`); | ||
const contractBuffer = feedback.returnValue._value._value; | ||
const contractID = StellarSdk.StrKey.encodeContract(contractBuffer); | ||
console.log(`ContractID of Our ${customAsset.code} Asset`, contractID); | ||
} catch (e) { | ||
console.error("An error occurred while Deploying assets:", e); | ||
} | ||
}; | ||
|
||
await deployStellarAssetContract(); | ||
``` | ||
|
||
This function is designed to deploy a Stellar Asset Contract (SAC) on the Soroban testnet. | ||
|
||
- **Secret Key**: It starts by defining the secret key for the source account (`sourceSecrets`), which you must replace with your own. | ||
- **Keypair and Account**: Generates the keypair from the secret key and fetches the account details from the Soroban server. | ||
- **Custom Asset**: Defines a custom asset with the code `JOEBOY` and the issuer's public key. | ||
- **Transaction Building**: A transaction is built using the `TransactionBuilder`, which includes the `createStellarAssetContract` operation for the custom asset. The transaction is then prepared and signed. | ||
- **Send Transaction**: The signed transaction is sent to the network using `server.sendTransaction`. | ||
- **Feedback Handling**: It waits for the transaction feedback using the `yeetTx` function to ensure it has succeeded. extracts the contract buffer from the feedback and converts it to a contract ID using `StellarSdk.StrKey.encodeContract`. finally, it logs the contract ID for the deployed asset. |