Skip to content

Commit 81b4e81

Browse files
archseerhuangzhen1997briansztamfaterjadepark-devCopilot
authored
Changesets + contract bindings (#76)
* add sequnce and operation for onramp * need testing * mod tidy * add test * fix build * fix ci * refactor * fix nix and add test * refactor * goimport * test CI * reorder CI * fix file name * add router * DynamicConfig is not snakedata * These fields are not embedded * Start working on methods * Router should be cross chain address * ops: Restructure based on Aptos * wip: Further restructuring * router update * update test * update * Define deploy for all three contracts * Restructure packages, ops should be it's own package * Update vendorHash * Fix type sizing mistakey * Further work on AddLane * wip * wip * add sendRequest helper function and update ccipsend binding, missing tests * rm wrong imports * change extraargs back to cell * fix: Use destChainConfig.router rather than onramp.router * Relayer and TONService implementation (#60) * feat: implement relayer and ton service * update hash * add client cache with TTL expiration and TODOs for LogPoller-related functions * some refactor * Merge pull request #84 from smartcontractkit/jh/adding-mock-and-bump-chainlink-common Add go mocks and bump chainlink-common version * Use existing network in integration tests (#86) * feat: use existing ton * fix: lint * fix: repo link Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Tests almost pass * Manually call fund * goimports * Fix lints * Update vendor hash * fix more lints * more lints * More binding fixes, 2/3 commands now succeed * sync replaces with core * Update with changes upstream * add state * Fix compilation * Start implementing ChainAccessor * Get method to execute * Fix duplication * address PR comments for refactor, addLane testhelper * Partially implement feeQuoter.UpdatePrices, first Accessor test now passes * Implement GetExpectedNextSequenceNumber * Need to return the *next* sequence number * TEMP: Switch to smartcontractkit/chainlink-common#1450 for public types * implement missing parts for addLane changeset * update CCIP tokenAmounts * Switch back to latest stable chainlink-common * WIP: GetConfig * Validate correct sender * Apply suggestion from @patricios-space Co-authored-by: Patricio <contact@patricios.space> * update SendTonRequest, need to test once go work fixed * fix test from core branch, remove comments * fix address codec to be chain specific addrCodec * Undo shell.nix changes * XImplement FeeQuoterDestChainConfig, other methods * fix relay bugs * rm debugger print * Bump chainlink-common, implement more of config fetching * Add get sourceChainConfig(selector) * Update provider to actually initialize CCIP Provider * Fix method name * Use a mutex around bindings, add GetContractAddress * add comment * refactor * Get the code to build with latest core * Fix lintsy * Update hash... * Add type assertions, fix typing of TokenData codec * Bump again? * Fix testy * Fix compilation * Use RUnlock where appropriate * tidy * Fix bool parsing * Resolve a couple TODOs * fix deployment submodule * use zero version for stale version fast fail * update binding to use RampMsg instead of CCIPSent * lint * lint * Add offramp bindings and wrappers * Implement GetContractAddress via getBinding * Fix typing * Directly embed ramp message into MessageSent event * Implement feeQuoter.UpdateFeeTokens, fix tests * format * Update vendorHash * fix build --------- Co-authored-by: Joe Huang <joe.huang@smartcontract.com> Co-authored-by: Brian Sztamfater <brian.sztamfater@smartcontract.com> Co-authored-by: Jonghyeon Park <jadepark.dev@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Patricio <contact@patricios.space>
1 parent 9a2ac3f commit 81b4e81

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+8035
-506
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ golangci-lint-*-report.xml
4242

4343
# Golangci-lint config(We use a upstream config from core, see getting-started.md)
4444
.golangci.yml
45+
46+
_vendor/

cmd/chainlink-ton/default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ in
1818
];
1919

2020
# pin the vendor hash (update using 'pkgs.lib.fakeHash')
21-
vendorHash = "sha256-AXT9mLLjfKGdH4euryMcOEEmkZz7XXsQTfe7mNE5dw4=";
21+
vendorHash = "sha256-3ADpTHOZxiQpRi38kgOrEsB4hfz7ap8ss4gZATAtYJU=";
2222

2323
# postInstall script to write version and rev to share folder
2424
postInstall = ''

contracts/contracts/ccip/fee_quoter.tolk

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ fun updatePrices(mutate st: Storage, priceUpdates: PriceUpdates) {
191191
//TODO: emit UsdPerUnitGasUpdated(update.destChainSelector, update.usdPerUnitGas, block.timestamp);
192192
}
193193
}
194-
195-
st.store();
196194
}
197195

198196
// apply_premium_multiplier_wei_per_eth_updates??
@@ -401,10 +399,14 @@ get fun tokenTransferFeeConfig() {}
401399

402400
// TODO: processMessageArgs(), processPoolReturnData()?
403401

404-
get fun destChainConfig() {}
402+
get fun destChainConfig(destChainSelector: uint64): DestChainConfig {
403+
val st = lazy Storage.load();
404+
return st.destChainConfigs.mustGet(destChainSelector, ERROR_DEST_CHAIN_NOT_ENABLED);
405+
}
405406

406-
get fun staticConfig() {
407-
// maxFeeJuelsPerMsg, linkToken, tokenPriceStalenessThreshold
407+
get fun staticConfig(): (uint96, address, uint64) {
408+
val st = lazy Storage.load();
409+
return (st.maxFeeJuelsPerMsg, st.linkToken, st.tokenPriceStalenessThreshold);
408410
}
409411

410412
get fun typeAndVersion(): (slice, slice) {

contracts/contracts/ccip/offramp.tolk

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,17 @@ fun setDynamicConfig() {
349349
}
350350

351351
get fun dynamicConfig() {
352-
352+
// TODO: combine get staticConfig and dynamicConfig into get config
353353
}
354354

355-
get fun sourceChainConfig() {}
355+
get fun sourceChainConfig(sourceChainSelector: uint64): SourceChainConfig {
356+
val st = lazy Storage.load();
357+
return st.sourceChainConfigs.mustGet(sourceChainSelector,ERROR_SOURCE_CHAIN_NOT_ENABLED);
358+
}
356359

357-
get fun allSourceChainConfigs(): tuple {
358-
return createEmptyTuple()
360+
get fun allSourceChainConfigs(): dict {
361+
val st = lazy Storage.load();
362+
return st.sourceChainConfigs.value;
359363
}
360364

361365
fun applySourceChainConfigUpdates() {}

contracts/contracts/ccip/onramp.tolk

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ import "@stdlib/tvm-dicts";
88
const CCIP_MESSAGE_SENT_TOPIC: int = stringCrc32("CCIPMessageSent");
99

1010
struct CCIPMessageSent {
11-
destChainSelector: uint64; // NOTE: both these values are already part of message, is it even important to have?
12-
sequenceNumber: uint64;
13-
message: Cell<TVM2AnyRampMessage>;
11+
message: TVM2AnyRampMessage;
1412
}
1513

1614
struct Storage {
1715
ownable: Ownable2Step;
1816

1917
// static config
20-
router: address;
2118
chainSelector: uint64; // source chain selector
2219
// TODO: rmnRemote (only used to validate curse on getFee), nonceManager, tokenAdminRegistry
2320
// hmm, need to consider the design here.
@@ -34,7 +31,7 @@ struct Storage {
3431
}
3532

3633
struct DestChainConfig {
37-
router: CrossChainAddress;
34+
router: address; // Local router address that is allowed to send messages to the destination chain.
3835
sequenceNumber: uint64;
3936
allowlistEnabled: bool;
4037
allowedSenders: Map<bool>; // address -> bool
@@ -88,16 +85,17 @@ fun onInternalMessage(in: InMessage) {
8885

8986
fun send(payload: OnRampSend, sender: address) {
9087
val st = lazy Storage.load();
91-
// ccipSend must be forwarded from the router
92-
assert(st.router == sender, ERROR_UNAUTHORIZED);
9388

9489
val msg = payload.msg.load();
9590

9691
// validate allowlist
9792
val destChainConfig = st.destChainConfigs.mustGet(msg.destChainSelector, ERROR_UNKNOWN_DEST_CHAIN_SELECTOR);
93+
94+
// ccipSend must be forwarded from the router
95+
assert(destChainConfig.router == sender, ERROR_UNAUTHORIZED);
96+
9897
if (destChainConfig.allowlistEnabled) {
99-
// TODO:
100-
val (allowed, exists) = destChainConfig.allowedSenders.get(sender);
98+
val (allowed, exists) = destChainConfig.allowedSenders.get(payload.metadata.sender);
10199
assert(exists && allowed!, ERROR_SENDER_NOT_ALLOWED);
102100
}
103101

@@ -143,7 +141,9 @@ fun onMessageValidated(payload: MessageValidated<Metadata>, sender: address) {
143141
sourceChainSelector: st.chainSelector,
144142
destChainSelector: msg.destChainSelector,
145143
sequenceNumber: seqNr,
146-
nonce: 0, // TODO:
144+
// Only bump nonce for messages that specify allowOutOfOrderExecution == false. Otherwise, we may block ordered
145+
// message nonces, which is not what we want.
146+
nonce: 0,
147147
},
148148
sender: metadata.sender,
149149
body: TVM2AnyRampMessageBody {
@@ -157,6 +157,11 @@ fun onMessageValidated(payload: MessageValidated<Metadata>, sender: address) {
157157
feeValueJuels: 0, // TODO:
158158
};
159159

160+
// TODO: support for ordered execution
161+
// rampMessage.header.nonce = isOutOfOrderExecution
162+
// ? 0
163+
// : nonceManager.getIncrementedOutboundNonce(destChainSelector, metadata.sender);
164+
160165
// Metadata hash preimage to ensure global uniqueness, ensuring 2 identical messages sent to 2 different lanes
161166
// will have a distinct hash.
162167
val metadataHash = beginCell()
@@ -169,11 +174,7 @@ fun onMessageValidated(payload: MessageValidated<Metadata>, sender: address) {
169174

170175
rampMessage.header.messageId = rampMessage.generateMessageId(metadataHash);
171176

172-
emit(CCIP_MESSAGE_SENT_TOPIC, CCIPMessageSent {
173-
destChainSelector: msg.destChainSelector,
174-
sequenceNumber: seqNr,
175-
message: rampMessage.toCell(),
176-
});
177+
emit(CCIP_MESSAGE_SENT_TOPIC, CCIPMessageSent { message: rampMessage });
177178

178179
// TODO: notify user
179180
}
@@ -187,7 +188,7 @@ get fun isChainSupported(destChainSelector: uint64): bool {
187188
get fun expectedNextSequenceNumber(destChainSelector: uint64): uint64 {
188189
val st = lazy Storage.load();
189190
val config = st.destChainConfigs.mustGet(destChainSelector,ERROR_UNKNOWN_DEST_CHAIN_SELECTOR);
190-
return config.sequenceNumber;
191+
return config.sequenceNumber + 1;
191192
}
192193

193194
// TODO: getFee forwarding? users should just call the fee quoter

contracts/contracts/ccip/types.tolk

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,11 @@ struct (0x10000003) SetDynamicConfig {
162162

163163
struct OnRampUpdateDestChainConfig {
164164
destChainSelector: uint64;
165-
router: CrossChainAddress;
165+
router: address;
166166
allowlistEnabled: bool;
167167
}
168168

169+
// TODO: make this direct snakedata by using RemainingBitsAndRefs? this way it's not cell->cell
169170
struct (0x10000004) OnRampUpdateDestChainConfigs {
170171
updates: cell; // vec<OrRampUpdateDestChainConfig>
171172
}
@@ -176,6 +177,7 @@ struct UpdateAllowlist {
176177
remove: cell; // vec<address>
177178
}
178179

180+
// TODO: make this direct snakedata by using RemainingBitsAndRefs? this way it's not cell->cell
179181
struct (0x10000005) UpdateAllowlists {
180182
updates: cell; // vec<UpdateAllowlist>
181183
}
@@ -216,7 +218,7 @@ struct FeeQuoterDestChainConfig {
216218
destGasPerPayloadByteThreshold: uint16;
217219
destDataAvailabilityOverheadGas: uint32;
218220
destGasPerDataAvailabilityByte: uint16;
219-
destDataAvailabilityMultiplierBps: uint32;
221+
destDataAvailabilityMultiplierBps: uint16;
220222

221223
chainFamilySelector: uint32; // 4 bytes
222224
enforceOutOfOrder: bool;

contracts/tests/Logs.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ export const testLogCCIPMessageSent = (
135135
return testLog(message, from, CombinedLogTypes.CCIPMessageSent, (x) => {
136136
let bs = x.beginParse()
137137

138-
const destChainSelector = bs.loadUintBig(64)
139-
const sequenceNumber = bs.loadUintBig(64)
140-
141-
bs = bs.loadRef().beginParse()
142-
143138
const header = {
144139
messageId: bs.loadUintBig(256),
145140
sourceChainSelector: bs.loadUintBig(64),
@@ -152,8 +147,6 @@ export const testLogCCIPMessageSent = (
152147
const body = bs.loadRef().beginParse()
153148

154149
const msg: CCIPLogs.CCIPMessageSent = {
155-
destChainSelector,
156-
sequenceNumber,
157150
message: {
158151
header,
159152
sender,

contracts/tests/ccip/CCIPRouter.spec.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@ describe('Router', () => {
6868
),
6969
destChainConfigs: Dictionary.empty(Dictionary.Keys.BigUint(64)),
7070
}
71-
// HACK: pre-insert token data
72-
data.usdPerToken.set(ZERO_ADDRESS, {
73-
value: 123n,
74-
timestamp: BigInt(Date.now()),
75-
} as TimestampedPrice)
7671
feeQuoter = blockchain.openContract(FeeQuoter.createFromConfig(data, code))
7772

7873
let result = await feeQuoter.sendDeploy(deployer.getSender(), toNano('1'))
@@ -83,6 +78,16 @@ describe('Router', () => {
8378
success: true,
8479
})
8580

81+
result = await feeQuoter.sendUpdatePrices(deployer.getSender(), {
82+
value: toNano('1'),
83+
gasPrices: [],
84+
tokenPrices: [{ token: ZERO_ADDRESS, price: 123n }],
85+
})
86+
expect(result.transactions).toHaveTransaction({
87+
to: feeQuoter.address,
88+
success: true,
89+
})
90+
8691
// add config for EVM destination
8792
result = await feeQuoter.sendUpdateDestChainConfig(deployer.getSender(), {
8893
value: toNano('1'),
@@ -134,7 +139,6 @@ describe('Router', () => {
134139
owner: deployer.address,
135140
pendingOwner: null,
136141
},
137-
router: router.address,
138142
chainSelector: CHAINSEL_TON,
139143
config: {
140144
feeQuoter: feeQuoter.address,
@@ -160,7 +164,7 @@ describe('Router', () => {
160164
destChainConfigs: [
161165
{
162166
destChainSelector: CHAINSEL_EVM_TEST_90000001,
163-
router: Buffer.alloc(64),
167+
router: router.address,
164168
allowlistEnabled: false,
165169
},
166170
],

contracts/wrappers/ccip/FeeQuoter.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export function destChainConfigToBuilder(config: DestChainConfig): TonBuilder {
8282
.storeUint(config.destGasPerPayloadByteThreshold, 16)
8383
.storeUint(config.destDataAvailabilityOverheadGas, 32)
8484
.storeUint(config.destGasPerDataAvailabilityByte, 16)
85-
.storeUint(config.destDataAvailabilityMultiplierBps, 32)
85+
.storeUint(config.destDataAvailabilityMultiplierBps, 16)
8686
.storeUint(config.chainFamilySelector, 32)
8787
.storeBit(config.enforceOutOfOrder)
8888
.storeUint(config.defaultTokenFeeUsdCents, 16)
@@ -118,6 +118,7 @@ export const Builder = {
118118
export abstract class Params {}
119119

120120
export abstract class Opcodes {
121+
static updatePrices = 0x20000001
121122
static updateFeeTokens = 0x20000002
122123
static updateTransferFeeConfigs = 0x20000003
123124
static updateDestChainConfig = 0x20000004
@@ -177,6 +178,40 @@ export class FeeQuoter implements Contract {
177178
})
178179
}
179180

181+
async sendUpdatePrices(
182+
provider: ContractProvider,
183+
via: Sender,
184+
opts: {
185+
value: bigint
186+
gasPrices: {
187+
chainSelector: bigint
188+
executionGasPrice: bigint
189+
dataAvailabilityGasPrice: bigint
190+
}[]
191+
tokenPrices: { token: Address; price: bigint }[]
192+
},
193+
) {
194+
const tokenPrices = asSnakeData(opts.tokenPrices, (config) =>
195+
new TonBuilder().storeAddress(config.token).storeInt(config.price, 224),
196+
)
197+
const gasPrices = asSnakeData(opts.gasPrices, (config) =>
198+
new TonBuilder()
199+
.storeInt(config.chainSelector, 64)
200+
.storeInt(config.executionGasPrice, 112)
201+
.storeInt(config.dataAvailabilityGasPrice, 112),
202+
)
203+
204+
return await provider.internal(via, {
205+
value: opts.value,
206+
sendMode: SendMode.PAY_GAS_SEPARATELY,
207+
body: beginCell()
208+
.storeUint(Opcodes.updatePrices, 32)
209+
.storeRef(tokenPrices)
210+
.storeRef(gasPrices)
211+
.endCell(),
212+
})
213+
}
214+
180215
async sendUpdateFeeTokens(
181216
provider: ContractProvider,
182217
via: Sender,

contracts/wrappers/ccip/Logs.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ export enum LogTypes {
1111
}
1212

1313
export type CCIPMessageSent = {
14-
destChainSelector: bigint
15-
sequenceNumber: bigint
1614
message: {
1715
header: {
1816
messageId: bigint

0 commit comments

Comments
 (0)