diff --git a/src/AddressDriver.sol b/src/AddressDriver.sol index 8a5e4d86..23432d92 100644 --- a/src/AddressDriver.sol +++ b/src/AddressDriver.sol @@ -28,7 +28,7 @@ contract AddressDriver is DriverTransferUtils, Managed { /// `driverId (32 bits) | zeros (64 bits) | addr (160 bits)`. /// @param addr The address /// @return accountId The account ID - function calcAccountId(address addr) public view returns (uint256 accountId) { + function calcAccountId(address addr) public view onlyProxy returns (uint256 accountId) { // By assignment we get `accountId` value: // `zeros (224 bits) | driverId (32 bits)` accountId = driverId; @@ -55,7 +55,7 @@ contract AddressDriver is DriverTransferUtils, Managed { /// If you use such tokens in the protocol, they can get stuck or lost. /// @param transferTo The address to send collected funds to /// @return amt The collected amount - function collect(IERC20 erc20, address transferTo) public returns (uint128 amt) { + function collect(IERC20 erc20, address transferTo) public onlyProxy returns (uint128 amt) { return _collectAndTransfer(drips, _callerAccountId(), erc20, transferTo); } @@ -70,7 +70,7 @@ contract AddressDriver is DriverTransferUtils, Managed { /// or impose any restrictions on holding or transferring tokens are not supported. /// If you use such tokens in the protocol, they can get stuck or lost. /// @param amt The given amount - function give(uint256 receiver, IERC20 erc20, uint128 amt) public { + function give(uint256 receiver, IERC20 erc20, uint128 amt) public onlyProxy { _giveAndTransfer(drips, _callerAccountId(), receiver, erc20, amt); } @@ -131,7 +131,7 @@ contract AddressDriver is DriverTransferUtils, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public returns (int128 realBalanceDelta) { + ) public onlyProxy returns (int128 realBalanceDelta) { return _setStreamsAndTransfer( drips, _callerAccountId(), @@ -164,7 +164,7 @@ contract AddressDriver is DriverTransferUtils, Managed { /// This is usually unwanted, because if splitting is repeated, /// funds split to themselves will be again split using the current configuration. /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. - function setSplits(SplitsReceiver[] calldata receivers) public { + function setSplits(SplitsReceiver[] calldata receivers) public onlyProxy { drips.setSplits(_callerAccountId(), receivers); } @@ -172,7 +172,7 @@ contract AddressDriver is DriverTransferUtils, Managed { /// The keys and the values are not standardized by the protocol, it's up to the users /// to establish and follow conventions to ensure compatibility with the consumers. /// @param accountMetadata The list of account metadata. - function emitAccountMetadata(AccountMetadata[] calldata accountMetadata) public { + function emitAccountMetadata(AccountMetadata[] calldata accountMetadata) public onlyProxy { if (accountMetadata.length != 0) { drips.emitAccountMetadata(_callerAccountId(), accountMetadata); } diff --git a/src/Drips.sol b/src/Drips.sol index 406b1a9d..7c5ce7e0 100644 --- a/src/Drips.sol +++ b/src/Drips.sol @@ -174,7 +174,7 @@ contract Drips is Managed, Streams, Splits { /// It should be a smart contract capable of dealing with the Drips API. /// It shouldn't be an EOA because the API requires making multiple calls per transaction. /// @return driverId The registered driver ID. - function registerDriver(address driverAddr) public returns (uint32 driverId) { + function registerDriver(address driverAddr) public onlyProxy returns (uint32 driverId) { require(driverAddr != address(0), "Driver registered for 0 address"); DripsStorage storage dripsStorage = _dripsStorage(); driverId = dripsStorage.nextDriverId++; @@ -186,7 +186,7 @@ contract Drips is Managed, Streams, Splits { /// @param driverId The driver ID to look up. /// @return driverAddr The address of the driver. /// If the driver hasn't been registered yet, returns address 0. - function driverAddress(uint32 driverId) public view returns (address driverAddr) { + function driverAddress(uint32 driverId) public view onlyProxy returns (address driverAddr) { return _dripsStorage().driverAddresses[driverId]; } @@ -195,7 +195,7 @@ contract Drips is Managed, Streams, Splits { /// @param newDriverAddr The new address of the driver. /// It should be a smart contract capable of dealing with the Drips API. /// It shouldn't be an EOA because the API requires making multiple calls per transaction. - function updateDriverAddress(uint32 driverId, address newDriverAddr) public { + function updateDriverAddress(uint32 driverId, address newDriverAddr) public onlyProxy { _assertCallerIsDriver(driverId); _dripsStorage().driverAddresses[driverId] = newDriverAddr; emit DriverAddressUpdated(driverId, msg.sender, newDriverAddr); @@ -203,7 +203,7 @@ contract Drips is Managed, Streams, Splits { /// @notice Returns the driver ID which will be assigned for the next registered driver. /// @return driverId The next driver ID. - function nextDriverId() public view returns (uint32 driverId) { + function nextDriverId() public view onlyProxy returns (uint32 driverId) { return _dripsStorage().nextDriverId; } @@ -225,6 +225,7 @@ contract Drips is Managed, Streams, Splits { function balances(IERC20 erc20) public view + onlyProxy returns (uint128 streamsBalance, uint128 splitsBalance) { Balance storage balance = _dripsStorage().balances[erc20]; @@ -308,7 +309,7 @@ contract Drips is Managed, Streams, Splits { /// @param amt The withdrawn amount. /// It must be at most the difference between the balance of the token held by the Drips /// contract address and the sum of balances managed by the protocol as indicated by `balances`. - function withdraw(IERC20 erc20, address receiver, uint256 amt) public { + function withdraw(IERC20 erc20, address receiver, uint256 amt) public onlyProxy { (uint128 streamsBalance, uint128 splitsBalance) = balances(erc20); uint256 withdrawable = erc20.balanceOf(address(this)) - streamsBalance - splitsBalance; require(amt <= withdrawable, "Withdrawal amount too high"); @@ -330,6 +331,7 @@ contract Drips is Managed, Streams, Splits { function receivableStreamsCycles(uint256 accountId, IERC20 erc20) public view + onlyProxy returns (uint32 cycles) { return Streams._receivableStreamsCycles(accountId, erc20); @@ -350,6 +352,7 @@ contract Drips is Managed, Streams, Splits { function receiveStreamsResult(uint256 accountId, IERC20 erc20, uint32 maxCycles) public view + onlyProxy returns (uint128 receivableAmt) { (receivableAmt,,,,) = Streams._receiveStreamsResult(accountId, erc20, maxCycles); @@ -371,6 +374,7 @@ contract Drips is Managed, Streams, Splits { /// @return receivedAmt The received amount function receiveStreams(uint256 accountId, IERC20 erc20, uint32 maxCycles) public + onlyProxy returns (uint128 receivedAmt) { receivedAmt = Streams._receiveStreams(accountId, erc20, maxCycles); @@ -406,7 +410,7 @@ contract Drips is Managed, Streams, Splits { uint256 senderId, bytes32 historyHash, StreamsHistory[] memory streamsHistory - ) public returns (uint128 amt) { + ) public onlyProxy returns (uint128 amt) { amt = Streams._squeezeStreams(accountId, erc20, senderId, historyHash, streamsHistory); if (amt != 0) { _moveBalanceFromStreamsToSplits(erc20, amt); @@ -433,7 +437,7 @@ contract Drips is Managed, Streams, Splits { uint256 senderId, bytes32 historyHash, StreamsHistory[] memory streamsHistory - ) public view returns (uint128 amt) { + ) public view onlyProxy returns (uint128 amt) { (amt,,,,) = Streams._squeezeStreamsResult(accountId, erc20, senderId, historyHash, streamsHistory); } @@ -447,7 +451,12 @@ contract Drips is Managed, Streams, Splits { /// or impose any restrictions on holding or transferring tokens are not supported. /// If you use such tokens in the protocol, they can get stuck or lost. /// @return amt The amount received but not split yet. - function splittable(uint256 accountId, IERC20 erc20) public view returns (uint128 amt) { + function splittable(uint256 accountId, IERC20 erc20) + public + view + onlyProxy + returns (uint128 amt) + { return Splits._splittable(accountId, erc20); } @@ -465,6 +474,7 @@ contract Drips is Managed, Streams, Splits { function splitResult(uint256 accountId, SplitsReceiver[] memory currReceivers, uint128 amount) public view + onlyProxy returns (uint128 collectableAmt, uint128 splitAmt) { return Splits._splitResult(accountId, currReceivers, amount); @@ -495,6 +505,7 @@ contract Drips is Managed, Streams, Splits { /// @return splitAmt The amount split to the account's splits receivers function split(uint256 accountId, IERC20 erc20, SplitsReceiver[] memory currReceivers) public + onlyProxy returns (uint128 collectableAmt, uint128 splitAmt) { return Splits._split(accountId, erc20, currReceivers); @@ -509,7 +520,12 @@ contract Drips is Managed, Streams, Splits { /// or impose any restrictions on holding or transferring tokens are not supported. /// If you use such tokens in the protocol, they can get stuck or lost. /// @return amt The collectable amount. - function collectable(uint256 accountId, IERC20 erc20) public view returns (uint128 amt) { + function collectable(uint256 accountId, IERC20 erc20) + public + view + onlyProxy + returns (uint128 amt) + { return Splits._collectable(accountId, erc20); } @@ -526,6 +542,7 @@ contract Drips is Managed, Streams, Splits { /// @return amt The collected amount function collect(uint256 accountId, IERC20 erc20) public + onlyProxy onlyDriver(accountId) returns (uint128 amt) { @@ -549,6 +566,7 @@ contract Drips is Managed, Streams, Splits { /// @param amt The given amount function give(uint256 accountId, uint256 receiver, IERC20 erc20, uint128 amt) public + onlyProxy onlyDriver(accountId) { if (amt != 0) _increaseSplitsBalance(erc20, amt); @@ -571,6 +589,7 @@ contract Drips is Managed, Streams, Splits { function streamsState(uint256 accountId, IERC20 erc20) public view + onlyProxy returns ( bytes32 streamsHash, bytes32 streamsHistoryHash, @@ -602,7 +621,7 @@ contract Drips is Managed, Streams, Splits { IERC20 erc20, StreamReceiver[] memory currReceivers, uint32 timestamp - ) public view returns (uint128 balance) { + ) public view onlyProxy returns (uint128 balance) { return Streams._balanceAt(accountId, erc20, currReceivers, timestamp); } @@ -667,7 +686,7 @@ contract Drips is Managed, Streams, Splits { // slither-disable-next-line similar-names uint32 maxEndHint1, uint32 maxEndHint2 - ) public onlyDriver(accountId) returns (int128 realBalanceDelta) { + ) public onlyProxy onlyDriver(accountId) returns (int128 realBalanceDelta) { if (balanceDelta > 0) _increaseStreamsBalance(erc20, uint128(balanceDelta)); realBalanceDelta = Streams._setStreams( accountId, erc20, currReceivers, balanceDelta, newReceivers, maxEndHint1, maxEndHint2 @@ -730,6 +749,7 @@ contract Drips is Managed, Streams, Splits { /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. function setSplits(uint256 accountId, SplitsReceiver[] memory receivers) public + onlyProxy onlyDriver(accountId) { Splits._setSplits(accountId, receivers); @@ -738,7 +758,7 @@ contract Drips is Managed, Streams, Splits { /// @notice Current account's splits hash, see `hashSplits`. /// @param accountId The account ID. /// @return currSplitsHash The current account's splits hash - function splitsHash(uint256 accountId) public view returns (bytes32 currSplitsHash) { + function splitsHash(uint256 accountId) public view onlyProxy returns (bytes32 currSplitsHash) { return Splits._splitsHash(accountId); } @@ -761,6 +781,7 @@ contract Drips is Managed, Streams, Splits { /// @param accountMetadata The list of account metadata. function emitAccountMetadata(uint256 accountId, AccountMetadata[] calldata accountMetadata) public + onlyProxy onlyDriver(accountId) { unchecked { diff --git a/src/Giver.sol b/src/Giver.sol index f2d8da93..51fb2406 100644 --- a/src/Giver.sol +++ b/src/Giver.sol @@ -68,7 +68,7 @@ contract GiversRegistry is Managed { } /// @notice Initialize this instance of the contract. - function initialize() public { + function initialize() public onlyProxy { if (!Address.isContract(_giverLogic(address(this)))) new Giver(); } @@ -77,7 +77,7 @@ contract GiversRegistry is Managed { /// to its address will be `give`n when `give` is called. /// @param accountId The ID of the account to which the `Giver` is assigned. /// @return giver_ The address of the `Giver`. - function giver(uint256 accountId) public view returns (address giver_) { + function giver(uint256 accountId) public view onlyProxy returns (address giver_) { return _giver(accountId, address(this)); } @@ -106,7 +106,7 @@ contract GiversRegistry is Managed { /// If it's the zero address, `Giver` wraps all the native tokens it holds using /// `nativeTokenWrapper`, and then `give`s to the account all the wrapped tokens it holds. /// @param amt The amount of tokens that were `give`n. - function give(uint256 accountId, IERC20 erc20) public returns (uint256 amt) { + function give(uint256 accountId, IERC20 erc20) public onlyProxy returns (uint256 amt) { address giver_ = giver(accountId); if (!Address.isContract(giver_)) { // slither-disable-next-line unused-return diff --git a/src/ImmutableSplitsDriver.sol b/src/ImmutableSplitsDriver.sol index 97749ebc..6b53d7c3 100644 --- a/src/ImmutableSplitsDriver.sol +++ b/src/ImmutableSplitsDriver.sol @@ -38,7 +38,7 @@ contract ImmutableSplitsDriver is Managed { /// Every account ID is a 256-bit integer constructed by concatenating: /// `driverId (32 bits) | accountIdsCounter (224 bits)`. /// @return accountId The account ID. - function nextAccountId() public view returns (uint256 accountId) { + function nextAccountId() public view onlyProxy returns (uint256 accountId) { // By assignment we get `accountId` value: // `zeros (224 bits) | driverId (32 bits)` accountId = driverId; @@ -70,7 +70,7 @@ contract ImmutableSplitsDriver is Managed { function createSplits( SplitsReceiver[] calldata receivers, AccountMetadata[] calldata accountMetadata - ) public returns (uint256 accountId) { + ) public onlyProxy returns (uint256 accountId) { accountId = nextAccountId(); StorageSlot.getUint256Slot(_counterSlot).value++; uint256 weightSum = 0; diff --git a/src/NFTDriver.sol b/src/NFTDriver.sol index 180c7bdf..d35536fd 100644 --- a/src/NFTDriver.sol +++ b/src/NFTDriver.sol @@ -8,6 +8,7 @@ import {DriverTransferUtils, ERC2771Context} from "./DriverTransferUtils.sol"; import {Managed} from "./Managed.sol"; import { Context, + ERC165, ERC721, ERC721Burnable, IERC721, @@ -58,7 +59,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// Every token ID is a 256-bit integer constructed by concatenating: /// `driverId (32 bits) | zeros (160 bits) | mintedTokensCounter (64 bits)`. /// @return tokenId The token ID. It's equal to the account ID controlled by it. - function nextTokenId() public view returns (uint256 tokenId) { + function nextTokenId() public view onlyProxy returns (uint256 tokenId) { return calcTokenIdWithSalt(address(0), _nftDriverStorage().mintedTokens); } @@ -71,6 +72,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { function calcTokenIdWithSalt(address minter, uint64 salt) public view + onlyProxy returns (uint256 tokenId) { // By assignment we get `tokenId` value: @@ -93,7 +95,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @param minter The minter of the token. /// @param salt The salt used for minting the token. /// @return isUsed True if the salt has been used, false otherwise. - function isSaltUsed(address minter, uint64 salt) public view returns (bool isUsed) { + function isSaltUsed(address minter, uint64 salt) public view onlyProxy returns (bool isUsed) { return _nftDriverStorage().isSaltUsed[minter][salt]; } @@ -107,6 +109,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @return tokenId The minted token ID. It's equal to the account ID controlled by it. function mint(address to, AccountMetadata[] calldata accountMetadata) public + onlyProxy returns (uint256 tokenId) { tokenId = _registerTokenId(); @@ -124,6 +127,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @return tokenId The minted token ID. It's equal to the account ID controlled by it. function safeMint(address to, AccountMetadata[] calldata accountMetadata) public + onlyProxy returns (uint256 tokenId) { tokenId = _registerTokenId(); @@ -151,6 +155,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// The ID is calculated using `calcTokenIdWithSalt` for the caller's address and the used salt. function mintWithSalt(uint64 salt, address to, AccountMetadata[] calldata accountMetadata) public + onlyProxy returns (uint256 tokenId) { tokenId = _registerTokenIdWithSalt(salt); @@ -171,6 +176,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// The ID is calculated using `calcTokenIdWithSalt` for the caller's address and the used salt. function safeMintWithSalt(uint64 salt, address to, AccountMetadata[] calldata accountMetadata) public + onlyProxy returns (uint256 tokenId) { tokenId = _registerTokenIdWithSalt(salt); @@ -203,6 +209,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @return amt The collected amount function collect(uint256 tokenId, IERC20 erc20, address transferTo) public + onlyProxy onlyApprovedOrOwner(tokenId) returns (uint128 amt) { @@ -225,6 +232,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @param amt The given amount function give(uint256 tokenId, uint256 receiver, IERC20 erc20, uint128 amt) public + onlyProxy onlyApprovedOrOwner(tokenId) { _giveAndTransfer(drips, tokenId, receiver, erc20, amt); @@ -291,7 +299,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public onlyApprovedOrOwner(tokenId) returns (int128 realBalanceDelta) { + ) public onlyProxy onlyApprovedOrOwner(tokenId) returns (int128 realBalanceDelta) { return _setStreamsAndTransfer( drips, tokenId, @@ -329,6 +337,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. function setSplits(uint256 tokenId, SplitsReceiver[] calldata receivers) public + onlyProxy onlyApprovedOrOwner(tokenId) { drips.setSplits(tokenId, receivers); @@ -343,6 +352,7 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { /// @param accountMetadata The list of account metadata. function emitAccountMetadata(uint256 tokenId, AccountMetadata[] calldata accountMetadata) public + onlyProxy onlyApprovedOrOwner(tokenId) { _emitAccountMetadata(tokenId, accountMetadata); @@ -362,6 +372,16 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { } } + /// @inheritdoc IERC721 + function balanceOf(address owner) public view override onlyProxy returns (uint256) { + return super.balanceOf(owner); + } + + /// @inheritdoc IERC721 + function ownerOf(uint256 tokenId) public view override onlyProxy returns (address) { + return super.ownerOf(tokenId); + } + /// @inheritdoc IERC721Metadata function name() public pure override returns (string memory) { return "Drips identity"; @@ -372,37 +392,63 @@ contract NFTDriver is ERC721Burnable, DriverTransferUtils, Managed { return "DHI"; } - /// @inheritdoc ERC721Burnable - function burn(uint256 tokenId) public override { - super.burn(tokenId); + /// @inheritdoc IERC721Metadata + function tokenURI(uint256 tokenId) public view override onlyProxy returns (string memory) { + return super.tokenURI(tokenId); } /// @inheritdoc IERC721 - function approve(address to, uint256 tokenId) public override { + function approve(address to, uint256 tokenId) public override onlyProxy { super.approve(to, tokenId); } /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId) public override { - super.safeTransferFrom(from, to, tokenId); + function getApproved(uint256 tokenId) public view override onlyProxy returns (address) { + return super.getApproved(tokenId); } /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) + function setApprovalForAll(address operator, bool approved) public override onlyProxy { + super.setApprovalForAll(operator, approved); + } + + /// @inheritdoc IERC721 + function isApprovedForAll(address owner, address operator) public + view override + onlyProxy + returns (bool) { - super.safeTransferFrom(from, to, tokenId, data); + return super.isApprovedForAll(owner, operator); } /// @inheritdoc IERC721 - function setApprovalForAll(address operator, bool approved) public override { - super.setApprovalForAll(operator, approved); + function transferFrom(address from, address to, uint256 tokenId) public override onlyProxy { + super.transferFrom(from, to, tokenId); } /// @inheritdoc IERC721 - function transferFrom(address from, address to, uint256 tokenId) public override { - super.transferFrom(from, to, tokenId); + function safeTransferFrom(address from, address to, uint256 tokenId) + public + override + onlyProxy + { + super.safeTransferFrom(from, to, tokenId); + } + + /// @inheritdoc IERC721 + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) + public + override + onlyProxy + { + super.safeTransferFrom(from, to, tokenId, data); + } + + /// @inheritdoc ERC721Burnable + function burn(uint256 tokenId) public override onlyProxy { + super.burn(tokenId); } // Workaround for https://github.com/ethereum/solidity/issues/12554 diff --git a/src/RepoDriver.sol b/src/RepoDriver.sol index 7102299a..c4520078 100644 --- a/src/RepoDriver.sol +++ b/src/RepoDriver.sol @@ -136,6 +136,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { function calcAccountId(Forge forge, bytes memory name) public view + onlyProxy returns (uint256 accountId) { uint8 forgeId; @@ -184,6 +185,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// refer to their documentation to see what's the minimum value. function initializeAnyApiOperator(OperatorInterface operator, bytes32 jobId, uint96 defaultFee) public + onlyProxy { require(!_repoDriverAnyApiStorage().isInitialized, "Already initialized"); _updateAnyApiOperator(operator, jobId, defaultFee); @@ -198,6 +200,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// refer to their documentation to see what's the minimum value. function updateAnyApiOperator(OperatorInterface operator, bytes32 jobId, uint96 defaultFee) public + onlyProxy onlyAdmin { _updateAnyApiOperator(operator, jobId, defaultFee); @@ -231,6 +234,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { function anyApiOperator() public view + onlyProxy returns (OperatorInterface operator, bytes32 jobId, uint96 defaultFee) { RepoDriverAnyApiStorage storage storageRef = _repoDriverAnyApiStorage(); @@ -242,7 +246,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// @notice Gets the account owner. /// @param accountId The ID of the account. /// @return owner The owner of the account. - function ownerOf(uint256 accountId) public view returns (address owner) { + function ownerOf(uint256 accountId) public view onlyProxy returns (address owner) { return _repoDriverStorage().accountOwners[accountId]; } @@ -265,6 +269,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// @return accountId The ID of the account. function requestUpdateOwner(Forge forge, bytes memory name) public + onlyProxy returns (uint256 accountId) { uint256 fee = _repoDriverAnyApiStorage().defaultFee; @@ -285,7 +290,10 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// It must be a valid ABI-encoded calldata for `requestUpdateOwner`. /// The call parameters will be used the same way as when calling `requestUpdateOwner`, /// to determine which account's ownership update is requested. - function onTokenTransfer(address, /* sender */ uint256 amount, bytes calldata data) public { + function onTokenTransfer(address, /* sender */ uint256 amount, bytes calldata data) + public + onlyProxy + { require(msg.sender == address(linkToken), "Callable only by the Link token"); require(data.length >= 4, "Data not a valid calldata"); require(bytes4(data[:4]) == this.requestUpdateOwner.selector, "Data not requestUpdateOwner"); @@ -373,7 +381,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// Must be the same as the request ID generated when requesting an owner update, /// this function will update the account ownership that was requested back then. /// @param ownerRaw The new owner of the account. Must be a 20 bytes long address. - function updateOwnerByAnyApi(bytes32 requestId, bytes calldata ownerRaw) public { + function updateOwnerByAnyApi(bytes32 requestId, bytes calldata ownerRaw) public onlyProxy { RepoDriverAnyApiStorage storage storageRef = _repoDriverAnyApiStorage(); require(msg.sender == address(storageRef.operator), "Callable only by the operator"); uint256 accountId = storageRef.requestedUpdates[requestId]; @@ -399,6 +407,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// @return amt The collected amount function collect(uint256 accountId, IERC20 erc20, address transferTo) public + onlyProxy onlyOwner(accountId) returns (uint128 amt) { @@ -419,6 +428,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// @param amt The given amount function give(uint256 accountId, uint256 receiver, IERC20 erc20, uint128 amt) public + onlyProxy onlyOwner(accountId) { _giveAndTransfer(drips, accountId, receiver, erc20, amt); @@ -484,7 +494,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public onlyOwner(accountId) returns (int128 realBalanceDelta) { + ) public onlyProxy onlyOwner(accountId) returns (int128 realBalanceDelta) { return _setStreamsAndTransfer( drips, accountId, @@ -521,6 +531,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. function setSplits(uint256 accountId, SplitsReceiver[] calldata receivers) public + onlyProxy onlyOwner(accountId) { drips.setSplits(accountId, receivers); @@ -534,6 +545,7 @@ contract RepoDriver is ERC677ReceiverInterface, DriverTransferUtils, Managed { /// @param accountMetadata The list of account metadata. function emitAccountMetadata(uint256 accountId, AccountMetadata[] calldata accountMetadata) public + onlyProxy onlyOwner(accountId) { if (accountMetadata.length != 0) { diff --git a/src/dataStore/AddressDriverDataProxy.sol b/src/dataStore/AddressDriverDataProxy.sol index 059272fe..d36db08e 100644 --- a/src/dataStore/AddressDriverDataProxy.sol +++ b/src/dataStore/AddressDriverDataProxy.sol @@ -99,7 +99,7 @@ contract AddressDriverDataProxy is ERC2771Context, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public returns (int128 realBalanceDelta) { + ) public onlyProxy returns (int128 realBalanceDelta) { uint256 accountId = addressDriver.calcAccountId(_msgSender()); // slither-disable-next-line unused-return (bytes32 currStreamsHash,,,,) = drips.streamsState(accountId, erc20); @@ -138,7 +138,7 @@ contract AddressDriverDataProxy is ERC2771Context, Managed { /// This is usually unwanted, because if splitting is repeated, /// funds split to themselves will be again split using the current configuration. /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. - function setSplits(bytes32 splitsHash) public { + function setSplits(bytes32 splitsHash) public onlyProxy { bytes memory data = abi.encodeCall(addressDriver.setSplits, dripsDataStore.loadSplits(splitsHash)); abi.decode(_callAddressDriver(data), ()); @@ -149,7 +149,7 @@ contract AddressDriverDataProxy is ERC2771Context, Managed { /// to establish and follow conventions to ensure compatibility with the consumers. /// @param accountMetadataHash The hash of the list of account metadata, /// the actual list must be stored in DripsDataStore. - function emitAccountMetadata(bytes32 accountMetadataHash) public { + function emitAccountMetadata(bytes32 accountMetadataHash) public onlyProxy { bytes memory data = abi.encodeCall( addressDriver.emitAccountMetadata, dripsDataStore.loadAccountMetadata(accountMetadataHash) diff --git a/src/dataStore/DripsDataProxy.sol b/src/dataStore/DripsDataProxy.sol index 5f5cd456..09ef9364 100644 --- a/src/dataStore/DripsDataProxy.sol +++ b/src/dataStore/DripsDataProxy.sol @@ -55,7 +55,7 @@ contract DripsDataProxy is Managed { uint256 senderId, bytes32 historyStartHash, bytes32 streamsHistoryHash - ) public returns (uint128 amt) { + ) public onlyProxy returns (uint128 amt) { return drips.squeezeStreams( accountId, erc20, @@ -134,6 +134,7 @@ contract DripsDataProxy is Managed { /// @return splitAmt The amount split to the account's splits receivers function split(uint256 accountId, IERC20 erc20) public + onlyProxy returns (uint128 collectableAmt, uint128 splitAmt) { bytes32 splitsHash = drips.splitsHash(accountId); diff --git a/src/dataStore/NFTDriverDataProxy.sol b/src/dataStore/NFTDriverDataProxy.sol index 64edba05..1b44b496 100644 --- a/src/dataStore/NFTDriverDataProxy.sol +++ b/src/dataStore/NFTDriverDataProxy.sol @@ -54,7 +54,11 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// The keys and the values are not standardized by the protocol, it's up to the users /// to establish and follow conventions to ensure compatibility with the consumers. /// @return tokenId The minted token ID. It's equal to the account ID controlled by it. - function mint(address to, bytes32 accountMetadataHash) public returns (uint256 tokenId) { + function mint(address to, bytes32 accountMetadataHash) + public + onlyProxy + returns (uint256 tokenId) + { return nftDriver.mint(to, dripsDataStore.loadAccountMetadata(accountMetadataHash)); } @@ -67,7 +71,11 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// The keys and the values are not standardized by the protocol, it's up to the users /// to establish and follow conventions to ensure compatibility with the consumers. /// @return tokenId The minted token ID. It's equal to the account ID controlled by it. - function safeMint(address to, bytes32 accountMetadataHash) public returns (uint256 tokenId) { + function safeMint(address to, bytes32 accountMetadataHash) + public + onlyProxy + returns (uint256 tokenId) + { return nftDriver.safeMint(to, dripsDataStore.loadAccountMetadata(accountMetadataHash)); } @@ -85,6 +93,7 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// The ID is calculated using `calcTokenIdWithSalt` for the caller's address and the used salt. function mintWithSalt(uint64 salt, address to, bytes32 accountMetadataHash) public + onlyProxy returns (uint256 tokenId) { bytes memory data = abi.encodeCall( @@ -108,6 +117,7 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// The ID is calculated using `calcTokenIdWithSalt` for the caller's address and the used salt. function safeMintWithSalt(uint64 salt, address to, bytes32 accountMetadataHash) public + onlyProxy returns (uint256 tokenId) { bytes memory data = abi.encodeCall( @@ -176,7 +186,7 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public returns (int128 realBalanceDelta) { + ) public onlyProxy returns (int128 realBalanceDelta) { // slither-disable-next-line unused-return (bytes32 currStreamsHash,,,,) = drips.streamsState(tokenId, erc20); bytes memory data = abi.encodeCall( @@ -218,7 +228,7 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// This is usually unwanted, because if splitting is repeated, /// funds split to themselves will be again split using the current configuration. /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. - function setSplits(uint256 tokenId, bytes32 splitsHash) public { + function setSplits(uint256 tokenId, bytes32 splitsHash) public onlyProxy { bytes memory data = abi.encodeCall(nftDriver.setSplits, (tokenId, dripsDataStore.loadSplits(splitsHash))); abi.decode(_callNFTDriver(data), ()); @@ -232,7 +242,7 @@ contract NFTDriverDataProxy is ERC2771Context, Managed { /// The token ID is equal to the account ID controlled by it. /// @param accountMetadataHash The hash of the list of account metadata, /// the actual list must be stored in DripsDataStore. - function emitAccountMetadata(uint256 tokenId, bytes32 accountMetadataHash) public { + function emitAccountMetadata(uint256 tokenId, bytes32 accountMetadataHash) public onlyProxy { bytes memory data = abi.encodeCall( nftDriver.emitAccountMetadata, (tokenId, dripsDataStore.loadAccountMetadata(accountMetadataHash)) diff --git a/src/dataStore/RepoDriverDataProxy.sol b/src/dataStore/RepoDriverDataProxy.sol index 934e4435..40b9fc71 100644 --- a/src/dataStore/RepoDriverDataProxy.sol +++ b/src/dataStore/RepoDriverDataProxy.sol @@ -103,7 +103,7 @@ contract RepoDriverDataProxy is ERC2771Context, Managed { uint32 maxEndHint1, uint32 maxEndHint2, address transferTo - ) public returns (int128 realBalanceDelta) { + ) public onlyProxy returns (int128 realBalanceDelta) { // slither-disable-next-line unused-return (bytes32 currStreamsHash,,,,) = drips.streamsState(accountId, erc20); bytes memory data = abi.encodeCall( @@ -144,7 +144,7 @@ contract RepoDriverDataProxy is ERC2771Context, Managed { /// This is usually unwanted, because if splitting is repeated, /// funds split to themselves will be again split using the current configuration. /// Splitting 100% to self effectively blocks splitting unless the configuration is updated. - function setSplits(uint256 accountId, bytes32 splitsHash) public { + function setSplits(uint256 accountId, bytes32 splitsHash) public onlyProxy { bytes memory data = abi.encodeCall(repoDriver.setSplits, (accountId, dripsDataStore.loadSplits(splitsHash))); abi.decode(_callRepoDriver(data), ()); @@ -157,7 +157,7 @@ contract RepoDriverDataProxy is ERC2771Context, Managed { /// The caller must be the owner of the account. /// @param accountMetadataHash The hash of the list of account metadata, /// the actual list must be stored in DripsDataStore. - function emitAccountMetadata(uint256 accountId, bytes32 accountMetadataHash) public { + function emitAccountMetadata(uint256 accountId, bytes32 accountMetadataHash) public onlyProxy { bytes memory data = abi.encodeCall( repoDriver.emitAccountMetadata, (accountId, dripsDataStore.loadAccountMetadata(accountMetadataHash)) diff --git a/test/AddressDriver.t.sol b/test/AddressDriver.t.sol index 06bda2a0..26b10637 100644 --- a/test/AddressDriver.t.sol +++ b/test/AddressDriver.t.sol @@ -168,4 +168,35 @@ contract AddressDriverTest is Test { assertEq(drips.splittable(accountId, erc20), amt, "Invalid splittable after give"); } + + function notDelegatedReverts() internal returns (AddressDriver driver_) { + driver_ = AddressDriver(driver.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testCalcAccountIdMustBeDelegated() public { + notDelegatedReverts().calcAccountId(user); + } + + function testCollectMustBeDelegated() public { + notDelegatedReverts().collect(erc20, user); + } + + function testGiveMustBeDelegated() public { + notDelegatedReverts().give(accountId, erc20, 0); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams( + erc20, new StreamReceiver[](0), 0, new StreamReceiver[](0), 0, 0, user + ); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(new SplitsReceiver[](0)); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(new AccountMetadata[](0)); + } } diff --git a/test/Drips.t.sol b/test/Drips.t.sol index 8b82432b..96c3f02b 100644 --- a/test/Drips.t.sol +++ b/test/Drips.t.sol @@ -717,4 +717,101 @@ contract DripsTest is Test { withdraw(1); } + + function notDelegatedReverts() internal returns (Drips drips_) { + drips_ = Drips(drips.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testRegisterDriverMustBeDelegated() public { + notDelegatedReverts().registerDriver(address(0x1234)); + } + + function testDriverAddressMustBeDelegated() public { + notDelegatedReverts().driverAddress(0); + } + + function testUpdateDriverAddressMustBeDelegated() public { + notDelegatedReverts().updateDriverAddress(driverId, address(0x1234)); + } + + function testNextDriverIdMustBeDelegated() public { + notDelegatedReverts().nextDriverId(); + } + + function testBalancesMustBeDelegated() public { + notDelegatedReverts().balances(erc20); + } + + function testWithdrawMustBeDelegated() public { + notDelegatedReverts().withdraw(erc20, address(0x1234), 0); + } + + function testReceivableStreamsCyclesMustBeDelegated() public { + notDelegatedReverts().receivableStreamsCycles(accountId, erc20); + } + + function testReceiveStreamsResultMustBeDelegated() public { + notDelegatedReverts().receiveStreams(accountId, erc20, 0); + } + + function testReceiveStreamsMustBeDelegated() public { + notDelegatedReverts().receiveStreams(accountId, erc20, 0); + } + + function testSqueezeStreamsMustBeDelegated() public { + notDelegatedReverts().squeezeStreams(0, erc20, accountId, 0, new StreamsHistory[](0)); + } + + function testSqueezeStreamsResultMustBeDelegated() public { + notDelegatedReverts().squeezeStreamsResult(0, erc20, accountId, 0, new StreamsHistory[](0)); + } + + function testSplittableMustBeDelegated() public { + notDelegatedReverts().splittable(accountId, erc20); + } + + function testSplitResultMustBeDelegated() public { + notDelegatedReverts().splitResult(accountId, splitsReceivers(), 0); + } + + function testSplitMustBeDelegated() public { + notDelegatedReverts().split(accountId, erc20, splitsReceivers()); + } + + function testCollectableMustBeDelegated() public { + notDelegatedReverts().collectable(accountId, erc20); + } + + function testCollectMustBeDelegated() public { + notDelegatedReverts().collect(accountId, erc20); + } + + function testGiveMustBeDelegated() public { + notDelegatedReverts().give(accountId, 0, erc20, 1); + } + + function testStreamsStateMustBeDelegated() public { + notDelegatedReverts().streamsState(accountId, erc20); + } + + function testBalanceAtMustBeDelegated() public { + notDelegatedReverts().balanceAt(accountId, erc20, streamsReceivers(), 0); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams(0, erc20, streamsReceivers(), 0, streamsReceivers(), 0, 0); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(accountId, splitsReceivers()); + } + + function testSplitsHashMustBeDelegated() public { + notDelegatedReverts().splitsHash(accountId); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(accountId, new AccountMetadata[](0)); + } } diff --git a/test/Giver.t.sol b/test/Giver.t.sol index 09961794..14878294 100644 --- a/test/Giver.t.sol +++ b/test/Giver.t.sol @@ -165,4 +165,21 @@ contract GiversRegistryTest is Test { vm.expectRevert("Caller is not GiversRegistry"); giversRegistry.giveImpl(accountId, erc20); } + + function notDelegatedReverts() internal returns (GiversRegistry giversRegistry_) { + giversRegistry_ = GiversRegistry(giversRegistry.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testInitializeMustBeDelegated() public { + notDelegatedReverts().initialize(); + } + + function testGiverMustBeDelegated() public { + notDelegatedReverts().giver(accountId); + } + + function testGiveMustBeDelegated() public { + notDelegatedReverts().give(accountId, erc20); + } } diff --git a/test/ImmutableSplitsDriver.t.sol b/test/ImmutableSplitsDriver.t.sol index 8af42557..a2bd257f 100644 --- a/test/ImmutableSplitsDriver.t.sol +++ b/test/ImmutableSplitsDriver.t.sol @@ -50,4 +50,17 @@ contract ImmutableSplitsDriverTest is Test { vm.expectRevert("Invalid total receivers weight"); driver.createSplits(receivers, new AccountMetadata[](0)); } + + function notDelegatedReverts() internal returns (ImmutableSplitsDriver driver_) { + driver_ = ImmutableSplitsDriver(driver.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testNextAccountIdMustBeDelegated() public { + notDelegatedReverts().nextAccountId(); + } + + function testCreateSplitsMustBeDelegated() public { + notDelegatedReverts().createSplits(new SplitsReceiver[](0), new AccountMetadata[](0)); + } } diff --git a/test/NFTDriver.t.sol b/test/NFTDriver.t.sol index 4bb529c7..39ba91c1 100644 --- a/test/NFTDriver.t.sol +++ b/test/NFTDriver.t.sol @@ -317,4 +317,103 @@ contract NFTDriverTest is Test { assertEq(drips.splittable(tokenId, erc20), amt, "Invalid splittable after give"); } + + function notDelegatedReverts() internal returns (NFTDriver driver_) { + driver_ = NFTDriver(driver.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testNextTokenIdMustBeDelegated() public { + notDelegatedReverts().nextTokenId(); + } + + function testCalcTokenIdWithSaltMustBeDelegated() public { + notDelegatedReverts().calcTokenIdWithSalt(user, 0); + } + + function testIsSaltUsedMustBeDelegated() public { + notDelegatedReverts().isSaltUsed(user, 0); + } + + function testMintMustBeDelegated() public { + notDelegatedReverts().mint(user, noMetadata()); + } + + function testSafeMintMustBeDelegated() public { + notDelegatedReverts().safeMint(user, noMetadata()); + } + + function testMintWithSaltMustBeDelegated() public { + notDelegatedReverts().mintWithSalt(0, user, noMetadata()); + } + + function testSafeMintWithSaltMustBeDelegated() public { + notDelegatedReverts().safeMintWithSalt(0, user, noMetadata()); + } + + function testCollectMustBeDelegated() public { + notDelegatedReverts().collect(0, erc20, user); + } + + function testGiveMustBeDelegated() public { + notDelegatedReverts().give(0, 0, erc20, 0); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams( + 0, erc20, new StreamReceiver[](0), 0, new StreamReceiver[](0), 0, 0, user + ); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(0, new SplitsReceiver[](0)); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(0, noMetadata()); + } + + function testBalanceOfMustBeDelegated() public { + notDelegatedReverts().balanceOf(user); + } + + function testOwnerOfMustBeDelegated() public { + notDelegatedReverts().ownerOf(0); + } + + function testTokenURIMustBeDelegated() public { + notDelegatedReverts().tokenURI(0); + } + + function testApproveMustBeDelegated() public { + notDelegatedReverts().approve(user, 0); + } + + function testGetApprovedMustBeDelegated() public { + notDelegatedReverts().getApproved(0); + } + + function testSetApprovalForAllMustBeDelegated() public { + notDelegatedReverts().setApprovalForAll(user, false); + } + + function testIsApprovedForAllMustBeDelegated() public { + notDelegatedReverts().isApprovedForAll(user, user); + } + + function testTransferFromMustBeDelegated() public { + notDelegatedReverts().transferFrom(user, user, 0); + } + + function testSafeTransferFromMustBeDelegated() public { + notDelegatedReverts().safeTransferFrom(user, user, 0); + } + + function testSafeTransferFromWithDataMustBeDelegated() public { + notDelegatedReverts().safeTransferFrom(user, user, 0, new bytes(0)); + } + + function testBurnMustBeDelegated() public { + notDelegatedReverts().burn(0); + } } diff --git a/test/RepoDriver.t.sol b/test/RepoDriver.t.sol index 6841ec94..848d693d 100644 --- a/test/RepoDriver.t.sol +++ b/test/RepoDriver.t.sol @@ -650,4 +650,63 @@ contract RepoDriverTest is Test { caller.callAs(user, address(driver), giveData); assertEq(drips.splittable(accountId, erc20), amt, "Invalid splittable after give"); } + + function notDelegatedReverts() internal returns (RepoDriver driver_) { + driver_ = RepoDriver(driver.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testCalcAccountIdMustBeDelegated() public { + notDelegatedReverts().calcAccountId(Forge.GitHub, ""); + } + + function testInitializeAnyApiOperatorMustBeDelegated() public { + notDelegatedReverts().initializeAnyApiOperator(OperatorInterface(address(0)), 0, 0); + } + + function testUpdateAnyApiOperatorMustBeDelegated() public { + notDelegatedReverts().updateAnyApiOperator(OperatorInterface(address(0)), 0, 0); + } + + function testAnyApiOperatorMustBeDelegated() public { + notDelegatedReverts().anyApiOperator(); + } + + function testOwnerOfMustBeDelegated() public { + notDelegatedReverts().ownerOf(0); + } + + function testRequestUpdateOwnerMustBeDelegated() public { + notDelegatedReverts().requestUpdateOwner(Forge.GitHub, ""); + } + + function testOnTokenTransferMustBeDelegated() public { + notDelegatedReverts().onTokenTransfer(address(0), 0, ""); + } + + function testUpdateOwnerByAnyApiMustBeDelegated() public { + notDelegatedReverts().updateOwnerByAnyApi(0, ""); + } + + function testCollectMustBeDelegated() public { + notDelegatedReverts().collect(0, erc20, user); + } + + function testGiveMustBeDelegated() public { + notDelegatedReverts().give(0, 0, erc20, 0); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams( + 0, erc20, new StreamReceiver[](0), 0, new StreamReceiver[](0), 0, 0, user + ); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(0, new SplitsReceiver[](0)); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(0, noMetadata()); + } } diff --git a/test/dataStore/AddressDriverDataProxy.t.sol b/test/dataStore/AddressDriverDataProxy.t.sol index b3ccb5c4..60900934 100644 --- a/test/dataStore/AddressDriverDataProxy.t.sol +++ b/test/dataStore/AddressDriverDataProxy.t.sol @@ -150,4 +150,21 @@ contract AddressDriverDataProxyTest is Test { }); caller.callBatched(calls); } + + function notDelegatedReverts() internal returns (AddressDriverDataProxy dataProxy_) { + dataProxy_ = AddressDriverDataProxy(dataProxy.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams(erc20, 0, 0, 0, 0, user); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(0); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(0); + } } diff --git a/test/dataStore/DripsDataProxy.t.sol b/test/dataStore/DripsDataProxy.t.sol index 2a98bb69..29339d9c 100644 --- a/test/dataStore/DripsDataProxy.t.sol +++ b/test/dataStore/DripsDataProxy.t.sol @@ -107,4 +107,17 @@ contract DripsDataProxyTest is Test { uint256 balanceAt = dataProxy.balanceAt(account, erc20, uint32(vm.getBlockTimestamp() + 1)); assertEq(balanceAt, 1, "Invalid balance"); } + + function notDelegatedReverts() internal returns (DripsDataProxy dataProxy_) { + dataProxy_ = DripsDataProxy(dataProxy.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testSqueezeStreamsMustBeDelegated() public { + notDelegatedReverts().squeezeStreams(account, erc20, account, 0, 0); + } + + function testSplitMustBeDelegated() public { + notDelegatedReverts().split(account, erc20); + } } diff --git a/test/dataStore/NFTDriverDataProxy.t.sol b/test/dataStore/NFTDriverDataProxy.t.sol index 1cf75650..20e7d575 100644 --- a/test/dataStore/NFTDriverDataProxy.t.sol +++ b/test/dataStore/NFTDriverDataProxy.t.sol @@ -199,4 +199,37 @@ contract NFTDriverDataProxyTest is Test { }); caller.callBatched(calls); } + + function notDelegatedReverts() internal returns (NFTDriverDataProxy dataProxy_) { + dataProxy_ = NFTDriverDataProxy(dataProxy.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testMintMustBeDelegated() public { + notDelegatedReverts().mint(user, 0); + } + + function testSafeMintMustBeDelegated() public { + notDelegatedReverts().safeMint(user, 0); + } + + function testMintWithSaltMustBeDelegated() public { + notDelegatedReverts().mintWithSalt(0, user, 0); + } + + function testSafeMintWithSaltMustBeDelegated() public { + notDelegatedReverts().safeMintWithSalt(0, user, 0); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams(0, erc20, 0, 0, 0, 0, user); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(0, 0); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(0, 0); + } } diff --git a/test/dataStore/RepoDriverDataProxy.t.sol b/test/dataStore/RepoDriverDataProxy.t.sol index 35368b16..692d0a57 100644 --- a/test/dataStore/RepoDriverDataProxy.t.sol +++ b/test/dataStore/RepoDriverDataProxy.t.sol @@ -167,4 +167,21 @@ contract RepoDriverDataProxyTest is Test { }); caller.callBatched(calls); } + + function notDelegatedReverts() internal returns (RepoDriverDataProxy dataProxy_) { + dataProxy_ = RepoDriverDataProxy(dataProxy.implementation()); + vm.expectRevert("Function must be called through delegatecall"); + } + + function testSetStreamsMustBeDelegated() public { + notDelegatedReverts().setStreams(0, erc20, 0, 0, 0, 0, user); + } + + function testSetSplitsMustBeDelegated() public { + notDelegatedReverts().setSplits(0, 0); + } + + function testEmitAccountMetadataMustBeDelegated() public { + notDelegatedReverts().emitAccountMetadata(0, 0); + } }