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
7 changes: 7 additions & 0 deletions src/CampaignInfo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,13 @@ contract CampaignInfo is
return _getGlobalParams().getPlatformAdminAddress(platformHash);
}

/**
* @inheritdoc ICampaignInfo
*/
function getPlatformAdapter(bytes32 platformHash) external view override returns (address) {
return _getGlobalParams().getPlatformAdapter(platformHash);
}

/**
* @inheritdoc ICampaignInfo
*/
Expand Down
5 changes: 1 addition & 4 deletions src/TreasuryFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,8 @@ contract TreasuryFactory is Initializable, ITreasuryFactory, AdminAccessChecker,

clone = Clones.clone(implementation);

// Fetch the platform adapter (trusted forwarder) from GlobalParams
address platformAdapter = _getGlobalParams().getPlatformAdapter(platformHash);

(bool success,) = clone.call(
abi.encodeWithSignature("initialize(bytes32,address,address)", platformHash, infoAddress, platformAdapter)
abi.encodeWithSignature("initialize(bytes32,address)", platformHash, infoAddress)
);
Comment on lines +122 to 123

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep deploy compatible with previously approved implementations

deploy() now hard-codes initialize(bytes32,address), but implementations approved before this change still expose initialize(bytes32,address,address). After upgrading TreasuryFactory, any existing implementationId that still points to the old initializer will consistently fail with TreasuryFactoryTreasuryInitializationFailed, which can halt treasury creation until every stored implementation is replaced and re-approved.

Useful? React with 👍 / 👎.

if (!success) {
revert TreasuryFactoryTreasuryInitializationFailed();
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/ICampaignInfo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ interface ICampaignInfo is IERC721 {
*/
function getPlatformAdminAddress(bytes32 platformHash) external view returns (address);

/**
* @notice Retrieves the adapter (trusted forwarder) address for a platform from GlobalParams.
* @param platformHash The bytes32 identifier of the platform.
* @return The adapter address for ERC-2771 meta-transactions, or address(0) if none is set.
*/
function getPlatformAdapter(bytes32 platformHash) external view returns (address);

/**
* @notice Retrieves the campaign's launch time.
* @return The timestamp when the campaign was launched.
Expand Down
4 changes: 2 additions & 2 deletions src/treasuries/AllOrNothing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ contract AllOrNothing is IReward, BaseTreasury, TimestampChecker, ReentrancyGuar
*/
constructor() {}

function initialize(bytes32 _platformHash, address _infoAddress, address _trustedForwarder) external initializer {
__BaseContract_init(_platformHash, _infoAddress, _trustedForwarder);
function initialize(bytes32 _platformHash, address _infoAddress) external initializer {
__BaseContract_init(_platformHash, _infoAddress);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/treasuries/KeepWhatsRaised.sol
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ contract KeepWhatsRaised is IReward, BaseTreasury, TimestampChecker, ICampaignDa
*/
constructor() {}

function initialize(bytes32 _platformHash, address _infoAddress, address _trustedForwarder) external initializer {
__BaseContract_init(_platformHash, _infoAddress, _trustedForwarder);
function initialize(bytes32 _platformHash, address _infoAddress) external initializer {
__BaseContract_init(_platformHash, _infoAddress);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/treasuries/PaymentTreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ contract PaymentTreasury is BasePaymentTreasury {
*/
constructor() {}

function initialize(bytes32 _platformHash, address _infoAddress, address _trustedForwarder) external initializer {
__BaseContract_init(_platformHash, _infoAddress, _trustedForwarder);
function initialize(bytes32 _platformHash, address _infoAddress) external initializer {
__BaseContract_init(_platformHash, _infoAddress);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/treasuries/TimeConstrainedPaymentTreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ contract TimeConstrainedPaymentTreasury is BasePaymentTreasury, TimestampChecker
*/
constructor() {}

function initialize(bytes32 _platformHash, address _infoAddress, address _trustedForwarder) external initializer {
__BaseContract_init(_platformHash, _infoAddress, _trustedForwarder);
function initialize(bytes32 _platformHash, address _infoAddress) external initializer {
__BaseContract_init(_platformHash, _infoAddress);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/utils/BasePaymentTreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,20 @@ abstract contract BasePaymentTreasury is
hasLimit = true;
}

function __BaseContract_init(bytes32 platformHash, address infoAddress, address trustedForwarder_) internal {
function __BaseContract_init(bytes32 platformHash, address infoAddress) internal {
__CampaignAccessChecker_init(infoAddress);
PLATFORM_HASH = platformHash;
PLATFORM_FEE_PERCENT = INFO.getPlatformFeePercent(platformHash);
_trustedForwarder = trustedForwarder_;
}

/**
* @dev Override _msgSender to support ERC-2771 meta-transactions.
* When called by the trusted forwarder (adapter), extracts the actual sender from calldata.
* The adapter address is read dynamically from GlobalParams via CampaignInfo so that
* adapter rotations take effect immediately for all deployed treasuries.
*/
function _msgSender() internal view virtual override returns (address sender) {
if (msg.sender == _trustedForwarder && msg.data.length >= 20) {
if (msg.sender == INFO.getPlatformAdapter(PLATFORM_HASH) && msg.data.length >= 20) {
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
Expand Down
7 changes: 4 additions & 3 deletions src/utils/BaseTreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,20 @@ abstract contract BaseTreasury is Initializable, ICampaignTreasury, CampaignAcce
*/
error TreasuryCampaignInfoIsPaused();

function __BaseContract_init(bytes32 platformHash, address infoAddress, address trustedForwarder_) internal {
function __BaseContract_init(bytes32 platformHash, address infoAddress) internal {
__CampaignAccessChecker_init(infoAddress);
PLATFORM_HASH = platformHash;
PLATFORM_FEE_PERCENT = INFO.getPlatformFeePercent(platformHash);
_trustedForwarder = trustedForwarder_;
}

/**
* @dev Override _msgSender to support ERC-2771 meta-transactions.
* When called by the trusted forwarder (adapter), extracts the actual sender from calldata.
* The adapter address is read dynamically from GlobalParams via CampaignInfo so that
* adapter rotations take effect immediately for all deployed treasuries.
*/
function _msgSender() internal view virtual override returns (address sender) {
if (msg.sender == _trustedForwarder && msg.data.length >= 20) {
if (msg.sender == INFO.getPlatformAdapter(PLATFORM_HASH) && msg.data.length >= 20) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard adapter lookup for legacy CampaignInfo compatibility

_msgSender() now unconditionally calls INFO.getPlatformAdapter(PLATFORM_HASH) before falling back to msg.sender. If infoAddress points to a CampaignInfo deployment that predates this new interface method, that external call reverts and all treasury entrypoints that rely on _msgSender() fail, making newly deployed treasuries unusable for those existing campaigns.

Useful? React with 👍 / 👎.

assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
Expand Down
3 changes: 0 additions & 3 deletions src/utils/CampaignAccessChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ abstract contract CampaignAccessChecker is Context {
// Immutable reference to the ICampaignInfo contract, which provides campaign-related information and admin addresses.
ICampaignInfo internal INFO;

/// @dev Trusted forwarder address for ERC-2771 meta-transactions (set by derived contracts)
address internal _trustedForwarder;

/**
* @dev Throws when the caller is not authorized.
*/
Expand Down