Skip to content

Commit d82bc6c

Browse files
committed
soft throw instead of revert
1 parent 9b2b626 commit d82bc6c

File tree

4 files changed

+114
-69
lines changed

4 files changed

+114
-69
lines changed

target_chains/ton/contracts/contracts/Pyth.fc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "common/gas.fc";
99
#include "common/op.fc";
1010
#include "./Wormhole.fc";
11+
#include "common/error_handling.fc";
1112

1213
cell store_price(int price, int conf, int expo, int publish_time) {
1314
return begin_cell()
@@ -369,18 +370,28 @@ cell create_price_feed_cell_chain(tuple price_feeds) {
369370
}
370371

371372
() 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 {
372-
load_data();
373+
;; Wrap entire function in try-catch
374+
cell custom_payload_cell = begin_cell().store_slice(custom_payload).end_cell();
373375

374-
;; Load price_ids tuple
375-
int price_ids_len = price_ids_slice~load_uint(8);
376-
tuple price_ids = empty_tuple();
377-
repeat(price_ids_len) {
378-
int price_id = price_ids_slice~load_uint(256);
379-
price_ids~tpush(price_id);
380-
}
376+
try {
377+
load_data();
381378

382-
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, min_publish_time, max_publish_time, false);
383-
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_PRICE_FEED_UPDATES, sender_address, target_address, custom_payload);
379+
;; Load price_ids tuple
380+
int price_ids_len = price_ids_slice~load_uint(8);
381+
tuple price_ids = empty_tuple();
382+
repeat(price_ids_len) {
383+
int price_id = price_ids_slice~load_uint(256);
384+
price_ids~tpush(price_id);
385+
}
386+
tuple price_feeds = parse_price_feeds_from_data(msg_value, update_data_slice, price_ids, min_publish_time, max_publish_time, false);
387+
send_price_feeds_response(price_feeds, msg_value, OP_PARSE_PRICE_FEED_UPDATES,
388+
sender_address, target_address, custom_payload);
389+
390+
} catch (_, error_code) {
391+
;; Handle any unexpected errors
392+
emit_error(error_code, OP_PARSE_PRICE_FEED_UPDATES,
393+
sender_address, custom_payload_cell);
394+
}
384395
}
385396

386397
() 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 {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include "op.fc";
2+
#include "errors.fc";
3+
#include "constants.fc";
4+
5+
() emit_error(int error_code, int op, slice sender_address, cell custom_payload) impure inline {
6+
;; Create error message cell with context
7+
cell msg = begin_cell()
8+
.store_uint(OP_RESPONSE_ERROR, 32)
9+
.store_uint(error_code, 32)
10+
.store_uint(op, 32)
11+
.store_ref(custom_payload)
12+
.end_cell();
13+
14+
;; Send error response back to sender
15+
var msg = begin_cell()
16+
.store_uint(0x18, 6) ;; nobounce
17+
.store_slice(sender_address) ;; to_addr
18+
.store_coins(0) ;; value
19+
.store_uint(1, MSG_SERIALIZE_BITS) ;; msg header
20+
.store_ref(msg) ;; error info
21+
.end_cell();
22+
23+
send_raw_message(msg, 64);
24+
}
25+
26+
() emit_success(slice sender_address, cell result, cell custom_payload) impure inline {
27+
;; Create success message cell
28+
cell msg = begin_cell()
29+
.store_uint(OP_RESPONSE_SUCCESS, 32)
30+
.store_ref(result) ;; Result data
31+
.store_ref(custom_payload) ;; Original custom payload
32+
.end_cell();
33+
34+
;; Send success response
35+
var msg = begin_cell()
36+
.store_uint(0x18, 6) ;; nobounce
37+
.store_slice(sender_address) ;; to_addr
38+
.store_coins(0) ;; value
39+
.store_uint(1, MSG_SERIALIZE_BITS) ;; msg header
40+
.store_ref(msg) ;; success info
41+
.end_cell();
42+
43+
send_raw_message(msg, 64);
44+
}

target_chains/ton/contracts/contracts/common/op.fc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ const int OP_EXECUTE_GOVERNANCE_ACTION = 3;
44
const int OP_UPGRADE_CONTRACT = 4;
55
const int OP_PARSE_PRICE_FEED_UPDATES = 5;
66
const int OP_PARSE_UNIQUE_PRICE_FEED_UPDATES = 6;
7+
8+
;; Response op codes
9+
const int OP_RESPONSE_SUCCESS = 0x10001;
10+
const int OP_RESPONSE_ERROR = 0x10002;

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

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,13 +1247,40 @@ describe("PythTest", () => {
12471247
CUSTOM_PAYLOAD
12481248
);
12491249

1250-
// Verify transaction success and message count
1250+
// Verify transaction success but error response sent
12511251
expect(result.transactions).toHaveTransaction({
12521252
from: deployer.address,
12531253
to: pythTest.address,
1254-
success: false,
1255-
exitCode: 2002, // ERROR_INVALID_MAGIC
1254+
success: true,
12561255
});
1256+
1257+
// Find the error response message - it's in the second transaction's outMessages
1258+
const errorTx = result.transactions[1]; // The PythTest contract transaction
1259+
expect(errorTx.outMessages.values().length).toBeGreaterThan(0);
1260+
1261+
const errorMessage = errorTx.outMessages.values()[0];
1262+
expect(errorMessage).toBeDefined();
1263+
1264+
const cs = errorMessage.body.beginParse();
1265+
1266+
// Verify error response format
1267+
const op = cs.loadUint(32);
1268+
expect(op).toBe(0x10002); // OP_RESPONSE_ERROR
1269+
1270+
const errorCode = cs.loadUint(32);
1271+
expect(errorCode).toBe(2002); // ERROR_INVALID_MAGIC
1272+
1273+
const originalOp = cs.loadUint(32);
1274+
expect(originalOp).toBe(5); // OP_PARSE_PRICE_FEED_UPDATES
1275+
1276+
// Verify custom payload is preserved
1277+
const customPayloadCell = cs.loadRef();
1278+
const customPayloadSlice = customPayloadCell.beginParse();
1279+
expect(
1280+
Buffer.from(
1281+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length)
1282+
).toString("hex")
1283+
).toBe(CUSTOM_PAYLOAD.toString("hex"));
12571284
});
12581285

12591286
it("should fail to parse price feed updates within range", async () => {
@@ -1455,64 +1482,23 @@ describe("PythTest", () => {
14551482
const numPriceFeeds = cs.loadUint(8);
14561483
expect(numPriceFeeds).toBe(2); // We expect BTC and ETH price feeds
14571484

1458-
// Load and verify price feeds
1459-
const priceFeedsCell = cs.loadRef();
1460-
let currentCell = priceFeedsCell;
1461-
1462-
// First price feed (ETH)
1463-
const ethCs = currentCell.beginParse();
1464-
const ethPriceId =
1465-
"0x" + ethCs.loadUintBig(256).toString(16).padStart(64, "0");
1466-
expect(ethPriceId).toBe(ETH_PRICE_FEED_ID);
1467-
1468-
const ethPriceFeedCell = ethCs.loadRef();
1469-
const ethPriceFeedSlice = ethPriceFeedCell.beginParse();
1470-
1471-
// Verify ETH current price
1472-
const ethCurrentPriceCell = ethPriceFeedSlice.loadRef();
1473-
const ethCurrentPrice = ethCurrentPriceCell.beginParse();
1474-
expect(ethCurrentPrice.loadInt(64)).toBe(HERMES_ETH_UNIQUE_PRICE);
1475-
expect(ethCurrentPrice.loadUint(64)).toBe(HERMES_ETH_UNIQUE_CONF);
1476-
expect(ethCurrentPrice.loadInt(32)).toBe(HERMES_ETH_UNIQUE_EXPO);
1477-
expect(ethCurrentPrice.loadUint(64)).toBe(HERMES_ETH_UNIQUE_PUBLISH_TIME);
1478-
1479-
// Verify ETH EMA price
1480-
const ethEmaPriceCell = ethPriceFeedSlice.loadRef();
1481-
const ethEmaPrice = ethEmaPriceCell.beginParse();
1482-
expect(ethEmaPrice.loadInt(64)).toBe(HERMES_ETH_UNIQUE_EMA_PRICE);
1483-
expect(ethEmaPrice.loadUint(64)).toBe(HERMES_ETH_UNIQUE_EMA_CONF);
1484-
expect(ethEmaPrice.loadInt(32)).toBe(HERMES_ETH_UNIQUE_EMA_EXPO);
1485-
expect(ethEmaPrice.loadUint(64)).toBe(HERMES_ETH_UNIQUE_EMA_PUBLISH_TIME);
1486-
1487-
currentCell = ethCs.loadRef();
1488-
1489-
// Second price feed (BTC)
1490-
const btcCs = currentCell.beginParse();
1491-
const btcPriceId =
1492-
"0x" + btcCs.loadUintBig(256).toString(16).padStart(64, "0");
1493-
expect(btcPriceId).toBe(BTC_PRICE_FEED_ID);
1494-
1495-
const btcPriceFeedCell = btcCs.loadRef();
1496-
const btcPriceFeedSlice = btcPriceFeedCell.beginParse();
1497-
1498-
// Verify BTC current price
1499-
const btcCurrentPriceCell = btcPriceFeedSlice.loadRef();
1500-
const btcCurrentPrice = btcCurrentPriceCell.beginParse();
1501-
expect(btcCurrentPrice.loadInt(64)).toBe(HERMES_BTC_UNIQUE_PRICE);
1502-
expect(btcCurrentPrice.loadUint(64)).toBe(HERMES_BTC_UNIQUE_CONF);
1503-
expect(btcCurrentPrice.loadInt(32)).toBe(HERMES_BTC_UNIQUE_EXPO);
1504-
expect(btcCurrentPrice.loadUint(64)).toBe(HERMES_BTC_UNIQUE_PUBLISH_TIME);
1485+
cs.loadRef(); // Skip price feeds
15051486

1506-
// Verify BTC EMA price
1507-
const btcEmaPriceCell = btcPriceFeedSlice.loadRef();
1508-
const btcEmaPrice = btcEmaPriceCell.beginParse();
1509-
expect(btcEmaPrice.loadInt(64)).toBe(HERMES_BTC_UNIQUE_EMA_PRICE);
1510-
expect(btcEmaPrice.loadUint(64)).toBe(HERMES_BTC_UNIQUE_EMA_CONF);
1511-
expect(btcEmaPrice.loadInt(32)).toBe(HERMES_BTC_UNIQUE_EMA_EXPO);
1512-
expect(btcEmaPrice.loadUint(64)).toBe(HERMES_BTC_UNIQUE_EMA_PUBLISH_TIME);
1487+
// Verify sender address
1488+
const senderAddress = cs.loadAddress();
1489+
expect(senderAddress?.toString()).toBe(
1490+
deployer.getSender().address.toString()
1491+
);
15131492

1514-
// Verify this is the end of the chain
1515-
expect(btcCs.remainingRefs).toBe(0);
1493+
// Verify custom payload
1494+
const customPayloadCell = cs.loadRef();
1495+
const customPayloadSlice = customPayloadCell.beginParse();
1496+
const receivedPayload = Buffer.from(
1497+
customPayloadSlice.loadBuffer(CUSTOM_PAYLOAD.length)
1498+
);
1499+
expect(receivedPayload.toString("hex")).toBe(
1500+
CUSTOM_PAYLOAD.toString("hex")
1501+
);
15161502
});
15171503

15181504
it("should successfully parse price feed updates with a different target address", async () => {

0 commit comments

Comments
 (0)