misc: PublicActProxy updated to support ProtocolSharedRevenue collect module

This commit is contained in:
vicnaum
2024-05-06 22:03:49 +02:00
parent 031fa8d30e
commit cabd862cb6
2 changed files with 363 additions and 0 deletions

View File

@@ -10,6 +10,10 @@ import {CollectPublicationAction} from 'contracts/modules/act/collect/CollectPub
import {BaseProfilePublicationData, IBaseFeeCollectModule} from 'contracts/modules/interfaces/IBaseFeeCollectModule.sol';
import {MetaTxLib} from 'contracts/libraries/MetaTxLib.sol';
interface IProtocolSharedRevenueMinFeeMintModule {
function getMintFeeParams() external view returns (address, uint256);
}
/// @title PublicActProxy
/// @author LensProtocol
/// @notice This contract allows anyone to Act on a publication without holding a profile
@@ -71,6 +75,18 @@ contract PublicActProxy {
_publicCollect(publicationActionParams, signature.signer);
}
function publicSharedRevenueCollect(Types.PublicationActionParams calldata publicationActionParams) external {
_publicSharedRevenueCollect(publicationActionParams, msg.sender);
}
function publicSharedRevenueCollectWithSig(
Types.PublicationActionParams calldata publicationActionParams,
Types.EIP712Signature calldata signature
) external {
MetaTxLib.validateActSignature(signature, publicationActionParams);
_publicSharedRevenueCollect(publicationActionParams, signature.signer);
}
function nonces(address signer) public view returns (uint256) {
return _nonces[signer];
}
@@ -103,6 +119,35 @@ contract PublicActProxy {
HUB.act(publicationActionParams);
}
function _publicSharedRevenueCollect(
Types.PublicationActionParams calldata publicationActionParams,
address transactionExecutor
) internal {
address collectModule = COLLECT_PUBLICATION_ACTION
.getCollectData(
publicationActionParams.publicationActedProfileId,
publicationActionParams.publicationActedId
)
.collectModule;
BaseProfilePublicationData memory collectData = IBaseFeeCollectModule(collectModule).getBasePublicationData(
publicationActionParams.publicationActedProfileId,
publicationActionParams.publicationActedId
);
if (collectData.amount > 0) {
IERC20(collectData.currency).safeTransferFrom(transactionExecutor, address(this), collectData.amount);
IERC20(collectData.currency).safeIncreaseAllowance(collectModule, collectData.amount);
} else {
(address currency, uint256 amount) = IProtocolSharedRevenueMinFeeMintModule(collectModule)
.getMintFeeParams();
IERC20(currency).safeTransferFrom(transactionExecutor, address(this), amount);
IERC20(currency).safeIncreaseAllowance(collectModule, amount);
}
HUB.act(publicationActionParams);
}
function name() external pure returns (string memory) {
return 'PublicActProxy';
}

View File

@@ -10,6 +10,7 @@ import {CollectNFT} from 'contracts/modules/act/collect/CollectNFT.sol';
import {SimpleFeeCollectModule} from 'contracts/modules/act/collect/SimpleFeeCollectModule.sol';
import {BaseFeeCollectModuleInitData} from 'contracts/modules/interfaces/IBaseFeeCollectModule.sol';
import {MockCurrency} from 'test/mocks/MockCurrency.sol';
import {ProtocolSharedRevenueDistribution, ProtocolSharedRevenueMinFeeMintModuleInitData, ProtocolSharedRevenueMinFeeMintModule} from 'contracts/modules/act/collect/ProtocolSharedRevenueMinFeeMintModule.sol';
contract PublicActProxyTest is BaseTest {
using stdJson for string;
@@ -216,4 +217,321 @@ contract PublicActProxyTest is BaseTest {
assertTrue(collectNFT.balanceOf(nftRecipient) > 0, 'NFT recipient balance is 0');
}
function testCanPublicSharedRevenueCollectPaid() public {
vm.prank(deployer);
address revenueShareModule = address(
new ProtocolSharedRevenueMinFeeMintModule(
address(hub),
address(collectPublicationAction),
address(moduleRegistry),
address(this)
)
);
collectPublicationAction.registerCollectModule(revenueShareModule);
MockCurrency currency = new MockCurrency();
currency.mint(payer, 10 ether);
ProtocolSharedRevenueMinFeeMintModuleInitData memory exampleInitData;
exampleInitData.amount = 1 ether;
exampleInitData.collectLimit = 0;
exampleInitData.currency = address(currency);
exampleInitData.referralFee = 0;
exampleInitData.followerOnly = false;
exampleInitData.endTimestamp = 0;
exampleInitData.recipient = defaultAccount.owner;
exampleInitData.creatorClient = address(0);
Types.PostParams memory postParams = _getDefaultPostParams();
postParams.actionModules[0] = address(collectPublicationAction);
postParams.actionModulesInitDatas[0] = abi.encode(revenueShareModule, abi.encode(exampleInitData));
vm.prank(defaultAccount.owner);
defaultPubId = hub.post(postParams);
collectActionParams = Types.PublicationActionParams({
publicationActedProfileId: defaultAccount.profileId,
publicationActedId: defaultPubId,
actorProfileId: publicProfile.profileId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
actionModuleAddress: address(collectPublicationAction),
actionModuleData: abi.encode(nftRecipient, abi.encode(currency, exampleInitData.amount, address(0)))
});
vm.startPrank(payer);
currency.approve(address(publicActProxy), exampleInitData.amount);
publicActProxy.publicSharedRevenueCollect(collectActionParams);
vm.stopPrank();
CollectNFT collectNFT = CollectNFT(
CollectPublicationAction(collectPublicationAction)
.getCollectData(defaultAccount.profileId, defaultPubId)
.collectNFT
);
assertTrue(collectNFT.balanceOf(nftRecipient) > 0, 'NFT recipient balance is 0');
}
function testCanPublicSharedRevenueCollectPaidWithSig() public {
vm.prank(deployer);
address revenueShareModule = address(
new ProtocolSharedRevenueMinFeeMintModule(
address(hub),
address(collectPublicationAction),
address(moduleRegistry),
address(this)
)
);
collectPublicationAction.registerCollectModule(revenueShareModule);
MockCurrency currency = new MockCurrency();
currency.mint(payer, 10 ether);
ProtocolSharedRevenueMinFeeMintModuleInitData memory exampleInitData;
exampleInitData.amount = 1 ether;
exampleInitData.collectLimit = 0;
exampleInitData.currency = address(currency);
exampleInitData.referralFee = 0;
exampleInitData.followerOnly = false;
exampleInitData.endTimestamp = 0;
exampleInitData.recipient = defaultAccount.owner;
exampleInitData.creatorClient = address(0);
Types.PostParams memory postParams = _getDefaultPostParams();
postParams.actionModules[0] = address(collectPublicationAction);
postParams.actionModulesInitDatas[0] = abi.encode(revenueShareModule, abi.encode(exampleInitData));
vm.prank(defaultAccount.owner);
defaultPubId = hub.post(postParams);
collectActionParams = Types.PublicationActionParams({
publicationActedProfileId: defaultAccount.profileId,
publicationActedId: defaultPubId,
actorProfileId: publicProfile.profileId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
actionModuleAddress: address(collectPublicationAction),
actionModuleData: abi.encode(nftRecipient, abi.encode(currency, exampleInitData.amount, address(0)))
});
vm.prank(payer);
currency.approve(address(publicActProxy), exampleInitData.amount);
domainSeparator = keccak256(
abi.encode(
Typehash.EIP712_DOMAIN,
keccak256('PublicActProxy'),
MetaTxLib.EIP712_DOMAIN_VERSION_HASH,
block.chainid,
address(publicActProxy)
)
);
publicActProxy.publicSharedRevenueCollectWithSig({
publicationActionParams: collectActionParams,
signature: _getSigStruct({
pKey: payerPk,
digest: _getActTypedDataHash(collectActionParams, publicActProxy.nonces(payer), type(uint256).max),
deadline: type(uint256).max
})
});
CollectNFT collectNFT = CollectNFT(
CollectPublicationAction(collectPublicationAction)
.getCollectData(defaultAccount.profileId, defaultPubId)
.collectNFT
);
assertTrue(collectNFT.balanceOf(nftRecipient) > 0, 'NFT recipient balance is 0');
}
function testCanPublicSharedRevenueCollectFree() public {
address creatorClient = makeAddr('CREATOR_CLIENT');
address executorClient = makeAddr('EXECUTOR_CLIENT');
uint256 mintFee = 10 ether;
vm.prank(deployer);
address revenueShareModule = address(
new ProtocolSharedRevenueMinFeeMintModule(
address(hub),
address(collectPublicationAction),
address(moduleRegistry),
address(this)
)
);
collectPublicationAction.registerCollectModule(revenueShareModule);
MockCurrency currency = new MockCurrency();
currency.mint(payer, mintFee);
ProtocolSharedRevenueMinFeeMintModule(revenueShareModule).setMintFeeParams(address(currency), mintFee);
ProtocolSharedRevenueMinFeeMintModule(revenueShareModule).setProtocolSharedRevenueDistribution(
ProtocolSharedRevenueDistribution({
creatorSplit: 5000,
protocolSplit: 2000,
creatorClientSplit: 1500,
executorClientSplit: 1500
})
);
ProtocolSharedRevenueMinFeeMintModuleInitData memory exampleInitData;
exampleInitData.amount = 0 ether;
exampleInitData.collectLimit = 0;
exampleInitData.currency = address(0);
exampleInitData.referralFee = 0;
exampleInitData.followerOnly = false;
exampleInitData.endTimestamp = 0;
exampleInitData.recipient = defaultAccount.owner;
exampleInitData.creatorClient = creatorClient;
Types.PostParams memory postParams = _getDefaultPostParams();
postParams.actionModules[0] = address(collectPublicationAction);
postParams.actionModulesInitDatas[0] = abi.encode(revenueShareModule, abi.encode(exampleInitData));
vm.prank(defaultAccount.owner);
defaultPubId = hub.post(postParams);
collectActionParams = Types.PublicationActionParams({
publicationActedProfileId: defaultAccount.profileId,
publicationActedId: defaultPubId,
actorProfileId: publicProfile.profileId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
actionModuleAddress: address(collectPublicationAction),
actionModuleData: abi.encode(
nftRecipient,
abi.encode(exampleInitData.currency, exampleInitData.amount, executorClient)
)
});
vm.startPrank(payer);
currency.approve(address(publicActProxy), mintFee);
publicActProxy.publicSharedRevenueCollect(collectActionParams);
vm.stopPrank();
CollectNFT collectNFT = CollectNFT(
CollectPublicationAction(collectPublicationAction)
.getCollectData(defaultAccount.profileId, defaultPubId)
.collectNFT
);
assertTrue(collectNFT.balanceOf(nftRecipient) > 0, 'NFT recipient balance is 0');
assertEq(currency.balanceOf(defaultAccount.owner), (mintFee * 5000) / 10000, 'Creator balance is incorrect');
assertEq(
currency.balanceOf(hub.getTreasury()),
(mintFee * 2000) / 10000,
'Protocol treasury client balance is incorrect'
);
assertEq(currency.balanceOf(creatorClient), (mintFee * 1500) / 10000, 'Creator client balance is incorrect');
assertEq(currency.balanceOf(executorClient), (mintFee * 1500) / 10000, 'Executor client balance is incorrect');
}
function testCanPublicSharedRevenueCollectFreeWithSig() public {
address creatorClient = makeAddr('CREATOR_CLIENT');
address executorClient = makeAddr('EXECUTOR_CLIENT');
uint256 mintFee = 10 ether;
vm.prank(deployer);
address revenueShareModule = address(
new ProtocolSharedRevenueMinFeeMintModule(
address(hub),
address(collectPublicationAction),
address(moduleRegistry),
address(this)
)
);
collectPublicationAction.registerCollectModule(revenueShareModule);
MockCurrency currency = new MockCurrency();
currency.mint(payer, mintFee);
ProtocolSharedRevenueMinFeeMintModule(revenueShareModule).setMintFeeParams(address(currency), mintFee);
ProtocolSharedRevenueMinFeeMintModule(revenueShareModule).setProtocolSharedRevenueDistribution(
ProtocolSharedRevenueDistribution({
creatorSplit: 5000,
protocolSplit: 2000,
creatorClientSplit: 1500,
executorClientSplit: 1500
})
);
ProtocolSharedRevenueMinFeeMintModuleInitData memory exampleInitData;
exampleInitData.amount = 0 ether;
exampleInitData.collectLimit = 0;
exampleInitData.currency = address(0);
exampleInitData.referralFee = 0;
exampleInitData.followerOnly = false;
exampleInitData.endTimestamp = 0;
exampleInitData.recipient = defaultAccount.owner;
exampleInitData.creatorClient = creatorClient;
Types.PostParams memory postParams = _getDefaultPostParams();
postParams.actionModules[0] = address(collectPublicationAction);
postParams.actionModulesInitDatas[0] = abi.encode(revenueShareModule, abi.encode(exampleInitData));
vm.prank(defaultAccount.owner);
defaultPubId = hub.post(postParams);
collectActionParams = Types.PublicationActionParams({
publicationActedProfileId: defaultAccount.profileId,
publicationActedId: defaultPubId,
actorProfileId: publicProfile.profileId,
referrerProfileIds: _emptyUint256Array(),
referrerPubIds: _emptyUint256Array(),
actionModuleAddress: address(collectPublicationAction),
actionModuleData: abi.encode(
nftRecipient,
abi.encode(exampleInitData.currency, exampleInitData.amount, executorClient)
)
});
vm.startPrank(payer);
currency.approve(address(publicActProxy), mintFee);
vm.stopPrank();
domainSeparator = keccak256(
abi.encode(
Typehash.EIP712_DOMAIN,
keccak256('PublicActProxy'),
MetaTxLib.EIP712_DOMAIN_VERSION_HASH,
block.chainid,
address(publicActProxy)
)
);
publicActProxy.publicSharedRevenueCollectWithSig({
publicationActionParams: collectActionParams,
signature: _getSigStruct({
pKey: payerPk,
digest: _getActTypedDataHash(collectActionParams, publicActProxy.nonces(payer), type(uint256).max),
deadline: type(uint256).max
})
});
CollectNFT collectNFT = CollectNFT(
CollectPublicationAction(collectPublicationAction)
.getCollectData(defaultAccount.profileId, defaultPubId)
.collectNFT
);
assertTrue(collectNFT.balanceOf(nftRecipient) > 0, 'NFT recipient balance is 0');
assertEq(currency.balanceOf(defaultAccount.owner), (mintFee * 5000) / 10000, 'Creator balance is incorrect');
assertEq(
currency.balanceOf(hub.getTreasury()),
(mintFee * 2000) / 10000,
'Protocol treasury client balance is incorrect'
);
assertEq(currency.balanceOf(creatorClient), (mintFee * 1500) / 10000, 'Creator client balance is incorrect');
assertEq(currency.balanceOf(executorClient), (mintFee * 1500) / 10000, 'Executor client balance is incorrect');
}
}