Skip to content

Commit 255e197

Browse files
Firedrill contracts (#602)
* add contracts and initial blueprint scaffolding * add wrappers * extend LogType to have feequoter logs * fix getSourceChainConfig ts wrapper * fix contracts * define test suites for firedrill contracts * fix offramp and get tests to pass * get tests to pass, fmt * move firerill files to the chainlink-ton/contracts directory * fix message and lane should be from ton to ton * script to deploy firedrill contracts * add typeAndVersion getters to contracts * fmt * check for ownable before the message match * remove unused exit code * clean up deployment script * use already defined ownable wrapppers * fmt * use createEmptyCell * fix var shadowing * fix entrypoint deployment * split runFiredrill scripts * add required contract getters * fix chain selector * fix tonAddressToCrossChainAddress * add else clause to message handler on ramps * fmt * change event to USDPerGasUpdated, add FeeQUoter to TypeAndversion * also include Router in typeAndVersion * increase delay to avoid script to fail * fix ci failures
1 parent 8353591 commit 255e197

27 files changed

Lines changed: 2566 additions & 3 deletions
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
tolk 1.2
2+
3+
import "../lib/utils.tolk"
4+
import "../lib/access/ownable_2step.tolk"
5+
import "../ccip/router/types.tolk"
6+
import "../ccip/fee_quoter/types.tolk"
7+
import "../ccip/fee_quoter/events.tolk"
8+
import "firedrill_entrypoint_messages.tolk"
9+
import "firedrill_onramp_messages.tolk"
10+
import "firedrill_offramp_messages.tolk"
11+
12+
struct FiredrillEntrypoint_Storage {
13+
id: uint32;
14+
ownable: Ownable2Step;
15+
chainSelector: uint64;
16+
tokenAddress: address;
17+
firedrillContracts: Cell<FiredrillContracts>?;
18+
sSendLast: uint64;
19+
}
20+
21+
struct FiredrillContracts {
22+
firedrillOnRamp: address;
23+
firedrillOffRamp: address;
24+
}
25+
26+
fun FiredrillEntrypoint_Storage.load(): FiredrillEntrypoint_Storage {
27+
return FiredrillEntrypoint_Storage.fromCell(contract.getData());
28+
}
29+
30+
fun FiredrillEntrypoint_Storage.store(self) {
31+
return contract.setData(self.toCell());
32+
}
33+
34+
enum FiredrillEntrypoint_Error {
35+
NothingToSend = 3001,
36+
MessageAlreadySent,
37+
NotYetSent,
38+
RampsAlreadyInitialized,
39+
RampsNotInitialized,
40+
NotEnoughTon
41+
}
42+
43+
const DRILL_MESSAGE_VALUE: coins = ton("0.007");
44+
45+
fun onInternalMessage(in: InMessage) {
46+
var st = lazy FiredrillEntrypoint_Storage.load();
47+
st.ownable.requireOwner(in.senderAddress);
48+
val msg = lazy FiredrillEntrypoint_InMessage.fromSlice(in.body);
49+
val value = in.valueCoins;
50+
51+
match (msg) {
52+
FiredrillEntrypoint_PrepareRegister => {
53+
prepareRegister(st);
54+
}
55+
FiredrillEntrypoint_DrillPendingCommitPendingQueueTxSpike => {
56+
drillPendingCommitPendingQueueTxSpike(mutate st, msg, value);
57+
st.store();
58+
}
59+
FiredrillEntrypoint_DrillPendingExecution => {
60+
drillPendingExecution(st, msg);
61+
}
62+
FiredrillEntrypoint_DrillPriceRegistries => {
63+
drillPriceRegistries(st);
64+
}
65+
FiredrillEntrypoint_InitRamps => {
66+
initRamps(mutate st, msg);
67+
st.store();
68+
}
69+
else => {
70+
// attempt to handle Ownable messages
71+
var st = lazy FiredrillEntrypoint_Storage.load();
72+
val handled = st.ownable.onInternalMessage(in.senderAddress, in.body);
73+
if (handled) {
74+
st.store();
75+
return;
76+
}
77+
78+
// ignore empty messages, "wrong opcode" for others
79+
assert (in.body.isEmpty()) throw 0xFFFF;
80+
}
81+
82+
}
83+
}
84+
85+
fun initRamps(mutate st: FiredrillEntrypoint_Storage, msg: FiredrillEntrypoint_InitRamps) {
86+
assert(st.firedrillContracts == null, FiredrillEntrypoint_Error.RampsAlreadyInitialized);
87+
val firedrillContracts = FiredrillContracts {
88+
firedrillOnRamp: msg.onramp,
89+
firedrillOffRamp: msg.offramp
90+
};
91+
st.firedrillContracts = firedrillContracts.toCell();
92+
}
93+
94+
fun prepareRegister(st: FiredrillEntrypoint_Storage) {
95+
// Send message to OffRamp to emit SourceChainConfigSet event
96+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
97+
val firedrillContracts = st.firedrillContracts.load();
98+
val msg = createMessage({
99+
bounce: false,
100+
value: 0,
101+
dest: firedrillContracts.firedrillOffRamp,
102+
body: FiredrillOffRamp_EmitSourceChainConfigSet {},
103+
});
104+
msg.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);
105+
}
106+
107+
fun drillPendingCommitPendingQueueTxSpike(mutate st: FiredrillEntrypoint_Storage, msg: FiredrillEntrypoint_DrillPendingCommitPendingQueueTxSpike, value: coins) {
108+
assert(msg.from <= msg.to, FiredrillEntrypoint_Error.NothingToSend);
109+
assert(msg.from > st.sSendLast, FiredrillEntrypoint_Error.MessageAlreadySent);
110+
assert(value >= DRILL_MESSAGE_VALUE * (msg.to - msg.from + 1) + ton("0.005"), FiredrillEntrypoint_Error.NotEnoughTon);
111+
112+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
113+
val firedrillContracts = st.firedrillContracts.load();
114+
115+
// Send messages to OnRamp to emit CCIPMessageSent events
116+
var i: uint64 = msg.from;
117+
while (i <= msg.to) {
118+
val emitMsg = FiredrillOnRamp_EmitCCIPMessageSent {
119+
sender: contract.getAddress(),
120+
sequenceNumber: i
121+
};
122+
123+
val message = createMessage({
124+
bounce: false,
125+
value: DRILL_MESSAGE_VALUE,
126+
dest: firedrillContracts.firedrillOnRamp,
127+
body: emitMsg,
128+
});
129+
message.send(SEND_MODE_REGULAR);
130+
131+
i += 1;
132+
}
133+
134+
st.sSendLast = msg.to;
135+
}
136+
137+
fun drillPendingExecution(st: FiredrillEntrypoint_Storage, msg: FiredrillEntrypoint_DrillPendingExecution) {
138+
assert(msg.from <= msg.to, FiredrillEntrypoint_Error.NothingToSend);
139+
assert(msg.to <= st.sSendLast, FiredrillEntrypoint_Error.NotYetSent);
140+
141+
// Send message to OffRamp to emit CommitReportAccepted event
142+
val emitMsg = FiredrillOffRamp_EmitCommitReportAccepted {
143+
minSeqNr: msg.from,
144+
maxSeqNr: msg.to
145+
};
146+
147+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
148+
val firedrillContracts = st.firedrillContracts.load();
149+
150+
val message = createMessage({
151+
bounce: false,
152+
value: 0,
153+
dest: firedrillContracts.firedrillOffRamp,
154+
body: emitMsg,
155+
});
156+
message.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);
157+
}
158+
159+
fun drillPriceRegistries(st: FiredrillEntrypoint_Storage) {
160+
// Emit UsdPerTokenUpdated event
161+
val timestamp = blockchain.now();
162+
163+
emit(USD_PER_UNIT_GAS_UPDATED, UsdPerUnitGasUpdated {
164+
destChainSelector: st.chainSelector,
165+
executionGasPrice: 1,
166+
dataAvailabilityGasPrice: 1,
167+
timestamp: timestamp
168+
});
169+
}
170+
171+
// ========== Router Getters ==========
172+
173+
get fun onRamp(destChainSelector: uint64): address {
174+
val st = lazy FiredrillEntrypoint_Storage.load();
175+
176+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
177+
val firedrillContracts = st.firedrillContracts.load();
178+
179+
return firedrillContracts.firedrillOnRamp;
180+
}
181+
182+
get fun offRamp(sourceChainSelector: uint64): address {
183+
val st = lazy FiredrillEntrypoint_Storage.load();
184+
185+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
186+
val firedrillContracts = st.firedrillContracts.load();
187+
188+
return firedrillContracts.firedrillOffRamp;
189+
}
190+
191+
get fun onRamps(): OnRamps {
192+
val st = lazy FiredrillEntrypoint_Storage.load();
193+
194+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
195+
val firedrillContracts = st.firedrillContracts.load();
196+
197+
val selectors = beginCell().storeUint(st.chainSelector, 64).endCell() as SnakedCell<uint64>;
198+
199+
return OnRamps {
200+
destChainSelectors: selectors,
201+
onRamp: firedrillContracts.firedrillOnRamp
202+
};
203+
}
204+
205+
get fun offRamps(): OffRamps {
206+
val st = lazy FiredrillEntrypoint_Storage.load();
207+
208+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
209+
val firedrillContracts = st.firedrillContracts.load();
210+
val selectors = beginCell().storeUint(st.chainSelector, 64).endCell() as SnakedCell<uint64>;
211+
return OffRamps {
212+
sourceChainSelectors: selectors,
213+
offRamp: firedrillContracts.firedrillOffRamp
214+
};
215+
}
216+
217+
// ========== FeeQuoter Getters ==========
218+
219+
get fun staticConfig(): (uint96, address, uint64) {
220+
val st = lazy FiredrillEntrypoint_Storage.load();
221+
// Returns (maxFeeJuelsPerMsg, linkToken, tokenPriceStalenessThreshold)
222+
return (1, st.tokenAddress, 0);
223+
}
224+
225+
get fun tokenPrice(token: address): TimestampedPrice {
226+
return TimestampedPrice {
227+
value: 1,
228+
timestamp: 0
229+
};
230+
}
231+
232+
get fun destinationChainGasPrice(destChainSelector: uint64): cell {
233+
val gasPrice = GasPrice {
234+
executionGasPrice: 1,
235+
dataAvailabilityGasPrice: 1,
236+
timestamp: 0
237+
};
238+
return gasPrice.toCell();
239+
}
240+
241+
get fun destChainConfig(destChainSelector: uint64): DestChainConfig {
242+
val destChainConfig: DestChainConfig = {
243+
config: {// minimal valid config for EVM destination
244+
isEnabled: true,
245+
maxNumberOfTokensPerMsg: 0,
246+
maxDataBytes: 300,
247+
maxPerMsgGasLimit: 4000000,
248+
destGasOverhead: 300000,
249+
destGasPerPayloadByteBase: 16,
250+
destGasPerPayloadByteHigh: 40,
251+
destGasPerPayloadByteThreshold: 100,
252+
destDataAvailabilityOverheadGas:300 ,
253+
destGasPerDataAvailabilityByte: 300,
254+
destDataAvailabilityMultiplierBps: 6840,
255+
chainFamilySelector: 0x647e2ba9, //TVM
256+
defaultTokenFeeUsdCents: 50,
257+
defaultTokenDestGasOverhead: 90000,
258+
defaultTxGasLimit: 1000000,
259+
gasMultiplierWeiPerEth: 1000000000000000000,
260+
gasPriceStalenessThreshold: 12 * 60 * 60,
261+
networkFeeUsdCents: 100,
262+
},
263+
usdPerUnitGas: GasPrice {
264+
executionGasPrice: 1000000,
265+
dataAvailabilityGasPrice: 1000000000,
266+
timestamp: blockchain.now()
267+
}.toCell(),
268+
tokenTransferFeeConfigs: createEmptyMap(),
269+
};
270+
return destChainConfig;
271+
}
272+
273+
// ========== Common Getters ==========
274+
275+
get fun chainSelector(): uint64 {
276+
val st = lazy FiredrillEntrypoint_Storage.load();
277+
return st.chainSelector;
278+
}
279+
280+
get fun tokenAddress(): address {
281+
val st = lazy FiredrillEntrypoint_Storage.load();
282+
return st.tokenAddress;
283+
}
284+
285+
get fun onRampAddress(): address {
286+
val st = lazy FiredrillEntrypoint_Storage.load();
287+
288+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
289+
val firedrillContracts = st.firedrillContracts.load();
290+
return firedrillContracts.firedrillOnRamp;
291+
}
292+
293+
get fun offRampAddress(): address {
294+
val st = lazy FiredrillEntrypoint_Storage.load();
295+
296+
assert(st.firedrillContracts != null, FiredrillEntrypoint_Error.RampsNotInitialized);
297+
val firedrillContracts = st.firedrillContracts.load();
298+
return firedrillContracts.firedrillOffRamp;
299+
}
300+
301+
get fun owner(): address {
302+
val st = lazy FiredrillEntrypoint_Storage.load();
303+
return st.ownable.owner;
304+
}
305+
306+
get fun pendingOwner(): address? {
307+
val st = lazy FiredrillEntrypoint_Storage.load();
308+
return st.ownable.pendingOwner;
309+
}
310+
311+
get fun typeAndVersion(): (slice, slice) {
312+
return ("com.chainlink.ton.ccip.firedrill.firedrillEntrypoint.Router.FeeQuoter", "1.6.0")
313+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
type FiredrillEntrypoint_InMessage =
2+
| FiredrillEntrypoint_PrepareRegister
3+
| FiredrillEntrypoint_DrillPendingCommitPendingQueueTxSpike
4+
| FiredrillEntrypoint_DrillPendingExecution
5+
| FiredrillEntrypoint_DrillPriceRegistries
6+
| FiredrillEntrypoint_InitRamps
7+
;
8+
9+
struct (0x10000001) FiredrillEntrypoint_PrepareRegister {
10+
}
11+
12+
struct (0x10000002) FiredrillEntrypoint_DrillPendingCommitPendingQueueTxSpike {
13+
from: uint64;
14+
to: uint64;
15+
}
16+
17+
struct (0x10000003) FiredrillEntrypoint_DrillPendingExecution {
18+
from: uint64;
19+
to: uint64;
20+
}
21+
22+
struct (0x10000004) FiredrillEntrypoint_DrillPriceRegistries {
23+
}
24+
25+
struct (0x10000005) FiredrillEntrypoint_InitRamps {
26+
onramp: address,
27+
offramp: address,
28+
}

0 commit comments

Comments
 (0)