<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>arsln.eth (🧙‍♂️, 🧪)</title>
        <link>https://paragraph.com/@arsln</link>
        <description>Web3 / Ethereum developer, founder of @arslan_web3 &amp; @bardak_znaniy (telegram)</description>
        <lastBuildDate>Sun, 05 Apr 2026 16:56:08 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>arsln.eth (🧙‍♂️, 🧪)</title>
            <url>https://storage.googleapis.com/papyrus_images/3994516837d24ddc7613c90f488926fa3ae73f7721c21599ac21a50cea8c3175.jpg</url>
            <link>https://paragraph.com/@arsln</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[woow]]></title>
            <link>https://paragraph.com/@arsln/woow</link>
            <guid>p8NNfpWClNagrTwrH6ro</guid>
            <pubDate>Fri, 05 Jan 2024 14:44:59 GMT</pubDate>
            <description><![CDATA[woow]]></description>
            <content:encoded><![CDATA[<p>woow</p>]]></content:encoded>
            <author>arsln@newsletter.paragraph.com (arsln.eth (🧙‍♂️, 🧪))</author>
        </item>
        <item>
            <title><![CDATA[Lens для Solidity разработчиков]]></title>
            <link>https://paragraph.com/@arsln/lens-solidity</link>
            <guid>gQJToTKyjkCcLk7TjSau</guid>
            <pubDate>Fri, 05 Jan 2024 14:43:30 GMT</pubDate>
            <description><![CDATA[Привет! Перед тем, как ты продолжишь, я должен предупредить тебя: я не являюсь гуру solidity разработке, у меня нет багажа в несколько лет опыта и я не знаком с Виталиком Бутериным, но мне интересно изучать как устроены различные web3/DeFi протоколы, логику и инфраструктуру их смарт-контрактов. Я не буду говорить, что я знаю все о смарт-контрактах, но я обещаю, что вы узнаете много полезного и интересного из этого материала. Цель этой работы - разобраться как работает Lens и поделиться своими...]]></description>
            <content:encoded><![CDATA[<p>Привет! Перед тем, как ты продолжишь, я должен предупредить тебя: я не являюсь гуру solidity разработке, у меня нет багажа в несколько лет опыта и я не знаком с Виталиком Бутериным, но мне интересно изучать как устроены различные web3/DeFi протоколы, логику и инфраструктуру их смарт-контрактов.</p><p>Я не буду говорить, что я знаю все о смарт-контрактах, но я обещаю, что вы узнаете много полезного и интересного из этого материала.</p><p>Цель этой работы - разобраться как работает Lens и поделиться своими знаниями с другими разработчиками, которые не знакомы с этим протоколом.</p><p>Я верю в идею &quot;learn by public&quot;, поэтому создал этот материал для людей любого уровня в Solidity. Если вы junior или middle, то мои объяснения для каждого контракта будут полезны для вас. Если же вы advanced, то вы сможете двигаться со мной по порядку и углублять свои знания. Но не думайте, что этот материал будет скучным и тягучим, я постараюсь добавить немного юмора и интересных фактов, чтобы вы не заскучали.</p><p>Если вы заметили, что я где-то объяснил что-то неправильно или есть моменты, которые можно улучшить в этом материале, пожалуйста, сообщите мне об этом в телеграме. Я всегда открыт к обратной связи и готов улучшать свой материал для вас.</p><h2 id="h-chast-1-chto-takoe-lens" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Часть 1: <strong>Что такое Lens? 🌿</strong></h2><p>Я хотел рассказать вам о Lens Protocol и насколько это круто. Но, кажется, ребята из СНГ Lens сообщества меня уже опередили и написали классную статью об этом протоколе!)</p><p>Я настоятельно рекомендую тебе ее прочитать. Обрати внимание, что некоторые данные и статистики в статье могут быть актуальны на момент ее написания - 21 февраля.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/lensprotocolru.eth/jgKvqrez2VW8w4fjNjrezSo72XBbRFZEF1BJbqZrLFE">https://mirror.xyz/lensprotocolru.eth/jgKvqrez2VW8w4fjNjrezSo72XBbRFZEF1BJbqZrLFE</a></p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import {IFollowModule} from &apos;../../../interfaces/IFollowModule.sol&apos;;
import {ILensHub} from &apos;../../../interfaces/ILensHub.sol&apos;;
import {Errors} from &apos;../../../libraries/Errors.sol&apos;;
import {FeeModuleBase} from &apos;../FeeModuleBase.sol&apos;;
import {ModuleBase} from &apos;../ModuleBase.sol&apos;;
import {FollowValidatorFollowModuleBase} from &apos;./FollowValidatorFollowModuleBase.sol&apos;;
import {IERC20} from &apos;@openzeppelin/contracts/token/ERC20/IERC20.sol&apos;;
import {SafeERC20} from &apos;@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol&apos;;
import {IERC721} from &apos;@openzeppelin/contracts/token/ERC721/IERC721.sol&apos;;

/**
 * @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 &amp; treasury addresses as well as the treasury fee.
 */
contract FeeFollowModule is FeeModuleBase, FollowValidatorFollowModuleBase {
    using SafeERC20 for IERC20;

    mapping(uint256 =&gt; 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 &gt; 0)
            IERC20(currency).safeTransferFrom(follower, treasury, treasuryAmount);
    }

    /**
     * @dev We don&apos;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];
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>

<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.10;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">IFollowModule</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../../../interfaces/IFollowModule.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ILensHub</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../../../interfaces/ILensHub.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Errors</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../../../libraries/Errors.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">FeeModuleBase</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../FeeModuleBase.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ModuleBase</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../ModuleBase.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">FollowValidatorFollowModuleBase</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'./FollowValidatorFollowModuleBase.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@openzeppelin/contracts/token/ERC20/IERC20.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">SafeERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC721</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@openzeppelin/contracts/token/ERC721/IERC721.sol'</span>;

<span class="hljs-comment">/**
 * @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.
 */</span>
<span class="hljs-keyword">struct</span> <span class="hljs-title">ProfileData</span> {
    <span class="hljs-keyword">address</span> currency;
    <span class="hljs-keyword">uint256</span> amount;
    <span class="hljs-keyword">address</span> recipient;
}

<span class="hljs-comment">/**
 * @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 &#x26; treasury addresses as well as the treasury fee.
 */</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FeeFollowModule</span> <span class="hljs-keyword">is</span> <span class="hljs-title">FeeModuleBase</span>, <span class="hljs-title">FollowValidatorFollowModuleBase</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">SafeERC20</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">IERC20</span>;

    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> ProfileData) <span class="hljs-keyword">internal</span> _dataByProfile;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> hub, <span class="hljs-keyword">address</span> moduleGlobals</span>) <span class="hljs-title">FeeModuleBase</span>(<span class="hljs-params">moduleGlobals</span>) <span class="hljs-title">ModuleBase</span>(<span class="hljs-params">hub</span>) </span>{}

    <span class="hljs-comment">/**
     * @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.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initializeFollowModule</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> profileId, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>)
        <span class="hljs-title"><span class="hljs-keyword">external</span></span>
        <span class="hljs-title"><span class="hljs-keyword">override</span></span>
        <span class="hljs-title">onlyHub</span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes</span> <span class="hljs-keyword">memory</span></span>)
    </span>{
        (<span class="hljs-keyword">uint256</span> amount, <span class="hljs-keyword">address</span> currency, <span class="hljs-keyword">address</span> recipient) <span class="hljs-operator">=</span> <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">decode</span>(
            data,
            (<span class="hljs-keyword">uint256</span>, <span class="hljs-keyword">address</span>, <span class="hljs-keyword">address</span>)
        );
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>_currencyWhitelisted(currency) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> recipient <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>) <span class="hljs-operator">|</span><span class="hljs-operator">|</span> amount <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>)
            <span class="hljs-keyword">revert</span> Errors.InitParamsInvalid();

        _dataByProfile[profileId].amount <span class="hljs-operator">=</span> amount;
        _dataByProfile[profileId].currency <span class="hljs-operator">=</span> currency;
        _dataByProfile[profileId].recipient <span class="hljs-operator">=</span> recipient;
        <span class="hljs-keyword">return</span> data;
    }

    <span class="hljs-comment">/**
     * @dev Processes a follow by:
     *  1. Charging a fee
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processFollow</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> follower,
        <span class="hljs-keyword">uint256</span> profileId,
        <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> <span class="hljs-title">onlyHub</span> </span>{
        <span class="hljs-keyword">uint256</span> amount <span class="hljs-operator">=</span> _dataByProfile[profileId].amount;
        <span class="hljs-keyword">address</span> currency <span class="hljs-operator">=</span> _dataByProfile[profileId].currency;
        _validateDataIsExpected(data, currency, amount);

        (<span class="hljs-keyword">address</span> treasury, <span class="hljs-keyword">uint16</span> treasuryFee) <span class="hljs-operator">=</span> _treasuryData();
        <span class="hljs-keyword">address</span> recipient <span class="hljs-operator">=</span> _dataByProfile[profileId].recipient;
        <span class="hljs-keyword">uint256</span> treasuryAmount <span class="hljs-operator">=</span> (amount <span class="hljs-operator">*</span> treasuryFee) <span class="hljs-operator">/</span> BPS_MAX;
        <span class="hljs-keyword">uint256</span> adjustedAmount <span class="hljs-operator">=</span> amount <span class="hljs-operator">-</span> treasuryAmount;

        IERC20(currency).safeTransferFrom(follower, recipient, adjustedAmount);
        <span class="hljs-keyword">if</span> (treasuryAmount <span class="hljs-operator">></span> <span class="hljs-number">0</span>)
            IERC20(currency).safeTransferFrom(follower, treasury, treasuryAmount);
    }

    <span class="hljs-comment">/**
     * @dev We don't need to execute any additional logic on transfers in this follow module.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">followModuleTransferHook</span>(<span class="hljs-params">
        <span class="hljs-keyword">uint256</span> profileId,
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>,
        <span class="hljs-keyword">address</span> to,
        <span class="hljs-keyword">uint256</span> followNFTTokenId
    </span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">override</span></span> </span>{}

    <span class="hljs-comment">/**
     * @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.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProfileData</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> profileId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params">ProfileData <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> _dataByProfile[profileId];
    }
}
</code></pre>]]></content:encoded>
            <author>arsln@newsletter.paragraph.com (arsln.eth (🧙‍♂️, 🧪))</author>
        </item>
        <item>
            <title><![CDATA[some text here]]></title>
            <link>https://paragraph.com/@arsln/some-text-here</link>
            <guid>DRqyqeN0VriVyc54w1hH</guid>
            <pubDate>Fri, 05 Jan 2024 14:42:25 GMT</pubDate>
            <description><![CDATA[some text here]]></description>
            <content:encoded><![CDATA[<p>some text here</p>]]></content:encoded>
            <author>arsln@newsletter.paragraph.com (arsln.eth (🧙‍♂️, 🧪))</author>
        </item>
        <item>
            <title><![CDATA[Nothing on mind....]]></title>
            <link>https://paragraph.com/@arsln/nothing-on-mind</link>
            <guid>ALysWtf9zf9AuMOzkqzR</guid>
            <pubDate>Fri, 05 Jan 2024 14:41:47 GMT</pubDate>
            <description><![CDATA[Nothing on mind....]]></description>
            <content:encoded><![CDATA[<p>Nothing on mind....</p>]]></content:encoded>
            <author>arsln@newsletter.paragraph.com (arsln.eth (🧙‍♂️, 🧪))</author>
        </item>
        <item>
            <title><![CDATA[Всё о Solidity — серия статей]]></title>
            <link>https://paragraph.com/@arsln/solidity</link>
            <guid>LFz0y5nQgEyOWCzEcXHV</guid>
            <pubDate>Wed, 04 Jan 2023 06:58:33 GMT</pubDate>
            <description><![CDATA[Добро пожаловать в серию статей «Всё о Solidity»! Цель этого материала — помощь разработчикам смарт-контрактов создавать лучшие контракты и приложения поверх Ethereum или любых блокчейнов на основе EVM. Эта серия статей охватывает несколько аспектов языка смарт-контрактов Solidity, таких как адреса, мэппинги, байты, структуры и многое другое. Эта страница является отправной точкой входа в серию статей. Ниже вы найдете полный список всех статей. Приятного чтения! Перевел — @arslan_web3 | Ориги...]]></description>
            <content:encoded><![CDATA[<p>Добро пожаловать в серию статей «Всё о Solidity»!</p><p>Цель этого материала — помощь разработчикам смарт-контрактов создавать лучшие контракты и приложения поверх <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/ru/">Ethereum</a> или любых блокчейнов на основе EVM.</p><p>Эта серия статей охватывает несколько аспектов <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/latest/"><strong>языка смарт-контрактов Solidity</strong></a>, таких как адреса, мэппинги, байты, структуры и многое другое.</p><p>Эта страница является отправной точкой входа в серию статей. Ниже вы найдете полный список всех статей. Приятного чтения!</p><p>Перевел — <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://t.me/arslan_web3">@arslan_web3</a> | Оригинал — <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/coinmonks/all-about-solidity-article-series-f57be7bf6746">All About Solidity - Article Series</a></p>]]></content:encoded>
            <author>arsln@newsletter.paragraph.com (arsln.eth (🧙‍♂️, 🧪))</author>
        </item>
    </channel>
</rss>