Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
df9a846
docs: update audit extracts for PR1301 v02 report
RembrandtK Apr 17, 2026
cb6c45c
fix(collector): add gas overhead buffer to callback prechecks (TRST-L-9)
RembrandtK Apr 17, 2026
3ce5813
fix(collector): cap returndata copy in payer callbacks (TRST-M-4)
RembrandtK Apr 17, 2026
8e50abd
docs: add response to TRST-L-10 EIP-7702 callback dispatch (won't fix)
RembrandtK Apr 17, 2026
6a0ac79
feat(RAM): drop pair tracking below residual escrow threshold (TRST-M…
RembrandtK Apr 17, 2026
f96a731
docs: add responses to TRST-L-6, TRST-R-7 (both won't fix)
RembrandtK Apr 19, 2026
35447e7
docs(audit): acknowledge TRST-R-3 cancelAgreement defensive check
RembrandtK Apr 20, 2026
2dd2372
fix(collector): remove dead oldHash guard (TRST-R-6)
RembrandtK Apr 20, 2026
c1ef1cb
fix(collector): non-zero offer types, reserve OFFER_TYPE_NONE=0 senti…
RembrandtK Apr 19, 2026
3621793
refactor(interfaces): drop unused state and offer-option flags, tight…
RembrandtK Apr 19, 2026
f32e550
docs(audit): acknowledge trust-boundary correction in TRST-H-4
RembrandtK Apr 19, 2026
d2fd364
docs(audit): acknowledge reclaim-reason change in TRST-R-13
RembrandtK Apr 19, 2026
b61d441
docs(ram): document collector replay-protection assumption (TRST-R-4)
RembrandtK Apr 19, 2026
0271015
docs(ram): document non-retroactive role-change semantics (TRST-R-10)
RembrandtK Apr 19, 2026
1ee49f2
docs(ram): align pause-escalation prose with whenNotPaused scope (TRS…
RembrandtK Apr 19, 2026
9396dbd
docs(collector): note self-authorization auth-check obligation (TRST-…
RembrandtK Apr 19, 2026
1e5a6b3
fix(subgraph-service): validate update terms against RCAU rate, not s…
RembrandtK Apr 21, 2026
8be1aa0
refactor(collector): preparatory helpers, signatures, and version con…
RembrandtK Apr 22, 2026
cfaf39b
refactor(collector): drop unreachable agreementId-zero check
RembrandtK Apr 21, 2026
35748ff
refactor(collector): extract _requireValidTerms from duplicated valid…
RembrandtK Apr 21, 2026
0ad0be4
refactor(collector): split accept logic out of _validateAndStoreAgree…
RembrandtK Apr 21, 2026
bfe7754
refactor(collector): split update apply out of _validateAndStoreUpdate
RembrandtK Apr 21, 2026
594d19b
feat(subgraph-service): idempotent accept/update with allocation rebi…
RembrandtK Apr 27, 2026
885555e
refactor(collector): hoist solhint-disable, idiomatic deadline compar…
RembrandtK Apr 27, 2026
572853b
fix(collector): validate offer terms against deadline, not block.time…
RembrandtK Apr 22, 2026
b6adbf1
refactor(collector): extract _getAgreementDetails/_versionHashAt helpers
RembrandtK Apr 27, 2026
8b48437
fix(collector): persistent agreement.payer for independent cancellati…
RembrandtK Apr 27, 2026
769b252
feat(collector): idempotent accept/update/cancel-on-nothing
RembrandtK Apr 27, 2026
f96b4ea
feat(collector): add OfferCancelled event for SCOPE_PENDING cancellat…
RembrandtK Apr 25, 2026
c1dfc34
feat(collector): per-version semantics in getAgreementDetails (TRST-L…
RembrandtK Apr 27, 2026
33d2ced
feat(collector): compose cancel/settled flags in getAgreementDetails …
RembrandtK Apr 19, 2026
fe13b11
feat(collector): add SCOPE_SIGNED to cancel() for EOA offer revocatio…
RembrandtK Apr 19, 2026
b13d910
feat(issuance): expose getIssuanceAllocator on IIssuanceTarget
RembrandtK Apr 10, 2026
e4cd9e0
fix(collector): validate full terms at offer time
RembrandtK Apr 26, 2026
6772545
fix(collector): respect deadlines in scoped claim cap
RembrandtK Apr 26, 2026
067168e
refactor(collector): collapse redundant state guard in _getMaxNextClaim
RembrandtK Apr 27, 2026
757da41
fix(collector): use dedicated error for invalid offer type in offer()
RembrandtK Apr 27, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ describe('RewardsManager interfaces', () => {
})

it('IIssuanceTarget should have stable interface ID', () => {
expect(IIssuanceTarget__factory.interfaceId).to.equal('0xaee4dc43')
expect(IIssuanceTarget__factory.interfaceId).to.equal('0x19f6601a')
})

it('IRewardsManager should have stable interface ID', () => {
expect(IRewardsManager__factory.interfaceId).to.equal('0x337b092e')
expect(IRewardsManager__factory.interfaceId).to.equal('0x8469b577')
})
})

Expand Down
17 changes: 9 additions & 8 deletions packages/contracts/contracts/rewards/RewardsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -173,24 +173,25 @@ contract RewardsManager is
* Note that the IssuanceAllocator can be set to the zero address to disable use of an allocator, and
* use the local `issuancePerBlock` variable instead to control issuance.
*/
function setIssuanceAllocator(address newIssuanceAllocator) external override onlyGovernor {
if (address(issuanceAllocator) != newIssuanceAllocator) {
function setIssuanceAllocator(IIssuanceAllocationDistribution newIssuanceAllocator) external override onlyGovernor {
if (issuanceAllocator != newIssuanceAllocator) {
// Update rewards calculation before changing the issuance allocator
updateAccRewardsPerSignal();

// Check that the contract supports the IIssuanceAllocationDistribution interface
// Allow zero address to disable the allocator
if (newIssuanceAllocator != address(0)) {
if (address(newIssuanceAllocator) != address(0)) {
// solhint-disable-next-line gas-small-strings
require(
IERC165(newIssuanceAllocator).supportsInterface(type(IIssuanceAllocationDistribution).interfaceId),
IERC165(address(newIssuanceAllocator)).supportsInterface(
type(IIssuanceAllocationDistribution).interfaceId
),
"Contract does not support IIssuanceAllocationDistribution interface"
);
}

address oldIssuanceAllocator = address(issuanceAllocator);
issuanceAllocator = IIssuanceAllocationDistribution(newIssuanceAllocator);
emit IssuanceAllocatorSet(oldIssuanceAllocator, newIssuanceAllocator);
emit IssuanceAllocatorSet(issuanceAllocator, newIssuanceAllocator);
issuanceAllocator = newIssuanceAllocator;
}
}

Expand Down Expand Up @@ -325,7 +326,7 @@ contract RewardsManager is
}

/**
* @inheritdoc IRewardsManager
* @inheritdoc IIssuanceTarget
*/
function getIssuanceAllocator() external view override returns (IIssuanceAllocationDistribution) {
return issuanceAllocator;
Expand Down
10 changes: 5 additions & 5 deletions packages/deployment/lib/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ function loadAbi(artifactPath: string): Abi {
return artifact.abi as Abi
}

// Interface IDs - these match the generated values from TypeChain factories
// Verified by tests: packages/issuance/testing/tests/allocate/InterfaceIdStability.test.ts
// and packages/contracts-test/tests/unit/rewards/rewards-interface.test.ts
// Interface IDs - these mirror the values the compiler derives from the
// corresponding ABI. Cross-checked by test/interface-id-stability.test.ts;
// update both together whenever an interface changes.
export const IERC165_INTERFACE_ID = '0x01ffc9a7' as const
export const IISSUANCE_TARGET_INTERFACE_ID = '0xaee4dc43' as const
export const IREWARDS_MANAGER_INTERFACE_ID = '0xa0a2f219' as const
export const IISSUANCE_TARGET_INTERFACE_ID = '0x19f6601a' as const
export const IREWARDS_MANAGER_INTERFACE_ID = '0x8469b577' as const

export const REWARDS_MANAGER_ABI = loadAbi(
'@graphprotocol/interfaces/artifacts/contracts/contracts/rewards/IRewardsManager.sol/IRewardsManager.json',
Expand Down
34 changes: 34 additions & 0 deletions packages/deployment/test/interface-id-stability.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect } from 'chai'
import type { Abi } from 'viem'
import { toFunctionSelector } from 'viem'

import {
IERC165_ABI,
IERC165_INTERFACE_ID,
IISSUANCE_TARGET_INTERFACE_ID,
IREWARDS_MANAGER_INTERFACE_ID,
ISSUANCE_TARGET_ABI,
REWARDS_MANAGER_ABI,
} from '../lib/abis.js'

function computeInterfaceId(abi: Abi): `0x${string}` {
const xor = abi
.filter((item): item is Extract<(typeof abi)[number], { type: 'function' }> => item.type === 'function')
.map((f) => Number.parseInt(toFunctionSelector(f).slice(2), 16) >>> 0)
.reduce((a, s) => (a ^ s) >>> 0, 0)
return `0x${xor.toString(16).padStart(8, '0')}`
}

describe('Interface ID Stability', function () {
it('IERC165_INTERFACE_ID matches the IERC165 ABI', function () {
expect(IERC165_INTERFACE_ID).to.equal(computeInterfaceId(IERC165_ABI))
})

it('IISSUANCE_TARGET_INTERFACE_ID matches the IIssuanceTarget ABI', function () {
expect(IISSUANCE_TARGET_INTERFACE_ID).to.equal(computeInterfaceId(ISSUANCE_TARGET_ABI))
})

it('IREWARDS_MANAGER_INTERFACE_ID matches the IRewardsManager ABI', function () {
expect(IREWARDS_MANAGER_INTERFACE_ID).to.equal(computeInterfaceId(REWARDS_MANAGER_ABI))
})
})
Loading
Loading