Skip to content

Commit 36065ad

Browse files
authored
Merge pull request #27 from hyperweb-io/anmol/docs-first-contract
docs: writing your first contract with Hyperweb
2 parents 5519044 + d88f981 commit 36065ad

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed

docs/WRITING_FIRST_CONTRACT.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Writing Your First Contract
2+
3+
This guide walks you through creating a simple "Hello World" contract using Hyperweb. This contract will set an initial greeting message and provide a way to retrieve it.
4+
5+
## Prerequisites
6+
7+
Before starting, ensure you have:
8+
- Set up the Hyperweb development environment (refer to the main [README](../README.md)).
9+
- Basic understanding of TypeScript and object-oriented programming.
10+
11+
## Overview
12+
13+
Our "Hello World" contract will:
14+
15+
1. Set a greeting message when the contract is instantiated.
16+
2. Provide a method to retrieve the message.
17+
18+
## Step 1: Create Your Contract Directory
19+
20+
1. Navigate to the `src/` directory.
21+
2. Create a new folder named `hello-world`:
22+
23+
```bash
24+
mkdir src/hello-world
25+
```
26+
27+
3. Inside the `hello-world` folder, create a file named `index.ts`:
28+
29+
```bash
30+
touch src/hello-world/index.ts
31+
```
32+
33+
## Step 2: Implement the Hello World Contract
34+
35+
In `src/hello-world/index.ts`, define the contract as follows:
36+
37+
```ts
38+
export interface State {
39+
get(key: string): string;
40+
set(key: string, value: any): void;
41+
};
42+
43+
default export class HelloWorldContract {
44+
state: State;
45+
46+
constructor(state: State) {
47+
this.state = state;
48+
this.state.set('greet', "Hello, World!"); // Set initial greeting in constructor
49+
}
50+
51+
// Retrieve the greeting message
52+
greet(): string {
53+
return this.state.get('greet');
54+
}
55+
}
56+
```
57+
58+
### Explanation
59+
60+
- **Constructor**: Initializes the contract with the greeting message "Hello, World!".
61+
- **`greet`**: Returns the message stored in the state.
62+
63+
## Step 3: Add the Contract to the Build Script
64+
65+
To include your contract in the build process:
66+
67+
1. Open `scripts/build.ts`.
68+
2. Add an entry for the `hello-world` contract:
69+
70+
```ts
71+
const configs: BuildConfig[] = [
72+
// existing contracts
73+
{
74+
entryFile: 'src/hello-world',
75+
outFile: 'dist/contracts/helloWorld.js',
76+
externalPackages: []
77+
}
78+
];
79+
```
80+
81+
This configuration specifies the entry point and output file for the build process.
82+
83+
## Step 4: Build the Contract
84+
85+
Compile the contract:
86+
87+
```bash
88+
yarn build
89+
```
90+
91+
This will generate the bundled contract in `dist/contracts`, making it ready for deployment.
92+
93+
## Step 5: Write Tests for the Hello World Contract
94+
95+
Testing helps ensure the contract behaves as expected. In the `__tests__/` directory:
96+
97+
1. Create `helloWorld.test.ts`:
98+
99+
```bash
100+
touch __tests__/helloWorld.test.ts
101+
```
102+
103+
2. Write test cases for greeting retrieval:
104+
105+
```js
106+
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
107+
import { assertIsDeliverTxSuccess } from '@cosmjs/stargate';
108+
109+
import path from "path";
110+
import fs from 'fs';
111+
import { getSigningJsdClient, jsd } from 'hyperwebjs';
112+
import { useChain, generateMnemonic } from 'starshipjs';
113+
import { sleep } from '../test-utils/sleep';
114+
import './setup.test';
115+
116+
describe('Hello World Contract Tests', () => {
117+
let wallet, denom, address, queryClient, signingClient;
118+
let chainInfo, getCoin, getRpcEndpoint, creditFromFaucet;
119+
let contractCode, contractIndex;
120+
121+
let fee;
122+
123+
beforeAll(async () => {
124+
({
125+
chainInfo,
126+
getCoin,
127+
getRpcEndpoint,
128+
creditFromFaucet
129+
} = useChain('hyperweb'));
130+
denom = (await getCoin()).base;
131+
132+
// Initialize wallet
133+
wallet = await DirectSecp256k1HdWallet.fromMnemonic(generateMnemonic(), {
134+
prefix: chainInfo.chain.bech32_prefix
135+
});
136+
address = (await wallet.getAccounts())[0].address;
137+
console.log(`contract creator address: ${address}`);
138+
139+
// Create custom cosmos interchain client
140+
queryClient = await jsd.ClientFactory.createRPCQueryClient({
141+
rpcEndpoint: await getRpcEndpoint()
142+
});
143+
144+
signingClient = await getSigningJsdClient({
145+
rpcEndpoint: await getRpcEndpoint(),
146+
signer: wallet
147+
});
148+
149+
// Set default fee
150+
fee = { amount: [{ denom, amount: '100000' }], gas: '550000' };
151+
152+
await creditFromFaucet(address);
153+
await sleep(2000); // Wait for faucet transfer
154+
});
155+
156+
it('check balance', async () => {
157+
const balance = await signingClient.getBalance(address, denom);
158+
expect(balance.amount).toEqual("10000000000");
159+
expect(balance.denom).toEqual(denom);
160+
});
161+
162+
it('instantiate Hello World contract', async () => {
163+
// Read contract code from external file
164+
const contractPath = path.join(__dirname, '../dist/contracts/helloWorld.js');
165+
contractCode = fs.readFileSync(contractPath, 'utf8');
166+
167+
const msg = jsd.jsd.MessageComposer.fromPartial.instantiate({
168+
creator: address,
169+
code: contractCode,
170+
});
171+
172+
const result = await signingClient.signAndBroadcast(address, [msg], fee);
173+
assertIsDeliverTxSuccess(result);
174+
175+
// Parse response to get the contract index
176+
const response = jsd.jsd.MsgInstantiateResponse.fromProtoMsg(result.msgResponses[0]);
177+
contractIndex = response.index;
178+
expect(contractIndex).toBeGreaterThan(0);
179+
console.log(`contract index: ${contractIndex}`);
180+
});
181+
182+
it('query for initial greeting', async () => {
183+
const msg = jsd.jsd.MessageComposer.fromPartial.eval({
184+
creator: address,
185+
index: contractIndex,
186+
fnName: "greet",
187+
arg: "",
188+
});
189+
190+
const result = await signingClient.signAndBroadcast(address, [msg], fee);
191+
assertIsDeliverTxSuccess(result);
192+
193+
const response = jsd.jsd.MsgEvalResponse.fromProtoMsg(result.msgResponses[0]);
194+
expect(response.result).toEqual("Hello, World!");
195+
});
196+
});
197+
```
198+
199+
3. Run the tests:
200+
201+
```bash
202+
yarn test
203+
```
204+
205+
## Step 6: Deploy and Interact with the Contract
206+
207+
With the contract built and tested, you can now deploy it to the Hyperweb blockchain:
208+
209+
1. **Deploy**: Use Hyperweb’s deployment tools to deploy your contract.
210+
2. **Interact**: Call the `greet` method to retrieve the greeting message from the deployed contract.
211+
212+
## Summary
213+
214+
You've successfully created, built, tested, and deployed a simple "Hello World" contract using Hyperweb.
215+
This foundational contract will help as you move on to more complex contracts.
216+
For further information, refer to the Hyperweb documentation.

0 commit comments

Comments
 (0)