Skip to content

Commit 20ed3e0

Browse files
committed
packages/core: add tests and docs for subclassed contracts, add docs for instance contracts
1 parent c80c697 commit 20ed3e0

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

docs/ref/contract.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,37 @@ class Chat extends Contract<typeof Chat.models> {
2727
})
2828
}
2929
}
30+
```
31+
32+
A constructor is optional, but if provided, it should pass the topic to super(). Additionally, actions will only be generated for methods on the contract directly.
33+
34+
```ts
35+
class NamespacedChat extends Contract<typeof Chat.models> {
36+
createMessage(content: string) {
37+
super(content)
38+
}
39+
constructor(namespace: string) {
40+
super(namespace + ".chat.canvas.xyz")
41+
}
42+
}
43+
```
3044

45+
You can initialize a class contract by providing it to `Canvas.initialize`, or calling `initialize()` on it directly:
46+
47+
```ts
3148
const app = await Canvas.initialize({
3249
contract: Chat,
3350
topic: "example.xyz"
3451
})
52+
```
53+
54+
```ts
55+
const app = await NamespacedChat.initialize("mynamespace")
56+
```
3557

58+
Once initialized, methods on the contract are called via `this.actions`.
59+
60+
```ts
3661
app.actions.createMessage("I'm a scary and powerful fire demon!")
3762
```
3863

packages/core/test/contract.instance.test.ts

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ethers } from "ethers"
55
import { SIWESigner } from "@canvas-js/signer-ethereum"
66
import { Canvas, ModelSchema, Contract, GetActionsType } from "@canvas-js/core"
77

8-
test("inline contract initializes with instance topic", async (t) => {
8+
test("initialize contract with instance topic", async (t) => {
99
const wallet = ethers.Wallet.createRandom()
1010

1111
class Blog extends Contract<typeof Blog.models> {
@@ -32,7 +32,7 @@ test("inline contract initializes with instance topic", async (t) => {
3232
t.is(posts.length, 2)
3333
})
3434

35-
test("string contract initializes with instance topic", async (t) => {
35+
test("initialize string contract with instance topic", async (t) => {
3636
const wallet = ethers.Wallet.createRandom()
3737

3838
const contract = `import { Contract } from "@canvas-js/core/contract";
@@ -62,3 +62,78 @@ test("string contract initializes with instance topic", async (t) => {
6262
const posts = await app.db.query("posts")
6363
t.is(posts.length, 2)
6464
})
65+
66+
test("initialize subclassed contract with instance topic", async (t) => {
67+
const wallet = ethers.Wallet.createRandom()
68+
69+
class Blog extends Contract<typeof Blog.models> {
70+
static models = { posts: { id: "primary", creator: "string", content: "string" } } satisfies ModelSchema
71+
async createPostParent(content: string) {
72+
await this.db.create("posts", { id: this.id, creator: this.address, content })
73+
}
74+
}
75+
76+
class NamespacedBlog extends Blog {
77+
async createPostParent(content: string) {
78+
super.createPostParent(content)
79+
}
80+
async createPostChild(content: string) {
81+
await this.db.create("posts", { id: this.id, creator: this.address, content })
82+
}
83+
constructor(topic: string) {
84+
super(topic + ".test")
85+
}
86+
}
87+
88+
const app = await NamespacedBlog.initialize("example.xyz")
89+
app.updateSigners([new SIWESigner({ signer: wallet })])
90+
91+
t.teardown(() => app.stop())
92+
93+
t.is(app.topic, "example.xyz.test")
94+
95+
await app.actions.createPostParent("hello world")
96+
await app.actions.createPostChild("second post")
97+
98+
const posts = await app.db.query("posts")
99+
t.is(posts.length, 2)
100+
})
101+
102+
test("initialize subclassed string contract with instance topic", async (t) => {
103+
const wallet = ethers.Wallet.createRandom()
104+
105+
const contract = `import { Contract } from "@canvas-js/core/contract";
106+
107+
class Chat extends Contract {
108+
static models = { posts: { id: "primary", creator: "string", content: "string" } }
109+
async createPostParent(content) {
110+
await this.db.create("posts", { id: this.id, creator: this.address, content })
111+
}
112+
}
113+
export default class extends Chat {
114+
async createPostParent(content) {
115+
super.createPostParent(content)
116+
}
117+
async createPostChild(content) {
118+
await this.db.create("posts", { id: this.id, creator: this.address, content })
119+
}
120+
constructor(topic) {
121+
super(topic + ".test")
122+
}
123+
}`
124+
125+
const app = await Canvas.initialize({
126+
topic: "example.xyz",
127+
contract,
128+
})
129+
130+
t.teardown(() => app.stop())
131+
132+
t.is(app.topic, "example.xyz.test")
133+
134+
await app.actions.createPostParent("hello world")
135+
await app.actions.createPostChild("second post")
136+
137+
const posts = await app.db.query("posts")
138+
t.is(posts.length, 2)
139+
})

0 commit comments

Comments
 (0)