Skip to content

Commit 84bc1b9

Browse files
Sean Radgitbook-bot
Sean Rad
authored andcommitted
GITBOOK-651: No subject
1 parent cd66a2b commit 84bc1b9

File tree

112 files changed

+4676
-101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+4676
-101
lines changed

.gitbook/assets/image (1).png

-278 KB
Loading

.gitbook/assets/image (10).png

527 KB
Loading

.gitbook/assets/image (11).png

107 KB
Loading

.gitbook/assets/image (2).png

730 KB
Loading

.gitbook/assets/image (3).png

197 KB
Loading

.gitbook/assets/image (4).png

-433 KB
Loading

.gitbook/assets/image (6).png

15.7 KB
Loading

.gitbook/assets/image (7).png

140 KB
Loading

.gitbook/assets/image (8).png

581 KB
Loading

.gitbook/assets/image (9).png

161 KB
Loading

.gitbook/assets/sn-logo (1).png

639 KB
Loading

.gitbook/assets/sn-logo (2).png

-737 KB
Loading

.gitbook/assets/sn-logo.png

97.8 KB
Loading
64.5 KB
Loading
64.5 KB
Loading

.gitbook/assets/testnetguide_1.png

64.5 KB
Loading

SUMMARY.md

+69-69
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
---
2+
description: Learn how to create a SNIP-20 token on Secret Network
3+
---
4+
5+
# Secret Tokens (SNIP-20)
6+
7+
### Introduction
8+
9+
In this tutorial, we are going to create our own SNIP-20 token on Secret Network using Secret Labs' SNIP-20 reference implementation contract, and we will learn how to upload, instantiate, execute, and query our SNIP-20 contract using Secret.js. Let's dive in!
10+
11+
### Source Code
12+
13+
You can clone the source code [here](https://github.com/scrtlabs/snip20-reference-impl), which we will reference throughout the course of this documentation.
14+
15+
### Prerequisites
16+
17+
Use [the following guide ](https://docs.scrt.network/secret-network-documentation/development/getting-started/setting-up-your-environment)to set up your developer environment.
18+
19+
### Build and Deploy Contract
20+
21+
Now that you've cloned the SNIP-20 reference implementation repo above, let's compile the contract. In your terminal run `make compile-optimized`.
22+
23+
{% hint style="info" %}
24+
In Rust, a Makefile can be used to automate tasks such as building the project, running tests, or even generating documentation. **`Make compile-optimized`** is running the following optimizer command, which you can view in the Makefile:
25+
{% endhint %}
26+
27+
#### Optimizer command
28+
29+
```
30+
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
31+
```
32+
33+
### Configuring Secret.js
34+
35+
1. In your root project folder, create a new folder called `node.`
36+
2. In your `node` folder, create a new javascript file called`index.js`.
37+
3. Run `npm init -y` to create a package.json file.
38+
4. Add `"type" : "module"` to your package.json file.
39+
5. Install secret.js:`npm i secretjs`
40+
41+
### Uploading the SNIP-20 Contract
42+
43+
In your index.js file, paste the following (be sure to replace the wallet seed phrase with your wallet seed phrase):
44+
45+
{% code overflow="wrap" %}
46+
```javascript
47+
import { Wallet, SecretNetworkClient, EncryptionUtilsImpl, fromUtf8, MsgExecuteContractResponse } from "secretjs";
48+
import * as fs from "fs";
49+
50+
const wallet = new Wallet(
51+
"your walltet seed phrase to go here"
52+
);
53+
54+
const txEncryptionSeed = EncryptionUtilsImpl.GenerateNewSeed();
55+
56+
const contract_wasm = fs.readFileSync("../contract.wasm.gz");
57+
58+
const codeId = 1072;
59+
const contractCodeHash = "26af567eadde095c909ca6ecf58806235877e5b7ec9bfe30f1057e005f548b17";
60+
const contractAddress = "secret1xez6pv463a0elalnj0z53w60fz6tgclv368dw0";
61+
62+
const secretjs = new SecretNetworkClient({
63+
chainId: "pulsar-3",
64+
url: "https://api.pulsar.scrttestnet.com",
65+
wallet: wallet,
66+
walletAddress: wallet.address,
67+
txEncryptionSeed: txEncryptionSeed
68+
});
69+
70+
let upload_contract = async () => {
71+
let tx = await secretjs.tx.compute.storeCode(
72+
{
73+
sender: wallet.address,
74+
wasm_byte_code: contract_wasm,
75+
source: "",
76+
builder: "",
77+
},
78+
{
79+
gasLimit: 4_000_000,
80+
}
81+
);
82+
83+
const codeId = Number(
84+
tx.arrayLog.find((log) => log.type === "message" && log.key === "code_id")
85+
.value
86+
);
87+
88+
console.log("codeId: ", codeId);
89+
// contract hash, useful for contract composition
90+
const contractCodeHash = (await secretjs.query.compute.codeHashByCodeId({code_id: codeId})).code_hash;
91+
console.log(`Contract hash: ${contractCodeHash}`);
92+
}
93+
94+
upload_contract();
95+
```
96+
{% endcode %}
97+
98+
Run `node index.js` in your terminal to execute the `upload_contract()` function. Upon successful execution, a codeId and contract hash will be returned:
99+
100+
```
101+
codeId: 1070
102+
Contract hash: 26af567eadde095c909ca6ecf58806235877e5b7ec9bfe30f1057e005f548b17
103+
```
104+
105+
### Instantiating the SNIP-20 Contract
106+
107+
In your index.js file, paste the following:
108+
109+
```javascript
110+
let instantiate_contract = async () => {
111+
const initMsg = {
112+
name: "Zebra",
113+
symbol: "ZBRA",
114+
decimals: 6,
115+
prng_seed: Buffer.from("Something really random").toString("base64"),
116+
admin: wallet.address,
117+
initial_balances: [
118+
{
119+
address: wallet.address,
120+
amount: "1000000000",
121+
},
122+
],
123+
};
124+
125+
let tx = await secretjs.tx.compute.instantiateContract(
126+
{
127+
code_id: codeId,
128+
sender: wallet.address,
129+
code_hash: contractCodeHash,
130+
init_msg: initMsg,
131+
label: " Snip-20 Example" + Math.ceil(Math.random() * 10000),
132+
},
133+
{
134+
gasLimit: 400_000,
135+
}
136+
);
137+
138+
//Find the contract_address in the logs
139+
const contractAddress = tx.arrayLog.find(
140+
(log) => log.type === "message" && log.key === "contract_address"
141+
).value;
142+
143+
console.log(contractAddress);
144+
};
145+
146+
instantiate_contract();
147+
```
148+
149+
The `initMsg` object in our `index.js` file is referencing the instantiation message defined in [msg.rs at line 20](https://github.com/scrtlabs/snip20-reference-impl/blob/81ad9714e50b890a50d8394dcac718950da127b6/src/msg.rs#L20). Notice that we chose to omit the optional `config` variable. If we include `config`, there is a variety of additional contract functionality that we could program, such as burn, mint, admin privileges, etc [as seen here](https://github.com/scrtlabs/snip20-reference-impl/blob/81ad9714e50b890a50d8394dcac718950da127b6/src/msg.rs#L42).
150+
151+
Now we are going to instantiate some ZBRA coin. If you want to create your own coin name, update the `name, symbol,` and `amount` fields respectively. Be sure to comment out `upload_contract()` and now run `node index.js` to call `instantiate_contract()`. Upon successful execution, a contract address will be returned:
152+
153+
```
154+
secret1xez6pv463a0elalnj0z53w60fz6tgclv368dw0
155+
```
156+
157+
### Query the Token Info
158+
159+
To check that the instantiation of our SNIP-20 ZEBRA token was successful, let's query the smart contract's token info:
160+
161+
```javascript
162+
let query_token_info = async () => {
163+
const tokenInfoQuery = await secretjs.query.compute.queryContract({
164+
contract_address: contractAddress,
165+
query: {
166+
token_info: {},
167+
},
168+
code_hash: contractCodeHash,
169+
});
170+
171+
console.log(tokenInfoQuery);
172+
};
173+
query_token_info();
174+
```
175+
176+
The following is returned upon successful query:
177+
178+
```
179+
token_info: { name: 'Zebra', symbol: 'ZBRA', decimals: 6, total_supply: null }
180+
}
181+
```
182+
183+
{% hint style="info" %}
184+
The reason `total supply` is `null` is because we chose to make `total supply` hidden in our instantiation message. If you want it to be public, then in the[ `InitConfig` variable](https://github.com/scrtlabs/snip20-reference-impl/blob/81ad9714e50b890a50d8394dcac718950da127b6/src/msg.rs#L45) set `public_total_supply` to true.
185+
{% endhint %}
186+
187+
### SNIP-20 Contract Messages
188+
189+
Now that we have successfully instantiated our SNIP-20 contract, let's send an [execution message](https://github.com/scrtlabs/snip20-reference-impl/blob/81ad9714e50b890a50d8394dcac718950da127b6/src/msg.rs#L91) to better understand the contract's functionality.
190+
191+
Start by adding the token to your Keplr wallet. Click on Keplr, select the hamburger icon, select "Add Token", and then paste in your token's contract address. If you need to fund your wallet to execute the transaction, you can do so using the [pulsar-3 faucet here](https://faucet.pulsar.scrttestnet.com/). You should now see your token in your Keplr wallet!
192+
193+
<figure><img src="../../../../.gitbook/assets/Screen Shot 2023-04-10 at 2.08.50 PM.png" alt=""><figcaption><p>keplr wallet with ZBRA token</p></figcaption></figure>
194+
195+
Let's [transfer some tokens](https://github.com/scrtlabs/snip20-reference-impl/blob/81ad9714e50b890a50d8394dcac718950da127b6/src/msg.rs#L107) to another wallet address. The transfer message is defined in msg.rs as follows:
196+
197+
```javascript
198+
Transfer {
199+
recipient: String,
200+
amount: Uint128,
201+
memo: Option<String>,
202+
decoys: Option<Vec<Addr>>,
203+
entropy: Option<Binary>,
204+
padding: Option<String>,
205+
}
206+
```
207+
208+
Now let's execute the transfer message with secret.js. Be sure to update the `recipient` wallet address with your own wallet before executing the code below. For testing purposes, I am using two Keplr wallet connected to the Secret Network testnet in order to move funds back and forth:
209+
210+
```javascript
211+
let transfer_snip20 = async (receiver_wallet) => {
212+
let executeMsg = {
213+
transfer: {
214+
owner: wallet.address,
215+
amount: "10000000",
216+
recipient: receiver_wallet,
217+
},
218+
};
219+
220+
let tx = await secretjs.tx.compute.executeContract(
221+
{
222+
sender: wallet.address,
223+
contract_address: contractAddress,
224+
code_hash: contractCodeHash,
225+
msg: executeMsg,
226+
},
227+
{
228+
gasLimit: 100_000,
229+
}
230+
);
231+
console.log(tx);
232+
};
233+
234+
transfer_snip20("secret1f9zykwvwc6jyhv6dtsjwx03e92j08nyffwuwcu");
235+
```
236+
237+
Congrats! You just successfully transferred your own SNIP-20 token on Secret Network! 🎉
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
description: >-
3+
Explanation of executing modules inside a CosmWasm contract using sending
4+
Native SCRT as an example.
5+
---
6+
7+
# Contract - module call
8+
9+
Sending Native SCRT from a contract is realtively trivial and can be done using the [`BankMsg::Send`](https://docs.rs/cosmwasm-std/latest/cosmwasm\_std/enum.BankMsg.html#variant.Send) message. \
10+
\
11+
This is a [contract-to-module](https://book.cosmwasm.com/basics/funds.html) call. Any native denoms can be send in this way (ex. native IBC tokens).
12+
13+
{% tabs %}
14+
{% tab title="Cosmwasm v1.0" %}
15+
```rust
16+
#[entry_point]
17+
pub fn execute(
18+
deps: DepsMut,
19+
env: Env,
20+
info: MessageInfo,
21+
msg: ExecuteMsg // this is a custom struct defined in your msg.rs
22+
) -> StdResult<Response> {
23+
// example: send 33 uscrt
24+
let coins_to_send: Vec<Coin> = vec![Coin {
25+
denom: "uscrt".to_string(),
26+
amount: Uint128::from(33u128),
27+
}];
28+
29+
let message = CosmosMsg::Bank(BankMsg::Send {
30+
// replace with recipient of your choice
31+
to_address: info.sender.clone().into_string(),
32+
amount: coins_to_send,
33+
});
34+
35+
let res = Response::new().add_message(message);
36+
Ok(res)
37+
}
38+
```
39+
{% endtab %}
40+
41+
{% tab title="Cosmwasm v0.10" %}
42+
```rust
43+
pub fn handle<S: Storage, A: Api, Q: Querier>(
44+
_deps: &mut Extern<S, A, Q>,
45+
env: Env,
46+
_msg: HandleMsg, // this is a custom struct defined in your msg.rs
47+
) -> StdResult<HandleResponse> {
48+
// example: send 33 uscrt
49+
let coins_to_send: Vec<Coin> = vec![Coin {
50+
denom: "uscrt".to_string(),
51+
amount: Uint128::from(33u128),
52+
}];
53+
54+
let res = HandleResponse {
55+
messages: vec![CosmosMsg::Bank(BankMsg::Send {
56+
from_address: env.contract.address,
57+
// replace with recipient of your choice
58+
to_address: env.message.sender,
59+
amount: coins_to_send,
60+
})],
61+
log: vec![],
62+
data: None,
63+
};
64+
65+
Ok(res)
66+
}
67+
```
68+
{% endtab %}
69+
{% endtabs %}
70+
71+
{% hint style="warning" %}
72+
**Having Trouble?** Always make sure your contract has enough funds to begin with!
73+
74+
You can send some coins to your contract like this:
75+
76+
```
77+
secretcli tx bank send <from-account> <contract-address> 1000uscrt
78+
```
79+
80+
You can always see decrypted error messages from the contract like so:
81+
82+
```
83+
secretcli q compute tx <tx_hash>
84+
```
85+
{% endhint %}
86+
87+
#### Transaction logs
88+
89+
You can see the spent coins as events when you query for the transaction:
90+
91+
```bash
92+
> tx_hash=$(secretcli tx compute execute <contract-address> '{}' --output json | jq '.txhash')
93+
> secretcli q tx $txhash
94+
# ...
95+
logs:
96+
- events:
97+
- attributes:
98+
- key: receiver
99+
value: secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03
100+
- key: amount
101+
value: 33uscrt
102+
type: coin_received
103+
- attributes:
104+
- key: spender
105+
value: secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg
106+
- key: amount
107+
value: 33uscrt
108+
type: coin_spent
109+
# ...
110+
```

0 commit comments

Comments
 (0)