Web3 / Ethereum developer, founder of @arslan_web3 & @bardak_znaniy (telegram)
Web3 / Ethereum developer, founder of @arslan_web3 & @bardak_znaniy (telegram)

Subscribe to arsln.eth (🧙♂️, 🧪)

Subscribe to arsln.eth (🧙♂️, 🧪)
<100 subscribers
<100 subscribers
Share Dialog
Share Dialog
Привет! Перед тем, как ты продолжишь, я должен предупредить тебя: я не являюсь гуру solidity разработке, у меня нет багажа в несколько лет опыта и я не знаком с Виталиком Бутериным, но мне интересно изучать как устроены различные web3/DeFi протоколы, логику и инфраструктуру их смарт-контрактов.
Я не буду говорить, что я знаю все о смарт-контрактах, но я обещаю, что вы узнаете много полезного и интересного из этого материала.
Цель этой работы - разобраться как работает Lens и поделиться своими знаниями с другими разработчиками, которые не знакомы с этим протоколом.
Я верю в идею "learn by public", поэтому создал этот материал для людей любого уровня в Solidity. Если вы junior или middle, то мои объяснения для каждого контракта будут полезны для вас. Если же вы advanced, то вы сможете двигаться со мной по порядку и углублять свои знания. Но не думайте, что этот материал будет скучным и тягучим, я постараюсь добавить немного юмора и интересных фактов, чтобы вы не заскучали.
Если вы заметили, что я где-то объяснил что-то неправильно или есть моменты, которые можно улучшить в этом материале, пожалуйста, сообщите мне об этом в телеграме. Я всегда открыт к обратной связи и готов улучшать свой материал для вас.
Я хотел рассказать вам о Lens Protocol и насколько это круто. Но, кажется, ребята из СНГ Lens сообщества меня уже опередили и написали классную статью об этом протоколе!)
Я настоятельно рекомендую тебе ее прочитать. Обрати внимание, что некоторые данные и статистики в статье могут быть актуальны на момент ее написания - 21 февраля.
https://mirror.xyz/lensprotocolru.eth/jgKvqrez2VW8w4fjNjrezSo72XBbRFZEF1BJbqZrLFE
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {IFollowModule} from '../../../interfaces/IFollowModule.sol';
import {ILensHub} from '../../../interfaces/ILensHub.sol';
import {Errors} from '../../../libraries/Errors.sol';
import {FeeModuleBase} from '../FeeModuleBase.sol';
import {ModuleBase} from '../ModuleBase.sol';
import {FollowValidatorFollowModuleBase} from './FollowValidatorFollowModuleBase.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
/**
* @notice A struct containing the necessary data to execute follow actions on a given profile.
*
* @param currency The currency associated with this profile.
* @param amount The following cost associated with this profile.
* @param recipient The recipient address associated with this profile.
*/
struct ProfileData {
address currency;
uint256 amount;
address recipient;
}
/**
* @title FeeFollowModule
* @author Lens Protocol
*
* @notice This is a simple Lens FollowModule implementation, inheriting from the IFollowModule interface, but with additional
* variables that can be controlled by governance, such as the governance & treasury addresses as well as the treasury fee.
*/
contract FeeFollowModule is FeeModuleBase, FollowValidatorFollowModuleBase {
using SafeERC20 for IERC20;
mapping(uint256 => ProfileData) internal _dataByProfile;
constructor(address hub, address moduleGlobals) FeeModuleBase(moduleGlobals) ModuleBase(hub) {}
/**
* @notice This follow module levies a fee on follows.
*
* @param profileId The profile ID of the profile to initialize this module for.
* @param data The arbitrary data parameter, decoded into:
* address currency: The currency address, must be internally whitelisted.
* uint256 amount: The currency total amount to levy.
* address recipient: The custom recipient address to direct earnings to.
*
* @return bytes An abi encoded bytes parameter, which is the same as the passed data parameter.
*/
function initializeFollowModule(uint256 profileId, bytes calldata data)
external
override
onlyHub
returns (bytes memory)
{
(uint256 amount, address currency, address recipient) = abi.decode(
data,
(uint256, address, address)
);
if (!_currencyWhitelisted(currency) || recipient == address(0) || amount == 0)
revert Errors.InitParamsInvalid();
_dataByProfile[profileId].amount = amount;
_dataByProfile[profileId].currency = currency;
_dataByProfile[profileId].recipient = recipient;
return data;
}
/**
* @dev Processes a follow by:
* 1. Charging a fee
*/
function processFollow(
address follower,
uint256 profileId,
bytes calldata data
) external override onlyHub {
uint256 amount = _dataByProfile[profileId].amount;
address currency = _dataByProfile[profileId].currency;
_validateDataIsExpected(data, currency, amount);
(address treasury, uint16 treasuryFee) = _treasuryData();
address recipient = _dataByProfile[profileId].recipient;
uint256 treasuryAmount = (amount * treasuryFee) / BPS_MAX;
uint256 adjustedAmount = amount - treasuryAmount;
IERC20(currency).safeTransferFrom(follower, recipient, adjustedAmount);
if (treasuryAmount > 0)
IERC20(currency).safeTransferFrom(follower, treasury, treasuryAmount);
}
/**
* @dev We don't need to execute any additional logic on transfers in this follow module.
*/
function followModuleTransferHook(
uint256 profileId,
address from,
address to,
uint256 followNFTTokenId
) external override {}
/**
* @notice Returns the profile data for a given profile, or an empty struct if that profile was not initialized
* with this module.
*
* @param profileId The token ID of the profile to query.
*
* @return ProfileData The ProfileData struct mapped to that profile.
*/
function getProfileData(uint256 profileId) external view returns (ProfileData memory) {
return _dataByProfile[profileId];
}
}
Привет! Перед тем, как ты продолжишь, я должен предупредить тебя: я не являюсь гуру solidity разработке, у меня нет багажа в несколько лет опыта и я не знаком с Виталиком Бутериным, но мне интересно изучать как устроены различные web3/DeFi протоколы, логику и инфраструктуру их смарт-контрактов.
Я не буду говорить, что я знаю все о смарт-контрактах, но я обещаю, что вы узнаете много полезного и интересного из этого материала.
Цель этой работы - разобраться как работает Lens и поделиться своими знаниями с другими разработчиками, которые не знакомы с этим протоколом.
Я верю в идею "learn by public", поэтому создал этот материал для людей любого уровня в Solidity. Если вы junior или middle, то мои объяснения для каждого контракта будут полезны для вас. Если же вы advanced, то вы сможете двигаться со мной по порядку и углублять свои знания. Но не думайте, что этот материал будет скучным и тягучим, я постараюсь добавить немного юмора и интересных фактов, чтобы вы не заскучали.
Если вы заметили, что я где-то объяснил что-то неправильно или есть моменты, которые можно улучшить в этом материале, пожалуйста, сообщите мне об этом в телеграме. Я всегда открыт к обратной связи и готов улучшать свой материал для вас.
Я хотел рассказать вам о Lens Protocol и насколько это круто. Но, кажется, ребята из СНГ Lens сообщества меня уже опередили и написали классную статью об этом протоколе!)
Я настоятельно рекомендую тебе ее прочитать. Обрати внимание, что некоторые данные и статистики в статье могут быть актуальны на момент ее написания - 21 февраля.
https://mirror.xyz/lensprotocolru.eth/jgKvqrez2VW8w4fjNjrezSo72XBbRFZEF1BJbqZrLFE
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {IFollowModule} from '../../../interfaces/IFollowModule.sol';
import {ILensHub} from '../../../interfaces/ILensHub.sol';
import {Errors} from '../../../libraries/Errors.sol';
import {FeeModuleBase} from '../FeeModuleBase.sol';
import {ModuleBase} from '../ModuleBase.sol';
import {FollowValidatorFollowModuleBase} from './FollowValidatorFollowModuleBase.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
/**
* @notice A struct containing the necessary data to execute follow actions on a given profile.
*
* @param currency The currency associated with this profile.
* @param amount The following cost associated with this profile.
* @param recipient The recipient address associated with this profile.
*/
struct ProfileData {
address currency;
uint256 amount;
address recipient;
}
/**
* @title FeeFollowModule
* @author Lens Protocol
*
* @notice This is a simple Lens FollowModule implementation, inheriting from the IFollowModule interface, but with additional
* variables that can be controlled by governance, such as the governance & treasury addresses as well as the treasury fee.
*/
contract FeeFollowModule is FeeModuleBase, FollowValidatorFollowModuleBase {
using SafeERC20 for IERC20;
mapping(uint256 => ProfileData) internal _dataByProfile;
constructor(address hub, address moduleGlobals) FeeModuleBase(moduleGlobals) ModuleBase(hub) {}
/**
* @notice This follow module levies a fee on follows.
*
* @param profileId The profile ID of the profile to initialize this module for.
* @param data The arbitrary data parameter, decoded into:
* address currency: The currency address, must be internally whitelisted.
* uint256 amount: The currency total amount to levy.
* address recipient: The custom recipient address to direct earnings to.
*
* @return bytes An abi encoded bytes parameter, which is the same as the passed data parameter.
*/
function initializeFollowModule(uint256 profileId, bytes calldata data)
external
override
onlyHub
returns (bytes memory)
{
(uint256 amount, address currency, address recipient) = abi.decode(
data,
(uint256, address, address)
);
if (!_currencyWhitelisted(currency) || recipient == address(0) || amount == 0)
revert Errors.InitParamsInvalid();
_dataByProfile[profileId].amount = amount;
_dataByProfile[profileId].currency = currency;
_dataByProfile[profileId].recipient = recipient;
return data;
}
/**
* @dev Processes a follow by:
* 1. Charging a fee
*/
function processFollow(
address follower,
uint256 profileId,
bytes calldata data
) external override onlyHub {
uint256 amount = _dataByProfile[profileId].amount;
address currency = _dataByProfile[profileId].currency;
_validateDataIsExpected(data, currency, amount);
(address treasury, uint16 treasuryFee) = _treasuryData();
address recipient = _dataByProfile[profileId].recipient;
uint256 treasuryAmount = (amount * treasuryFee) / BPS_MAX;
uint256 adjustedAmount = amount - treasuryAmount;
IERC20(currency).safeTransferFrom(follower, recipient, adjustedAmount);
if (treasuryAmount > 0)
IERC20(currency).safeTransferFrom(follower, treasury, treasuryAmount);
}
/**
* @dev We don't need to execute any additional logic on transfers in this follow module.
*/
function followModuleTransferHook(
uint256 profileId,
address from,
address to,
uint256 followNFTTokenId
) external override {}
/**
* @notice Returns the profile data for a given profile, or an empty struct if that profile was not initialized
* with this module.
*
* @param profileId The token ID of the profile to query.
*
* @return ProfileData The ProfileData struct mapped to that profile.
*/
function getProfileData(uint256 profileId) external view returns (ProfileData memory) {
return _dataByProfile[profileId];
}
}
No activity yet