@@ -8,17 +8,15 @@ import "../lib/utils.tolk";
88const STATE_UNTOUCHED: uint8 = 0;
99const STATE_TOKEN_TRANSFER: uint8 = 1;
1010const STATE_EXECUTE: uint8 = 2;
11- const STATE_SUCCESS: uint8 = 3;
12-
13- // Execution state stores CCIP specfic information
14- // These have to match the EVM states
15- const EXECUTION_STATE_UNTOUCHED: uint8 = 0;
16- const EXECUTION_STATE_IN_PROGRESS: uint8 = 1;
17- const EXECUTION_STATE_SUCCESS: uint8 = 2;
18- const EXECUTION_STATE_FAILURE: uint8 = 3;
11+ const STATE_EXECUTE_FAILED: uint8 = 3;
12+ const STATE_SUCCESS: uint8 = 4;
13+
1914// TODO: we need to fit additional states: TOKEN_TRANSFER | EXECUTE
2015
21- const ERROR_STATE_IS_NOT_UNTOUCHED: uint32 = 0x7878;
16+ const ERROR_STATE_IS_NOT_UNTOUCHED = 300;
17+ const ERROR_UPDATING_STATE_OF_NON_EXECUTED_MESSAGE = 301;
18+ const ERROR_NOTIFICATION_FROM_INVALID_RECEIVER = 303;
19+
2220
2321fun MerkleRoot_Storage.load(): MerkleRoot_Storage {
2422 return MerkleRoot_Storage.fromCell(contract.getData());
@@ -28,66 +26,126 @@ fun MerkleRoot_Storage.store(self) {
2826 return contract.setData(self.toCell());
2927}
3028
31-
32- type MerkleRoot_InMessage = MerkleRoot_Validate;
29+ type MerkleRoot_InMessage = MerkleRoot_Validate | MerkleRoot_CCIPReceiveBounced | MerkleRoot_CCIPReceiveConfirm;
3330
3431fun onInternalMessage(in: InMessage) {
3532 val msg = lazy MerkleRoot_InMessage.fromSlice(in.body);
3633 match (msg) {
3734 MerkleRoot_Validate => {
3835 // If we receive this message from the OffRamp then the merkle proof has already been validated.
3936 _validateAndExecute(msg, in.senderAddress);
40-
37+ }
38+ MerkleRoot_CCIPReceiveConfirm => {
39+ _ccipReceiveConfirm(msg, in.senderAddress);
40+ }
41+ MerkleRoot_CCIPReceiveBounced => {
42+ _ccipReceiveBounced(msg, in.senderAddress);
4143 }
4244 else => {
4345 // ignore empty messages, "wrong opcode" for others
4446 assert (in.body.isEmpty()) throw 0xFFFF
4547 }
4648 }
4749}
50+ fun _ccipReceiveBounced(msg: MerkleRoot_CCIPReceiveBounced, sender: address){
51+ var st = MerkleRoot_Storage.load();
52+
53+ assert(sender == st.owner, ERROR_NOT_OWNER);
54+ assert(st.state == STATE_EXECUTE && st.message != null, ERROR_UPDATING_STATE_OF_NON_EXECUTED_MESSAGE);
55+
56+ val ccipMessage = st.message!.load();
57+
58+ assert (msg.receiver == ccipMessage.receiver, ERROR_NOTIFICATION_FROM_INVALID_RECEIVER);
59+
60+ st.state = STATE_EXECUTE_FAILED;
61+ st.store();
62+
63+ val messageHeader = ccipMessage.header;
64+ val offRampNotifyFailure = createMessage({
65+ bounce: true,
66+ value: ton("0"),
67+ dest: st.owner,
68+ body: OffRamp_NotifyFailure {
69+ header: messageHeader,
70+ rootId: st.rootId,
71+ },
72+ });
73+ offRampNotifyFailure.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);
74+
75+ }
4876
49- //TODO: We are not keeping track of the execution state right now, we just relay the message to confirm that the merkle proof is valid
77+ fun _ccipReceiveConfirm(msg: MerkleRoot_CCIPReceiveConfirm, sender: address) {
78+ var st = MerkleRoot_Storage.load();
79+
80+ assert(st.state == STATE_EXECUTE && st.message != null, ERROR_UPDATING_STATE_OF_NON_EXECUTED_MESSAGE);
81+ assert(sender == st.owner, ERROR_NOT_OWNER);
82+
83+ val ccipMessage = st.message!.load();
84+
85+ assert (msg.receiver == ccipMessage.receiver, ERROR_NOTIFICATION_FROM_INVALID_RECEIVER);
86+
87+ st.state = STATE_SUCCESS;
88+ st.store();
89+
90+ val messageHeader = ccipMessage.header;
91+ val offRampNotifySuccess = createMessage({
92+ bounce: true,
93+ value: ton("0"),
94+ dest: st.owner,
95+ body: OffRamp_NotifySuccess {
96+ header: messageHeader,
97+ rootId: st.rootId
98+ },
99+ });
100+ offRampNotifySuccess.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);
101+ }
50102
51103fun _validateAndExecute(msg: MerkleRoot_Validate, sender: address) {
52- val st = MerkleRoot_Storage.load();
104+ var st = MerkleRoot_Storage.load();
105+
53106 assert(sender == st.owner, ERROR_NOT_OWNER);
107+ assert(st.state == STATE_UNTOUCHED, ERROR_STATE_IS_NOT_UNTOUCHED);
54108
55- assert(st.state == EXECUTION_STATE_UNTOUCHED, ERROR_STATE_IS_NOT_UNTOUCHED);
56- // TODO if no tokenTransfers
57- _execute(st, msg.messages, msg.proofs, msg.proofFlagBits, msg.metadataHash, sender);
58-
59- // if tokenTransfers
60- // validate execution state == untouched
61- // if initial
62- // allocate storage space for the execution report
63- // TODO: should we fan out CommitReport into individual executions?
64- //
65- // if in progress
109+ val ccipMessage = msg.message;
110+
111+ st.message = ccipMessage.toCell();
112+ st.store();
113+
114+ //TODO
66115 // if tokenAmounts > 0 && state == initial
116+ // val notifyInProgress = createMessage({
117+ // bounce: true,
118+ // value: ton("0.05"),
119+ // dest: st.owner,
120+ // body: OffRamp_NotifyInProgress {
121+ // st.messages, msg.proofs, msg.proofFlagBits, msg.metadataHash
122+ // }
123+ // });
124+ // notifyInProgress.send(SEND_MODE_REGULAR);
67125 // set state = token transfer
68126 // send message to offramp to ask to release tokens
127+
69128 // else if no tokenTransfers
70- // set state = execution
129+ _execute(st, ccipMessage);
71130}
72131
73- fun _execute(st: MerkleRoot_Storage, mesages: cell, proofs: cell, proofFlagBits: uint256, metadataHash: uint256, offRamp: address ) {
74- st.state = STATE_SUCCESS ;
132+ fun _execute(st: MerkleRoot_Storage, mesage: Any2TVMRampMessage ) {
133+ st.state = STATE_EXECUTE ;
75134 st.store();
76135 createMessage(
77136 {
78137 bounce: true,
79- value: ton("0"),
80- dest: offRamp ,
138+ value: ton("0.05 "),
139+ dest: st.owner ,
81140 body: OffRamp_DispatchValidated {
82- messages: mesages,
83- proofs: proofs,
84- proofFlagBits: proofFlagBits,
85- metadataHash: metadataHash
141+ message: mesage.toCell(),
142+ rootId: st.rootId,
86143 }
87144 }
88- ).send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE );
145+ ).send(SEND_MODE_REGULAR );
89146}
90147
148+
91149// TODO: should we wait for all transfers to either complete or fail before we allow retry?
92150
93151// fun onExcesses() {
0 commit comments