Skip to content

Commit 6d51e10

Browse files
Relayer: TON LogPoller initial version (#56)
* chore: init logpoller * feat: test contract * feat: scaffolding test env * feat: event parsing PoC * chore: clean up * feat: log parsing w/o magic field * feat: log poller service wip * feat: only saving logs * chore: cleaning up * chore: msg collector * chore: clean up * fix: skip already processed block * chore: lint & clean up * feat: CAL event query poc wip * chore: clean up * chore: clean up wip * fix: contract usage in tests wip * chore: test contract deployment * chore: lint wip * fix: only mvp interface * feat: testing with emitters * chore: test contract wip * chore: clean up * chore: debugging tolk * chore: cleaning up * chore: onInternalMessage not invoked wip * fix: revert test contract * feat: wip testing polling with block range * chore: clean up wip * chore: testing CTF with TVM 11 * chore: lint * chore: polishing main polling * fix: util name * chore: clean up & add todos * wip: edge block polling comparison * feat: logpoller smoke wip * fix: loader only load messages * fix: stop event emitter on target * chore: add todos * feat: cell query and comments * fix: added new sender * fix: filter need name * chore: flag * chore: lint * fix: clean up * chore: loader loop refactor * chore: clean up local test flag * fix: revert localton config * chore: clean up * feat: crc32 as event topic * chore: clean up * Squashed commit of the following: commit e216e65 Author: Jade Park <[email protected]> Date: Mon Jul 28 17:55:58 2025 +0100 chore: lint commit 287c4d0 Author: Jade Park <[email protected]> Date: Thu Jul 24 11:33:52 2025 -0400 feat: injected event parser commit 0e9c42a Author: Jade Park <[email protected]> Date: Wed Jul 23 09:50:54 2025 -0400 chore: ccip send event topic & lint commit f917df9 Author: Jade Park <[email protected]> Date: Fri Jul 18 16:08:08 2025 +0100 feat: tx context in msg, sort and limit * chore: tidy * chore: comment Co-authored-by: Copilot <[email protected]> * chore: comment Co-authored-by: Copilot <[email protected]> * fix: lint * fix: format * fix: use example counter for event ingestion * fix: interfaces, types and comments * feat: ExtOutLogBucket struct * fix: event parsers as test helpers * fix: no error swallow * fix: minor fixes, no interface for mocking * fix: helper clean up * fix: tests * chore: clean up * refactor: tlb-powered go binding * chore: lint --------- Co-authored-by: Copilot <[email protected]>
1 parent 5f669b2 commit 6d51e10

File tree

35 files changed

+2822
-92
lines changed

35 files changed

+2822
-92
lines changed

contracts/contracts/ccip/onramp.tolk

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import "@stdlib/lisp-lists"
1+
import "@stdlib/lisp-lists";
22
import "types.tolk";
33
import "../lib/access/ownable_2step.tolk";
44
import "../lib/upgrades/type_and_version.tolk";
55
import "../lib/utils.tolk";
66
import "@stdlib/tvm-dicts";
77

8-
// TODO: use crc32("CCIPMessageSent")
9-
const CCIP_MESSAGE_SENT_TOPIC: int = 0x99; // for easier indexing
8+
const CCIP_MESSAGE_SENT_TOPIC: int = 0xa45d293c; // crc32("CCIPMessageSent")
109

1110
struct CCIPMessageSent {
1211
destChainSelector: uint64; // NOTE: both these values are already part of message, is it even important to have?
Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,88 @@
1-
import "@stdlib/common.tolk";
2-
import "../../lib/upgrades/type_and_version.tolk";
3-
import "../../lib/utils.tolk";
4-
5-
/// Counter contract (Tolk example)
1+
import "@stdlib/common.tolk"
2+
import "../../lib/upgrades/type_and_version.tolk"
3+
import "../../lib/utils.tolk"
64

5+
/// Counter contract + event emission (Tolk example)
76
/// Message to set the counter value.
87
struct (0x00000004) SetCount {
9-
queryId: uint64; // Standard query_id field
10-
newCount: uint32; // Argument for the operation
8+
queryId: uint64 // Standard query_id field
9+
newCount: uint32 // Argument for the operation
1110
}
1211

13-
struct Storage {
14-
id: uint32;
15-
value: uint32;
12+
/// Message to increase the counter value.
13+
struct (0x10000005) IncreaseCount {
14+
queryId: uint64 // Standard query_id field
15+
}
16+
17+
/// Event Topics
18+
const COUNT_SET_TOPIC = 0x0766fed0 // crc32("CountSet")
19+
const COUNT_INCREASED_TOPIC = 0x1947b328 // crc32("CountIncreased")
20+
21+
/// Event emitted when the counter is set
22+
struct CountSet {
23+
id: uint32
24+
value: uint32
1625
}
1726

18-
type IncomingMessage = SetCount;
27+
/// Event emitted when the counter is increased
28+
struct CountIncreased {
29+
id: uint32
30+
value: uint32
31+
}
1932

20-
fun loadData() {
33+
struct Storage {
34+
id: uint32
35+
value: uint32
36+
}
37+
38+
fun Storage.load(): Storage {
2139
return Storage.fromCell(contract.getData());
2240
}
2341

24-
fun saveData(data: Storage) {
25-
contract.setData(data.toCell());
42+
fun Storage.store(self) {
43+
return contract.setData(self.toCell());
2644
}
2745

46+
type Msg = SetCount | IncreaseCount
47+
2848
fun onInternalMessage(in: InMessage) {
29-
val msg = lazy IncomingMessage.fromSlice(in.body); // 63 error code is thrown if the message opcode is unknown
49+
val msg = lazy Msg.fromSlice(in.body); // 63 error code is thrown if the message opcode is unknown
3050
match (msg) {
3151
SetCount => {
32-
/// Instructs the contract to step the counter.
33-
var storage = loadData();
34-
storage.value = msg.newCount;
35-
saveData(storage);
52+
/// Instructs the contract to set the counter.
53+
var st = lazy Storage.load();
54+
st.value = msg.newCount;
55+
st.store();
56+
emit<CountSet>(COUNT_SET_TOPIC, { id: st.id, value: st.value });
57+
}
58+
IncreaseCount => {
59+
/// Instructs the contract to increase the counter.
60+
var st = lazy Storage.load();
61+
st.value = st.value + 1;
62+
st.store();
63+
emit<CountIncreased>(COUNT_INCREASED_TOPIC, { id: st.id, value: st.value });
3664
}
3765
else => {
3866
// ignore empty messages, "wrong opcode" for others
39-
assert (in.body.isEmpty()) throw 0xFFFF
67+
assert (in.body.isEmpty()) throw 0xFFFF;
4068
}
4169
}
4270
}
4371

44-
/// Gets the current counter value.
45-
get fun value(): int {
46-
val storage = loadData();
47-
return storage.value;
48-
}
49-
5072
/// Gets the current id of the contract.
5173
get fun id(): int {
52-
val storage = loadData();
74+
val storage = Storage.load();
5375
return storage.id;
5476
}
5577

78+
/// Gets the current counter value.
79+
get fun value(): int {
80+
val storage = Storage.load();
81+
return storage.value;
82+
}
83+
5684
/// Gets the current type and version of the contract.
5785
get fun typeAndVersion(): (slice, slice) {
58-
return TypeAndVersion {
59-
typeStr: "com.chainlink.ton.examples.Counter",
60-
versionStr: "1.0.0",
61-
}.typeAndVersion();
86+
return TypeAndVersion { typeStr: "com.chainlink.ton.examples.Counter", versionStr: "1.0.0" }
87+
.typeAndVersion();
6288
}

contracts/tests/Counter.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('Counter', () => {
1313
beforeEach(async () => {
1414
blockchain = await Blockchain.create()
1515

16-
code = await compile('Counter')
16+
code = await compile('examples.counter')
1717

1818
counter = blockchain.openContract(Counter.createFromConfig({ id: 1337, value: 13 }, code))
1919

File renamed without changes.

contracts/wrappers/examples/Counter.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ export function counterConfigToCell(config: CounterConfig): Cell {
2121

2222
export const Opcodes = {
2323
OP_SET_COUNT: 0x00000004,
24+
OP_INCREASE_COUNT: 0x10000005,
25+
}
26+
27+
export const EventTopics = {
28+
COUNT_SET_TOPIC: 0x1947b328, // crc32("CountSet")
29+
COUNT_INCREASED_TOPIC: 0x1947b328, // crc32("CountIncreased")
2430
}
2531

2632
export class Counter implements Contract, TypeAndVersion {
@@ -71,6 +77,25 @@ export class Counter implements Contract, TypeAndVersion {
7177
})
7278
}
7379

80+
async sendIncreaseCount(
81+
provider: ContractProvider,
82+
via: Sender,
83+
opts: {
84+
value: bigint
85+
queryId?: number
86+
newCount: number
87+
},
88+
): Promise<void> {
89+
await provider.internal(via, {
90+
value: opts.value,
91+
sendMode: SendMode.PAY_GAS_SEPARATELY,
92+
body: beginCell()
93+
.storeUint(Opcodes.OP_SET_COUNT, 32)
94+
.storeUint(opts.queryId ?? 0, 64)
95+
.endCell(),
96+
})
97+
}
98+
7499
async getValue(provider: ContractProvider): Promise<number> {
75100
const result = await provider.get('value', [])
76101
return result.stack.readNumber()

integration-tests/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ require (
1010
github.com/smartcontractkit/chainlink-testing-framework/framework v0.10.4
1111
github.com/smartcontractkit/chainlink-ton v0.0.0
1212
github.com/stretchr/testify v1.10.0
13-
github.com/xssnick/tonutils-go v1.13.0
13+
github.com/xssnick/tonutils-go v1.14.0
1414
)
1515

1616
replace github.com/smartcontractkit/chainlink-ton => ../
1717

1818
require (
1919
dario.cat/mergo v1.0.1 // indirect
20+
filippo.io/edwards25519 v1.1.0 // indirect
2021
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
2122
github.com/Microsoft/go-winio v0.6.2 // indirect
2223
github.com/XSAM/otelsql v0.29.0 // indirect
@@ -105,7 +106,6 @@ require (
105106
github.com/morikuni/aec v1.0.0 // indirect
106107
github.com/mr-tron/base58 v1.2.0 // indirect
107108
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
108-
github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae // indirect
109109
github.com/oklog/run v1.0.0 // indirect
110110
github.com/opencontainers/go-digest v1.0.0 // indirect
111111
github.com/opencontainers/image-spec v1.1.1 // indirect

integration-tests/go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,6 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
322322
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
323323
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
324324
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
325-
github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae h1:7smdlrfdcZic4VfsGKD2ulWL804a4GVphr4s7WZxGiY=
326-
github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
327325
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
328326
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
329327
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -434,8 +432,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
434432
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
435433
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
436434
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
437-
github.com/xssnick/tonutils-go v1.13.0 h1:LV2JzB+CuuWaLQiYNolK+YI3NRQOpS0W+T+N+ctF6VQ=
438-
github.com/xssnick/tonutils-go v1.13.0/go.mod h1:EDe/9D/HZpAenbR+WPMQHICOF0BZWAe01TU5+Vpg08k=
435+
github.com/xssnick/tonutils-go v1.14.0 h1:9+WXLKleINMWTSBN/uRJuE3d2BRYtxDh55hCG5PYCBE=
436+
github.com/xssnick/tonutils-go v1.14.0/go.mod h1:68xwWjpoGGqiTbLJ0gT63sKu1Z1moCnDLLzA+DKanIg=
439437
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
440438
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
441439
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package counter
2+
3+
import (
4+
test_utils "integration-tests/utils"
5+
6+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/hash"
7+
)
8+
9+
// TODO: move to proper location
10+
var (
11+
ArtifactPath = test_utils.GetBuildDir("examples.counter.compiled.json")
12+
13+
SetCountOpCode uint32 = 0x10000004
14+
IncreaseCounterOpCode uint32 = 0x10000005
15+
16+
CountSetEventTopic uint32 = hash.CRC32("CountSet")
17+
CountIncreasedEventTopic uint32 = hash.CRC32("CountIncreased")
18+
)
19+
20+
// initial data structure
21+
type Storage struct {
22+
ID uint32 `tlb:"## 32"`
23+
Value uint32 `tlb:"## 32"`
24+
}
25+
26+
// incoming message bodies
27+
type SetCountMsg struct {
28+
OpCode uint32 `tlb:"## 32"`
29+
QueryID uint64 `tlb:"## 64"`
30+
Value uint32 `tlb:"## 32"`
31+
}
32+
33+
type IncreaseCountMsg struct {
34+
OpCode uint32 `tlb:"## 32"`
35+
QueryID uint64 `tlb:"## 64"`
36+
}
37+
38+
// events
39+
type CountSetEvent struct {
40+
ID uint32 `tlb:"## 32"`
41+
Value uint32 `tlb:"## 32"`
42+
}
43+
44+
type CountIncreasedEvent struct {
45+
ID uint32 `tlb:"## 32"`
46+
Value uint32 `tlb:"## 32"`
47+
}

0 commit comments

Comments
 (0)