Skip to content

Commit 3540daa

Browse files
[NONEVM-3031/3032]Migrate SenderExecutor to Deployable and update (#343)
* feat: Update send executor for onramp * feat: bindings * feat: code getter * feat: migrate SendExecutor deployable * ref: deployable cleanup * ref: rename executor.messageID for id * doc: new deployable message * fix: go bindings * fix: go type * fix: operations * fix: deploy CCIP * ref: rename IDs * fix: naming suggestions
1 parent d9e3a11 commit 3540daa

File tree

17 files changed

+267
-117
lines changed

17 files changed

+267
-117
lines changed

contracts/contracts/ccip/ccipsend_executor/contract.tolk

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fun onInternalMessage(in: InMessage) {
1818
match (msg) {
1919
CCIPSendExecutor_Execute => {
2020
var this = init(msg.onrampSend, msg.config.load());
21-
assert (in.senderAddress == this.addresses.load().onramp) throw CCIPSendExecutor_Error.Unauthorized;
21+
assert (in.senderAddress == contract.getAddress()) throw CCIPSendExecutor_Error.Unauthorized;
2222
assert (in.valueCoins >= SendExecutor_Costs.Execute()) throw CCIPSendExecutor_Error.InsufficientFee;
2323
this.onExecute();
2424
}
@@ -49,7 +49,7 @@ fun onBouncedMessage(in: InMessageBounced) {
4949
fun init(onrampSend: OnRamp_Send, config: CCIPSendExecutor_Config): CCIPSendExecutor<CCIPSendExecutor_State_Initialized> {
5050
val st = lazy CCIPSendExecutor_InitialData.fromCell(contract.getData());
5151
return CCIPSendExecutor<CCIPSendExecutor_State_Initialized> {
52-
messageID: st.messageID,
52+
id: st.id,
5353
onrampSend: onrampSend,
5454
addresses: CCIPSendExecutor_Addresses {
5555
onramp: st.onramp,
@@ -63,7 +63,7 @@ fun init(onrampSend: OnRamp_Send, config: CCIPSendExecutor_Config): CCIPSendExec
6363
fun CCIPSendExecutor<CCIPSendExecutor_State_Initialized>.onExecute(mutate self) {
6464
getValidatedFee(self.addresses.load().feeQuoter, self.onrampSend);
6565
val newState = CCIPSendExecutor<CCIPSendExecutor_State_OnGoingFeeValidation> {
66-
messageID: self.messageID,
66+
id: self.id,
6767
onrampSend: self.onrampSend,
6868
addresses: self.addresses,
6969
state: CCIPSendExecutor_State_OnGoingFeeValidation {
@@ -105,7 +105,7 @@ fun CCIPSendExecutor<T>.exitSuccessfully(self, fee: coins) {
105105
dest: self.addresses.load().onramp,
106106
body: OnRamp_ExecutorFinishedSuccessfully {
107107
fee,
108-
msgID: self.messageID,
108+
executorID: self.id,
109109
msg: self.onrampSend.msg,
110110
metadata: self.onrampSend.metadata,
111111
}
@@ -126,7 +126,7 @@ fun CCIPSendExecutor<T>.exitWithError(self, error: uint256, sender: address) {
126126
value: 0,
127127
dest: self.addresses.load().onramp,
128128
body: OnRamp_ExecutorFinishedWithError {
129-
msgID: self.messageID,
129+
executorID: self.id,
130130
error: error,
131131
msg: self.onrampSend.msg,
132132
metadata: self.onrampSend.metadata,

contracts/contracts/ccip/ccipsend_executor/storage.tolk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import "types"
33
import "../onramp/messages"
44

55
struct CCIPSendExecutor<T> {
6-
messageID: uint224,
6+
id: CCIPSendExecutor_ID,
77
onrampSend: OnRamp_Send,
88
addresses: Cell<CCIPSendExecutor_Addresses>,
99
state: Cell<T>,
@@ -13,7 +13,7 @@ fun CCIPSendExecutor<T>.load(): CCIPSendExecutor<T> {
1313
val st = lazy CCIPSendExecutor_Data.fromCell(contract.getData());
1414
assert (st.state is Cell<T>) throw CCIPSendExecutor_Error.StateNotExpected; // invalid state
1515
return CCIPSendExecutor<T> {
16-
messageID: st.messageId,
16+
id: st.id,
1717
onrampSend: st.onrampSend,
1818
addresses: st.addresses,
1919
state: st.state,
@@ -22,7 +22,7 @@ fun CCIPSendExecutor<T>.load(): CCIPSendExecutor<T> {
2222

2323
fun CCIPSendExecutor<T>.store(self) {
2424
contract.setData(CCIPSendExecutor_Data {
25-
messageId: 0,
25+
id: self.id,
2626
onrampSend: self.onrampSend,
2727
addresses: self.addresses,
2828
state: self.state,

contracts/contracts/ccip/ccipsend_executor/types.tolk

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
import "../onramp/messages.tolk";
2+
import "../../deployable/types"
3+
4+
type CCIPSendExecutor_ID = uint224
5+
6+
fun CCIPSendExecutor_DeployableData(owner: address, id: CCIPSendExecutor_ID): cell {
7+
return Deployable<_CCIPSendExecutor_DeployableData> {
8+
owner,
9+
id: _CCIPSendExecutor_DeployableData {
10+
id: id,
11+
contractType: stringCrc32("CCIPSendExecutor"),
12+
},
13+
}.toCell();
14+
}
15+
16+
struct _CCIPSendExecutor_DeployableData {
17+
id: CCIPSendExecutor_ID;
18+
contractType: uint256;
19+
}
220

321
struct CCIPSendExecutor_InitialData {
422
onramp: address,
5-
messageID: uint224,
23+
id: CCIPSendExecutor_ID,
624
}
725

826
struct CCIPSendExecutor_Data {
9-
messageId: uint224,
27+
id: CCIPSendExecutor_ID,
1028
onrampSend: OnRamp_Send,
1129
addresses: Cell<CCIPSendExecutor_Addresses>,
1230
state: CCIPSendExecutor_State,

contracts/contracts/ccip/onramp/contract.tolk

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import "../router/messages"
1717
import "../../lib/funding/withdrawable"
1818
import "../../lib/versioning/upgradeable"
1919
import "events"
20+
import "../../deployable/types"
2021
import "../fee_quoter/messages"
2122

2223
const CONTRACT_VERSION = "0.0.9";
@@ -66,6 +67,12 @@ fun onInternalMessage(in: InMessage) {
6667
applyAllowlistUpdates(mutate st, msg.updates);
6768
st.store();
6869
}
70+
OnRamp_UpdateSendExecutor => {
71+
var st = lazy OnRamp_Storage.load();
72+
st.ownable.requireOwner(in.senderAddress);
73+
st.executor.executorCode = msg.code;
74+
st.store();
75+
}
6976
Withdrawable_Withdraw => {
7077
var st = lazy OnRamp_Storage.load();
7178
st.ownable.requireOwner(in.senderAddress);
@@ -177,37 +184,36 @@ fun send(payload: OnRamp_Send, sender: address) {
177184
val executeMsg = createMessage({
178185
bounce: true,
179186
value: 0,
180-
dest: executorAddress(st.executorCode, st.currentMessageId),
181-
body: CCIPSendExecutor_Execute {
182-
onrampSend: payload,
183-
config: CCIPSendExecutor_Config {
184-
feeQuoter: config.feeQuoter,
185-
}.toCell(),
187+
dest: st.executor.autoDeployAddress(st.executor.currentID),
188+
body: Deployable_InitializeAndSend {
189+
stateInit: {
190+
code: st.executor.executorCode,
191+
data: CCIPSendExecutor_InitialData {
192+
onramp: contract.getAddress(),
193+
id: st.executor.currentID,
194+
}.toCell(),
195+
},
196+
selfMessage: {
197+
value: SendExecutor_Costs.Execute(),
198+
body: CCIPSendExecutor_Execute {
199+
onrampSend: payload,
200+
config: CCIPSendExecutor_Config {
201+
feeQuoter: config.feeQuoter,
202+
}.toCell(),
203+
}.toCell(),
204+
},
186205
}
187206
});
188207

189208
executeMsg.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);
190-
st.currentMessageId += 1;
209+
st.executor.currentID += 1;
191210

192211
st.store();
193212
}
194213

195-
@inline
196-
fun executorAddress(executorCode: cell, messageID: int): AutoDeployAddress {
197-
return AutoDeployAddress {
198-
stateInit: ContractState {
199-
code: executorCode,
200-
data: CCIPSendExecutor_InitialData {
201-
onramp: contract.getAddress(),
202-
messageID: messageID
203-
}.toCell(),
204-
}
205-
}
206-
}
207-
208214
fun commit(payload: OnRamp_ExecutorFinishedSuccessfully, sender: address) {
209215
var st = lazy OnRamp_Storage.load();
210-
assert(executorAddress(st.executorCode, payload.msgID).addressMatches(sender)) throw Error.Unauthorized;
216+
assert(st.executor.autoDeployAddress(payload.executorID).addressMatches(sender)) throw Error.Unauthorized;
211217

212218
val ccipsend: Router_CCIPSend = payload.msg.load();
213219
val metadata = payload.metadata;
@@ -274,7 +280,7 @@ fun commit(payload: OnRamp_ExecutorFinishedSuccessfully, sender: address) {
274280

275281
fun replyWithError(payload: OnRamp_ExecutorFinishedWithError, sender: address) {
276282
var st = lazy OnRamp_Storage.load();
277-
assert(executorAddress(st.executorCode, payload.msgID).addressMatches(sender)) throw Error.Unauthorized;
283+
assert(st.executor.autoDeployAddress(payload.executorID).addressMatches(sender)) throw Error.Unauthorized;
278284

279285
val ccipsend: Router_CCIPSend = payload.msg.load();
280286
val metadata = payload.metadata;
@@ -399,6 +405,11 @@ get fun destChainSelectors(): tuple? {
399405
return keysLispList(d)!;
400406
}
401407

408+
get fun sendExecutorCode(): cell {
409+
val st = lazy OnRamp_Storage.load();
410+
return st.executor.executorCode;
411+
}
412+
402413
get fun typeAndVersion(): (slice, slice) {
403414
return ("com.chainlink.ton.ccip.OnRamp", CONTRACT_VERSION);
404415
}

contracts/contracts/ccip/onramp/messages.tolk

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "../../lib/funding/withdrawable"
77
import "../../lib/versioning/upgradeable"
88
import "../ccipsend_executor/messages"
99
import "../fee_quoter/messages"
10+
import "../ccipsend_executor/types"
1011

1112
type OnRamp_InMessage =
1213
| OnRamp_Send
@@ -17,11 +18,11 @@ type OnRamp_InMessage =
1718
| OnRamp_ExecutorFinishedWithError
1819
| OnRamp_SetDynamicConfig
1920
| OnRamp_UpdateDestChainConfigs
21+
| OnRamp_UpdateSendExecutor
2022
| OnRamp_UpdateAllowlists
2123
| Withdrawable_Withdraw
2224
| Upgradeable_Upgrade
2325
;
24-
// TODO | UpdateExecutorCode
2526

2627
type OnRamp_NotificationInMessage =
2728
| OnRamp_Send
@@ -48,14 +49,14 @@ struct (0x10000003) OnRamp_SetDynamicConfig {
4849
}
4950

5051
struct (0xCFA6B336) OnRamp_ExecutorFinishedSuccessfully {
51-
msgID: uint224,
52+
executorID: CCIPSendExecutor_ID,
5253
fee: coins
5354
msg: Cell<Router_CCIPSend>
5455
metadata: Metadata
5556
}
5657

5758
struct (0xC4068E21) OnRamp_ExecutorFinishedWithError {
58-
msgID: uint224,
59+
executorID: CCIPSendExecutor_ID,
5960
error: uint256,
6061
msg: Cell<Router_CCIPSend>,
6162
metadata: Metadata,
@@ -66,6 +67,10 @@ struct (0x10000004) OnRamp_UpdateDestChainConfigs {
6667
updates: cell; // vec<OffRampUpdateDestChainConfig>
6768
}
6869

70+
struct (0x82901c45) OnRamp_UpdateSendExecutor {
71+
code: cell;
72+
}
73+
6974
// TODO: make this direct snakedata by using RemainingBitsAndRefs? this way it's not cell->cell
7075
struct (0x10000005) OnRamp_UpdateAllowlists {
7176
updates: cell; // vec<UpdateAllowlist>

contracts/contracts/ccip/onramp/storage.tolk

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ struct OnRamp_Storage {
1212
config: Cell<OnRamp_DynamicConfig>;
1313

1414
destChainConfigs: map<uint64, OnRamp_DestChainConfig>; // chainSelector -> DestChainConfig
15-
executorCode: cell; // code for CCIPSendExecutor
16-
currentMessageId: uint224;
15+
executor: ExecutorDeployment;
1716
}
1817

1918
fun OnRamp_Storage.load(): OnRamp_Storage {

contracts/contracts/ccip/onramp/types.tolk

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "../common/types"
22
import "../../lib/utils"
3+
import "../ccipsend_executor/types"
4+
import "../../deployable/types"
35

46
struct OnRamp_DestChainConfig {
57
router: address; // Local router address that is allowed to send messages to the destination chain.
@@ -21,6 +23,22 @@ struct OnRampUpdateDestChainConfig {
2123
allowlistEnabled: bool;
2224
}
2325

26+
struct ExecutorDeployment {
27+
deployableCode: cell;
28+
executorCode: cell; // code for SendExecutor
29+
currentID: uint224;
30+
}
31+
32+
@inline
33+
fun ExecutorDeployment.autoDeployAddress(self, executorID: int): AutoDeployAddress {
34+
return AutoDeployAddress {
35+
stateInit: ContractState {
36+
code: self.deployableCode,
37+
data: CCIPSendExecutor_DeployableData(contract.getAddress(), executorID),
38+
}
39+
}
40+
}
41+
2442
struct UpdateAllowlist {
2543
destChainSelector: uint64;
2644
add: SnakedCell<address>;
Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import "types"
22

3-
// initialize the contract as a stub with stateInit = {
4-
// owner: myAddr, type: "OnRamp", id: "some identifier, could also be a complex tuple"
5-
// }
6-
73
fun onInternalMessage(in: InMessage) {
84
val st = Deployable<RemainingBitsAndRefs>.load();
95
assert(in.senderAddress == st.owner) throw ERROR_NOT_OWNER;
10-
11-
val payload = Deployable_Initialize.fromSlice(in.body);
12-
13-
contract.setCodePostponed(payload.stateInit.code);
14-
contract.setData(payload.stateInit.data);
15-
//TODO: emit event
6+
val inMsg = lazy Deployable_InMessage.fromSlice(in.body);
7+
match (inMsg) {
8+
Deployable_Initialize => {
9+
contract.setCodePostponed(inMsg.stateInit.code);
10+
contract.setData(inMsg.stateInit.data);
11+
}
12+
Deployable_InitializeAndSend => {
13+
contract.setCodePostponed(inMsg.stateInit.code);
14+
contract.setData(inMsg.stateInit.data);
15+
val selfMsg = createMessage({
16+
bounce: false,
17+
value: inMsg.selfMessage.value,
18+
dest: contract.getAddress(),
19+
body: inMsg.selfMessage.body,
20+
});
21+
selfMsg.send( SEND_MODE_PAY_FEES_SEPARATELY);
22+
}
23+
}
1624
}

contracts/contracts/deployable/types.tolk

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,27 @@ fun Deployable<T>.store(self) {
1111
return contract.setData(self.toCell());
1212
}
1313

14+
type Deployable_InMessage =
15+
| Deployable_Initialize
16+
| Deployable_InitializeAndSend
17+
;
1418

19+
// Message for Initializing the Deployable contract. It sets the code and data of the contract.
1520
struct (0xba466447) Deployable_Initialize {
1621
stateInit: ContractState;
1722
}
1823

24+
// This message initializes the Deployable contract and immediately sends a message to itself to execute some logic. It allows to carry the message value.
25+
struct (0xe95e1156) Deployable_InitializeAndSend {
26+
stateInit: ContractState;
27+
selfMessage: Deployable_Message;
28+
}
29+
30+
struct Deployable_Message {
31+
value: coins;
32+
body: cell;
33+
}
34+
1935
//TODO: crc32('Deployable_ErrorNotOwner')
2036
const ERROR_NOT_OWNER: int = 0x1;
2137

contracts/tests/Logs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from '../wrappers/ccip/OffRamp'
1212
import { prettifyAddressesMap } from './utils/prettyPrint'
1313
import { crc32 } from 'zlib'
14-
import * as OR from '../wrappers/ccip/OnRamp'
14+
import * as onramp from '../wrappers/ccip/OnRamp'
1515

1616
// https://github.com/ton-blockchain/liquid-staking-contract/blob/1f4e9badbed52a4cf80cc58e4bb36ed375c6c8e7/utils.ts#L269-L294
1717
export const getExternals = (transactions: BlockchainTransaction[]) => {
@@ -467,7 +467,7 @@ export const testLogDestChainConfigUpdated = (
467467
const cs = x.beginParse()
468468
const msg = {
469469
destChainSelector: cs.loadUintBig(64),
470-
config: OR.builder.data.destChainConfig().load(cs),
470+
config: onramp.builder.data.destChainConfig.load(cs),
471471
}
472472
matchesObject(msg, match)
473473
return true

0 commit comments

Comments
 (0)