diff --git a/src/IntuitionFeeProxy.sol b/src/IntuitionFeeProxy.sol index 35993d7..3c795fb 100644 --- a/src/IntuitionFeeProxy.sol +++ b/src/IntuitionFeeProxy.sol @@ -208,6 +208,8 @@ contract IntuitionFeeProxy { uint256[] calldata assets, uint256 curveId ) external payable returns (bytes32[] memory atomIds) { + _validateReceiver(receiver); + if (data.length != assets.length) { revert Errors.IntuitionFeeProxy_WrongArrayLengths(); } @@ -271,6 +273,8 @@ contract IntuitionFeeProxy { uint256[] calldata assets, uint256 curveId ) external payable returns (bytes32[] memory tripleIds) { + _validateReceiver(receiver); + if (subjectIds.length != predicateIds.length || predicateIds.length != objectIds.length || objectIds.length != assets.length) { @@ -337,6 +341,8 @@ contract IntuitionFeeProxy { uint256 curveId, uint256 minShares ) external payable returns (uint256 shares) { + _validateReceiver(receiver); + // Must send more than just the fixed fee if (msg.value <= depositFixedFee) { revert Errors.IntuitionFeeProxy_InsufficientValue(); @@ -384,6 +390,8 @@ contract IntuitionFeeProxy { uint256[] calldata assets, uint256[] calldata minShares ) external payable returns (uint256[] memory shares) { + _validateReceiver(receiver); + if (termIds.length != curveIds.length || curveIds.length != assets.length || assets.length != minShares.length) { @@ -483,6 +491,13 @@ contract IntuitionFeeProxy { } } + /// @notice Ensure fee proxy users cannot send their shares to an arbitrary receiver + function _validateReceiver(address receiver) internal view { + if (receiver != msg.sender) { + revert Errors.IntuitionFeeProxy_ReceiverMustBeSender(); + } + } + /// @notice Sum array of uint256 values /// @param arr Array to sum /// @return sum Total sum diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 839d842..306d14e 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -27,4 +27,7 @@ library Errors { /// @notice Fee percentage exceeds maximum allowed (100%) error IntuitionFeeProxy_FeePercentageTooHigh(); + + /// @notice Receiver must match the transaction sender + error IntuitionFeeProxy_ReceiverMustBeSender(); } diff --git a/test/IntuitionFeeProxy.test.ts b/test/IntuitionFeeProxy.test.ts index 9365c5e..74411c5 100644 --- a/test/IntuitionFeeProxy.test.ts +++ b/test/IntuitionFeeProxy.test.ts @@ -266,6 +266,18 @@ describe("IntuitionFeeProxy", function () { proxy.connect(user).createAtoms(user.address, data, assets, curveId, { value: ethers.parseEther("0.01") }) ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_InsufficientValue"); }); + + it("Should reject createAtoms when receiver is not the sender", async function () { + const { proxy, user, nonAdmin } = await loadFixture(deployFixture); + + const data = [ethers.toUtf8Bytes("ipfs://atom1")]; + const assets = [0n]; + const curveId = 1n; + + await expect( + proxy.connect(user).createAtoms(nonAdmin.address, data, assets, curveId) + ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_ReceiverMustBeSender"); + }); }); describe("Proxy Functions - createTriples", function () { @@ -308,6 +320,20 @@ describe("IntuitionFeeProxy", function () { proxy.connect(user).createTriples(user.address, subjectIds, predicateIds, objectIds, assets, curveId, { value: ethers.parseEther("10") }) ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_WrongArrayLengths"); }); + + it("Should reject createTriples when receiver is not the sender", async function () { + const { proxy, user, nonAdmin } = await loadFixture(deployFixture); + + const subjectIds = [ethers.zeroPadValue("0x01", 32)]; + const predicateIds = [ethers.zeroPadValue("0x02", 32)]; + const objectIds = [ethers.zeroPadValue("0x03", 32)]; + const assets = [0n]; + const curveId = 1n; + + await expect( + proxy.connect(user).createTriples(nonAdmin.address, subjectIds, predicateIds, objectIds, assets, curveId) + ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_ReceiverMustBeSender"); + }); }); describe("Proxy Functions - deposit", function () { @@ -359,6 +385,17 @@ describe("IntuitionFeeProxy", function () { expect(await proxy.getMultiVaultAmountFromValue(DEPOSIT_FEE)).to.equal(0n); expect(await proxy.getMultiVaultAmountFromValue(ethers.parseEther("0.05"))).to.equal(0n); }); + + it("Should reject deposit when receiver is not the sender", async function () { + const { proxy, user, nonAdmin } = await loadFixture(deployFixture); + + const termId = ethers.zeroPadValue("0x01", 32); + const totalToSend = await proxy.getTotalDepositCost(ethers.parseEther("1")); + + await expect( + proxy.connect(user).deposit(nonAdmin.address, termId, 1n, 0n, { value: totalToSend }) + ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_ReceiverMustBeSender"); + }); }); describe("Proxy Functions - depositBatch", function () { @@ -396,6 +433,20 @@ describe("IntuitionFeeProxy", function () { proxy.connect(user).depositBatch(user.address, termIds, curveIds, assets, minShares, { value: ethers.parseEther("20") }) ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_WrongArrayLengths"); }); + + it("Should reject depositBatch when receiver is not the sender", async function () { + const { proxy, user, nonAdmin } = await loadFixture(deployFixture); + + const termIds = [ethers.zeroPadValue("0x01", 32)]; + const curveIds = [1n]; + const assets = [ethers.parseEther("1")]; + const minShares = [0n]; + const totalRequired = ethers.parseEther("1") + await proxy.calculateDepositFee(1n, ethers.parseEther("1")); + + await expect( + proxy.connect(user).depositBatch(nonAdmin.address, termIds, curveIds, assets, minShares, { value: totalRequired }) + ).to.be.revertedWithCustomError(proxy, "IntuitionFeeProxy_ReceiverMustBeSender"); + }); }); describe("View Functions (Passthrough)", function () {