Skip to content

Commit 574a872

Browse files
committed
add target address and custom payload
1 parent 0349da4 commit 574a872

File tree

7 files changed

+107
-52
lines changed

7 files changed

+107
-52
lines changed

target_chains/ton/contracts/contracts/Main.fc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,19 @@
3535
slice price_ids_slice = price_ids_cell.begin_parse();
3636
int min_publish_time = in_msg_body~load_uint(64);
3737
int max_publish_time = in_msg_body~load_uint(64);
38-
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address);
38+
slice target_address = in_msg_body~load_msg_addr();
39+
cell custom_payload_cell = in_msg_body~load_ref();
40+
slice custom_payload = custom_payload_cell.begin_parse();
41+
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address, target_address, custom_payload);
3942
} elseif (op == OP_PARSE_UNIQUE_PRICE_FEED_UPDATES) {
4043
cell price_ids_cell = in_msg_body~load_ref();
4144
slice price_ids_slice = price_ids_cell.begin_parse();
4245
int publish_time = in_msg_body~load_uint(64);
4346
int max_staleness = in_msg_body~load_uint(64);
44-
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address);
47+
slice target_address = in_msg_body~load_msg_addr();
48+
cell custom_payload_cell = in_msg_body~load_ref();
49+
slice custom_payload = custom_payload_cell.begin_parse();
50+
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address, target_address, custom_payload);
4551
} else {
4652
throw(0xffff); ;; Throw exception for unknown op
4753
}

target_chains/ton/contracts/contracts/Pyth.fc

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -328,60 +328,39 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
328328
return result;
329329
}
330330

331-
() send_price_feeds_response(tuple price_feeds, int msg_value, int op, slice sender_address) impure {
331+
() send_price_feeds_response(tuple price_feeds, int msg_value, int op, slice sender_address, slice target_address, slice custom_payload) impure {
332332
;; Build response cell with price feeds
333333
builder response = begin_cell()
334334
.store_uint(op, 32) ;; Response op
335335
.store_uint(price_feeds.tlen(), 8); ;; Number of price feeds
336336

337337
;; Create and store price feed cell chain
338338
cell price_feeds_cell = create_price_feed_cell_chain(price_feeds);
339-
response = response.store_ref(price_feeds_cell);
340-
341-
;; Build the complete message cell (https://docs.ton.org/v3/documentation/smart-contracts/message-management/sending-messages#message-layout)
342-
cell msg = begin_cell()
343-
.store_uint(0x18, 6)
344-
.store_slice(sender_address)
345-
.store_coins(0) ;; Will fill in actual amount after fee calculations
346-
.store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
347-
.store_ref(response.end_cell())
348-
.end_cell();
339+
cell custom_payload_cell = begin_cell().store_slice(custom_payload).end_cell();
340+
response = response.store_ref(price_feeds_cell).store_slice(sender_address).store_ref(custom_payload_cell);
349341

350342
int num_price_feeds = price_feeds.tlen();
351343

352-
;; Number of cells in the message
353-
;; - 2 cells: msg + response
354-
int cells = 2 + num_price_feeds;
355-
356-
;; Bit layout per TL-B spec (https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb):
357-
;; - 6 bits: optimized way of serializing the tag and the first 4 fields
358-
;; - 256 bits: owner address
359-
;; - 128 bits: coins (VarUInteger 16) from grams$_ amount:(VarUInteger 16) = Grams
360-
;; - 107 bits: MSG_SERIALIZE_BITS
361-
;; - PRICE_FEED_BITS * num_price_feeds: space for each price feed
362-
int bits = 6 + 256 + 128 + MSG_SERIALIZE_BITS + (PRICE_FEED_BITS * num_price_feeds);
363-
int fwd_fee = get_forward_fee(cells, bits, WORKCHAIN);
364-
365344
;; Calculate all fees
366345
int compute_fee = get_compute_fee(WORKCHAIN, get_gas_consumed());
367346
int update_fee = single_update_fee * price_feeds.tlen();
368347

369348
;; Calculate total fees and remaining excess
370-
int total_fees = compute_fee + update_fee + fwd_fee;
349+
int total_fees = compute_fee + update_fee;
371350
int excess = msg_value - total_fees;
372351

373-
;; Send response message back to sender with exact excess amount
374352
send_raw_message(begin_cell()
375353
.store_uint(0x18, 6)
376-
.store_slice(sender_address)
354+
.store_slice(target_address)
377355
.store_coins(excess)
378356
.store_uint(1, MSG_SERIALIZE_BITS)
379357
.store_ref(response.end_cell())
358+
380359
.end_cell(),
381360
0);
382361
}
383362

384-
() parse_price_feed_updates(int msg_value, slice update_data_slice, slice price_ids_slice, int min_publish_time, int max_publish_time, slice sender_address) impure {
363+
() parse_price_feed_updates(int msg_value, slice update_data_slice, slice price_ids_slice, int min_publish_time, int max_publish_time, slice sender_address, slice target_address, slice custom_payload) impure {
385364
load_data();
386365

387366
;; Load price_ids tuple
@@ -393,10 +372,10 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
393372
}
394373

395374
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, min_publish_time, max_publish_time, false);
396-
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_PRICE_FEED_UPDATES, sender_address);
375+
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_PRICE_FEED_UPDATES, sender_address, target_address, custom_payload);
397376
}
398377

399-
() parse_unique_price_feed_updates(int msg_value, slice update_data_slice, slice price_ids_slice, int publish_time, int max_staleness, slice sender_address) impure {
378+
() parse_unique_price_feed_updates(int msg_value, slice update_data_slice, slice price_ids_slice, int publish_time, int max_staleness, slice sender_address, slice target_address, slice custom_payload) impure {
400379
load_data();
401380

402381
;; Load price_ids tuple
@@ -408,7 +387,7 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
408387
}
409388

410389
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, publish_time, publish_time + max_staleness, true);
411-
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_UNIQUE_PRICE_FEED_UPDATES, sender_address);
390+
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_UNIQUE_PRICE_FEED_UPDATES, sender_address, target_address, custom_payload);
412391
}
413392

414393
() update_price_feeds(int msg_value, slice data) impure {

target_chains/ton/contracts/contracts/common/gas.fc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
int get_compute_fee(int workchain, int gas_used) asm(gas_used workchain) "GETGASFEE";
22
int get_gas_consumed() asm "GASCONSUMED";
3-
int get_forward_fee(int cells, int bits, int workchain) asm(cells bits workchain) "GETFORWARDFEE";
43

54

65
;; 1 update: 262,567 gas

target_chains/ton/contracts/contracts/tests/PythTest.fc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,19 @@
4040
slice price_ids_slice = price_ids_cell.begin_parse();
4141
int min_publish_time = in_msg_body~load_uint(64);
4242
int max_publish_time = in_msg_body~load_uint(64);
43-
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address);
43+
slice target_address = in_msg_body~load_msg_addr();
44+
cell custom_payload_cell = in_msg_body~load_ref();
45+
slice custom_payload = custom_payload_cell.begin_parse();
46+
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address, target_address, custom_payload);
4447
} elseif (op == OP_PARSE_UNIQUE_PRICE_FEED_UPDATES) {
4548
cell price_ids_cell = in_msg_body~load_ref();
4649
slice price_ids_slice = price_ids_cell.begin_parse();
4750
int publish_time = in_msg_body~load_uint(64);
4851
int max_staleness = in_msg_body~load_uint(64);
49-
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address);
52+
slice target_address = in_msg_body~load_msg_addr();
53+
cell custom_payload_cell = in_msg_body~load_ref();
54+
slice custom_payload = custom_payload_cell.begin_parse();
55+
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address, target_address, custom_payload);
5056
} else {
5157
throw(0xffff); ;; Throw exception for unknown op
5258
}

target_chains/ton/contracts/contracts/tests/PythTestUpgraded.fc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,19 @@
3434
slice price_ids_slice = price_ids_cell.begin_parse();
3535
int min_publish_time = in_msg_body~load_uint(64);
3636
int max_publish_time = in_msg_body~load_uint(64);
37-
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address);
37+
slice target_address = in_msg_body~load_msg_addr();
38+
cell custom_payload_cell = in_msg_body~load_ref();
39+
slice custom_payload = custom_payload_cell.begin_parse();
40+
parse_price_feed_updates(msg_value, data_slice, price_ids_slice, min_publish_time, max_publish_time, sender_address, target_address, custom_payload);
3841
} elseif (op == OP_PARSE_UNIQUE_PRICE_FEED_UPDATES) {
3942
cell price_ids_cell = in_msg_body~load_ref();
4043
slice price_ids_slice = price_ids_cell.begin_parse();
4144
int publish_time = in_msg_body~load_uint(64);
4245
int max_staleness = in_msg_body~load_uint(64);
43-
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address);
46+
slice target_address = in_msg_body~load_msg_addr();
47+
cell custom_payload_cell = in_msg_body~load_ref();
48+
slice custom_payload = custom_payload_cell.begin_parse();
49+
parse_unique_price_feed_updates(msg_value, data_slice, price_ids_slice, publish_time, max_staleness, sender_address, target_address, custom_payload);
4450
} else {
4551
throw(0xffff); ;; Throw exception for unknown op
4652
}

target_chains/ton/contracts/tests/PythTest.spec.ts

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
2-
import { Cell, CommonMessageInfoInternal, Message, toNano } from "@ton/core";
2+
import { Cell, CommonMessageInfoInternal, toNano } from "@ton/core";
33
import "@ton/test-utils";
44
import { compile } from "@ton/blueprint";
55
import { HexString, Price } from "@pythnetwork/price-service-sdk";
@@ -95,6 +95,7 @@ const TEST_GOVERNANCE_DATA_SOURCES: DataSource[] = [
9595
"0000000000000000000000000000000000000000000000000000000000000000",
9696
},
9797
];
98+
const CUSTOM_PAYLOAD = Buffer.from("1234567890abcdef", "hex");
9899

99100
describe("PythTest", () => {
100101
let code: Cell;
@@ -1000,7 +1001,9 @@ describe("PythTest", () => {
10001001
sentValue,
10011002
[BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
10021003
HERMES_BTC_PUBLISH_TIME,
1003-
HERMES_BTC_PUBLISH_TIME
1004+
HERMES_BTC_PUBLISH_TIME,
1005+
deployer.address,
1006+
CUSTOM_PAYLOAD
10041007
);
10051008

10061009
// Verify transaction success and message count
@@ -1088,6 +1091,20 @@ describe("PythTest", () => {
10881091

10891092
// Verify this is the end of the chain
10901093
expect(ethCs.remainingRefs).toBe(0);
1094+
1095+
// Verify sender address
1096+
const senderAddress = cs.loadAddress();
1097+
expect(senderAddress?.toString()).toBe(deployer.address.toString());
1098+
1099+
// Verify custom payload
1100+
const customPayloadCell = cs.loadRef();
1101+
const customPayloadSlice = customPayloadCell.beginParse();
1102+
const receivedPayload = Buffer.from(
1103+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length)
1104+
);
1105+
expect(receivedPayload.toString("hex")).toBe(
1106+
CUSTOM_PAYLOAD.toString("hex")
1107+
);
10911108
});
10921109

10931110
it("should successfully parse unique price feed updates", async () => {
@@ -1101,7 +1118,9 @@ describe("PythTest", () => {
11011118
sentValue,
11021119
[BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
11031120
HERMES_BTC_PUBLISH_TIME,
1104-
60
1121+
60,
1122+
deployer.address,
1123+
CUSTOM_PAYLOAD
11051124
);
11061125

11071126
// Verify transaction success and message count
@@ -1189,6 +1208,20 @@ describe("PythTest", () => {
11891208

11901209
// Verify this is the end of the chain
11911210
expect(ethCs.remainingRefs).toBe(0);
1211+
1212+
// Verify sender address
1213+
const senderAddress = cs.loadAddress();
1214+
expect(senderAddress?.toString()).toBe(deployer.address.toString());
1215+
1216+
// Verify custom payload
1217+
const customPayloadCell = cs.loadRef();
1218+
const customPayloadSlice = customPayloadCell.beginParse();
1219+
const receivedPayload = Buffer.from(
1220+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length)
1221+
);
1222+
expect(receivedPayload.toString("hex")).toBe(
1223+
CUSTOM_PAYLOAD.toString("hex")
1224+
);
11921225
});
11931226

11941227
it("should fail to parse invalid price feed updates", async () => {
@@ -1203,7 +1236,9 @@ describe("PythTest", () => {
12031236
toNano("1"),
12041237
[BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
12051238
HERMES_BTC_PUBLISH_TIME,
1206-
HERMES_BTC_PUBLISH_TIME
1239+
HERMES_BTC_PUBLISH_TIME,
1240+
deployer.address,
1241+
CUSTOM_PAYLOAD
12071242
);
12081243

12091244
// Verify transaction success and message count
@@ -1226,7 +1261,9 @@ describe("PythTest", () => {
12261261
sentValue,
12271262
[BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
12281263
HERMES_BTC_PUBLISH_TIME + 1,
1229-
HERMES_BTC_PUBLISH_TIME + 1
1264+
HERMES_BTC_PUBLISH_TIME + 1,
1265+
deployer.address,
1266+
CUSTOM_PAYLOAD
12301267
);
12311268

12321269
// Verify transaction success and message count
@@ -1249,7 +1286,9 @@ describe("PythTest", () => {
12491286
sentValue,
12501287
[BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID],
12511288
HERMES_BTC_PUBLISH_TIME,
1252-
60
1289+
60,
1290+
deployer.address,
1291+
CUSTOM_PAYLOAD
12531292
);
12541293

12551294
// Verify transaction success and message count
@@ -1272,7 +1311,9 @@ describe("PythTest", () => {
12721311
sentValue,
12731312
[ETH_PRICE_FEED_ID, BTC_PRICE_FEED_ID],
12741313
HERMES_BTC_PUBLISH_TIME,
1275-
HERMES_BTC_PUBLISH_TIME
1314+
HERMES_BTC_PUBLISH_TIME,
1315+
deployer.address,
1316+
CUSTOM_PAYLOAD
12761317
);
12771318

12781319
// Verify transaction success and message count
@@ -1291,6 +1332,10 @@ describe("PythTest", () => {
12911332
(outMessage.info as CommonMessageInfoInternal).value.coins
12921333
).toBeGreaterThan(0);
12931334

1335+
expect((outMessage.info as CommonMessageInfoInternal).dest.toString()).toBe(
1336+
deployer.address.toString()
1337+
);
1338+
12941339
const cs = outMessage.body.beginParse();
12951340

12961341
// Verify message header
@@ -1373,7 +1418,9 @@ describe("PythTest", () => {
13731418
sentValue,
13741419
[ETH_PRICE_FEED_ID, BTC_PRICE_FEED_ID],
13751420
HERMES_BTC_PUBLISH_TIME,
1376-
60
1421+
60,
1422+
deployer.address,
1423+
CUSTOM_PAYLOAD
13771424
);
13781425

13791426
// Verify transaction success and message count

target_chains/ton/contracts/wrappers/PythTest.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import {
33
Cell,
44
contractAddress,
55
ContractProvider,
6-
parseTuple,
76
Sender,
87
SendMode,
98
toNano,
9+
Address,
1010
} from "@ton/core";
1111
import { BaseWrapper } from "./BaseWrapper";
1212
import { HexString, Price } from "@pythnetwork/price-service-sdk";
@@ -202,7 +202,9 @@ export class PythTest extends BaseWrapper {
202202
updateData: Buffer,
203203
priceIds: HexString[],
204204
time1: number,
205-
time2: number
205+
time2: number,
206+
targetAddress: Address,
207+
customPayload: Buffer
206208
): Cell {
207209
// Create a buffer for price IDs: 1 byte length + (32 bytes per ID)
208210
const priceIdsBuffer = Buffer.alloc(1 + priceIds.length * 32);
@@ -221,6 +223,8 @@ export class PythTest extends BaseWrapper {
221223
.storeRef(createCellChain(priceIdsBuffer))
222224
.storeUint(time1, 64)
223225
.storeUint(time2, 64)
226+
.storeAddress(targetAddress)
227+
.storeRef(createCellChain(customPayload))
224228
.endCell();
225229
}
226230

@@ -231,14 +235,18 @@ export class PythTest extends BaseWrapper {
231235
updateFee: bigint,
232236
priceIds: HexString[],
233237
minPublishTime: number,
234-
maxPublishTime: number
238+
maxPublishTime: number,
239+
targetAddress: Address,
240+
customPayload: Buffer
235241
) {
236242
const messageCell = this.createPriceFeedMessage(
237243
5, // OP_PARSE_PRICE_FEED_UPDATES
238244
updateData,
239245
priceIds,
240246
minPublishTime,
241-
maxPublishTime
247+
maxPublishTime,
248+
targetAddress,
249+
customPayload
242250
);
243251

244252
await provider.internal(via, {
@@ -255,14 +263,18 @@ export class PythTest extends BaseWrapper {
255263
updateFee: bigint,
256264
priceIds: HexString[],
257265
publishTime: number,
258-
maxStaleness: number
266+
maxStaleness: number,
267+
targetAddress: Address,
268+
customPayload: Buffer
259269
) {
260270
const messageCell = this.createPriceFeedMessage(
261271
6, // OP_PARSE_UNIQUE_PRICE_FEED_UPDATES
262272
updateData,
263273
priceIds,
264274
publishTime,
265-
maxStaleness
275+
maxStaleness,
276+
targetAddress,
277+
customPayload
266278
);
267279

268280
await provider.internal(via, {

0 commit comments

Comments
 (0)