Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions contracts/tests/ccip/OffRamp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,48 @@ describe('OffRamp - Unit Tests', () => {
await commitReport([root], toNano('0.5'), 0x02, undefined)
})

it('Test commit fails when global cursed', async () => {
const message = createTestMessage()
const metadataHash = uint8ArrayToBigInt(getMetadataHash(CHAINSEL_EVM_TEST_90000001))
const rootBytes = uint8ArrayToBigInt(generateMessageId(message, metadataHash))
const root = createMerkleRoot(1n, 1n, rootBytes)

await setupOCRConfig()
await setupSourceChainConfig()

// Curse all lanes
const curseResult = await offRamp.sendUpdateCursedSubjects(deployer.getSender(), {
value: toNano('0.5'),
subjects: [rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT],
})
expect(curseResult.transactions).toHaveTransaction({
from: deployer.address,
to: offRamp.address,
success: true,
})
let cursedSubjects = await offRamp.getCursedSubjects()
expect(cursedSubjects).toEqual([rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT])

// Attempt to commit - should fail with SubjectCursed
await commitReport([root], toNano('0.5'), 0x01, undefined, false, of.OffRampError.SubjectCursed)

// Uncurse all lanes
const uncurseResult = await offRamp.sendUpdateCursedSubjects(deployer.getSender(), {
value: toNano('0.5'),
subjects: [],
})
expect(uncurseResult.transactions).toHaveTransaction({
from: deployer.address,
to: offRamp.address,
success: true,
})
cursedSubjects = await offRamp.getCursedSubjects()
expect(cursedSubjects).toEqual([])

// Now commit should succeed
await commitReport([root], toNano('0.5'), 0x02, undefined)
})

it('Test commit fails with onRamp address mismatch', async () => {
const message = createTestMessage()
const metadataHash = uint8ArrayToBigInt(getMetadataHash(CHAINSEL_EVM_TEST_90000001))
Expand Down Expand Up @@ -1377,6 +1419,42 @@ describe('OffRamp - Unit Tests', () => {
})
})

it('Test execute fails when source chain is cursed', async () => {
const message = createTestMessage(1n, 1n, receiver.address)

// Setup and commit with enabled chain
await setupOCRConfigs()
const metadataHash = uint8ArrayToBigInt(getMetadataHash(CHAINSEL_EVM_TEST_90000001))
const rootBytes = uint8ArrayToBigInt(generateMessageId(message, metadataHash))
const root = createMerkleRoot(1n, 1n, rootBytes)
await commitReport([root])

// Curse source chain
let result = await offRamp.sendUpdateCursedSubjects(deployer.getSender(), {
value: toNano('0.5'),
subjects: [rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT],
})
expect(result.transactions).toHaveTransaction({
from: deployer.address,
to: offRamp.address,
success: true,
})

const report = createExecuteReport([message])
await executeReportExpectingFailure(report, of.OffRampError.SubjectCursed)

// Uncurse source chain
result = await offRamp.sendUpdateCursedSubjects(deployer.getSender(), {
value: toNano('0.5'),
subjects: [],
})
expect(result.transactions).toHaveTransaction({
from: deployer.address,
to: offRamp.address,
success: true,
})
})

it('Test execute fails when source chain config does not exist', async () => {
const unknownChainSelector = 777777n
const message = createTestMessage(1n, 1n, receiver.address)
Expand Down
44 changes: 44 additions & 0 deletions contracts/tests/ccip/router/Router.cursing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,50 @@ describe('Router.cursing', () => {
}
})

it('router respect global cursing', async () => {
// Curse all lanes
{
const result = await router.sendRMNRemoteCurse(deployer.getSender(), {
value: toNano('1'),
body: { queryID: 0n, subjects: [rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT] },
})
expect(result.transactions).toHaveTransaction({
from: deployer.address,
to: router.address,
success: true,
})

assertLog(result.transactions, router.address, LogTypes.Cursed, {
subject: rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT,
})

await verifyNotCursed(router, deployer, false)
const cursedSubjects = await router.getCursedSubjects()
expect(cursedSubjects).toEqual([rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT])
}

// Uncurse all lanes
{
const result = await router.sendRMNRemoteUncurse(deployer.getSender(), {
value: toNano('1'),
body: { queryID: 0n, subjects: [rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT] },
})
expect(result.transactions).toHaveTransaction({
from: deployer.address,
to: router.address,
success: true,
})

assertLog(result.transactions, router.address, LogTypes.Uncursed, {
subject: rt.RMNREMOTE_GLOBAL_CURSE_SUBJECT,
})

await verifyNotCursed(router, deployer, true)
const cursedSubjects = await router.getCursedSubjects()
expect(cursedSubjects).toEqual([])
}
})

afterAll(async () => {
if (process.env['COVERAGE'] === 'true') {
await coverage.generateCoverageArtifacts(
Expand Down
2 changes: 2 additions & 0 deletions contracts/wrappers/ccip/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,8 @@ export type MessageValidationFailed = {
context: Slice
}

export const RMNREMOTE_GLOBAL_CURSE_SUBJECT = 0x01000000000000000000000000000001n

export type RMNRemoteCurse = {
queryID: bigint
subjects: bigint[]
Expand Down
Loading