mirror of
https://github.com/Rate-Limiting-Nullifier/rln-docs.git
synced 2026-01-08 23:08:09 -05:00
deploy: c98f6d2bba
This commit is contained in:
46
print.html
46
print.html
@@ -384,6 +384,50 @@ Checked that \(0 \le messageId < limit\). </p>
|
||||
<li>\(identityCommitment = Poseidon(identitySecret)\).</li>
|
||||
</ul>
|
||||
<div style="break-before: page; page-break-before: always;"></div><h1 id="smart-contract"><a class="header" href="#smart-contract">Smart-contract</a></h1>
|
||||
<p>Smart-contract plays an important role in RLN protocol. Having it may confuse you, as you can think that RLN protocol should be used on-chain. However, the registry and slashing are the only mechanisms that happen on-chain. The actual usage of RLN after a user registers, is off-chain, and if they break the rate-limit they will be slashed and removed from the registry on-chain.</p>
|
||||
<p>As it was said smart-contract only plays a registry role in the protocol. Though it's not necessary to use on-chain smart-contract registry - it's a good practice, because the best fit for RLN is <em>non-consensus anonymous environments</em>, and the only thing that should be truly/verifiably consistent is a user set, that's why to store it we need a registry, preferably on a blockchain.</p>
|
||||
<p>You can find a <a href="https://github.com/Rate-Limiting-Nullifier/rln-contract">Foundry project for the RLN registry</a> in our GitHub. It was audited internally by PSE. </p>
|
||||
<p>The project contains:</p>
|
||||
<ul>
|
||||
<li><strong>RLN.sol</strong> - main contract; functionality for registration and withdrawal (or slashing);</li>
|
||||
<li><strong>Verifier.sol</strong> & <strong>IVerifier.sol</strong> - generated contracts for zkSNARK (Groth16) verification used for withdrawal (or slashing).</li>
|
||||
</ul>
|
||||
<p>We'll focus on main components of the registry contract and we'll skip verifier, cause it was generated by SnarkJS.</p>
|
||||
<hr />
|
||||
<h2 id="registry-contract"><a class="header" href="#registry-contract">Registry contract</a></h2>
|
||||
<h3 id="constructor"><a class="header" href="#constructor">Constructor</a></h3>
|
||||
<p>Constructor gets all the necessary parameters for initialization of the contract. These parameters are immutable, so it's not possible to change it after the initialization.</p>
|
||||
<p>It takes following parameters:</p>
|
||||
<ul>
|
||||
<li>minimalDeposit: minimal membership deposit, cost of 1 message;</li>
|
||||
<li>depth: depth of the merkle tree;</li>
|
||||
<li>feePercentage: fee percentage;</li>
|
||||
<li>feeReceiver: address of the fee receiver;</li>
|
||||
<li>freezePeriod: amount of blocks for withdrawal time-lock;</li>
|
||||
<li>_token: address of the ERC20 contract;</li>
|
||||
<li>_verifier: address of the Groth16 Verifier.</li>
|
||||
</ul>
|
||||
<p>Fees play important role in the economical side of the protocol. They prevent self-slashing attack vector, by making it economically inefficient; and also fees prevent money laundering schemes.</p>
|
||||
<h3 id="registration-1"><a class="header" href="#registration-1">Registration</a></h3>
|
||||
<p>Function <strong>register</strong> is used for registration. It receives \(identityCommitment\) as the argument as well as stake amount. Then it calculate messageLimit, based on the stake amount:
|
||||
\[messageLimit = amount / MINIMAL\_DEPOSIT\] </p>
|
||||
<p>Then it stores the \(identityCommitment\) in the users' set, and emits an event. Client nodes that need to listen to the event, cause based on that they calculate \(rateCommitment\) value. It's important part, because by doing that we don't need to calculate Poseidon hash on-chain, that's not cheap.</p>
|
||||
<h3 id="withdraw--slashing"><a class="header" href="#withdraw--slashing">Withdraw | Slashing</a></h3>
|
||||
<p>There are two terms: <em>withdraw</em> and <em>slash</em> used in the RLN protocol. Let's define them:</p>
|
||||
<ul>
|
||||
<li><strong>withdraw</strong> - when the account that withdraws an \(identityCommitment\) (and stake) is the same that registered it;</li>
|
||||
<li><strong>slash</strong> - when the account that withdraws an \(identityCommitment\) (and stake) is different to the one that registered it.</li>
|
||||
</ul>
|
||||
<p>It's important to separate these terms, because in withdraw method, users don't have to pay fees. The reason is if it's the same account that's used for withdrawal, then it's clearly not a money laundering. That's not the case with slashing, and that's why users pay fee for slashing.</p>
|
||||
<p>Self slashing is not a problem, cause users will still lose some amount of their stake, so it's economically inefficient. </p>
|
||||
<p>But there was a problem with <em>self withdrawal with front-run</em>. It's when users spam and quickly remove/withdraw themselves before others can do it. The problem is solved with time-lock withdrawal: when users initialize the withdraw, their funds being locked to <strong>freezePeriod</strong> amount of blocks, giving others an opportunity to slash (slashing happens immediately).</p>
|
||||
<p>Withdraw function emits an event, and it's important for client nodes to listen to it, as they should remove the removed \(identityCommitment\) from their membership Merkle tree, because if they don't - removed user will be able to spam.</p>
|
||||
<hr />
|
||||
<h2 id="important-notes"><a class="header" href="#important-notes">Important notes</a></h2>
|
||||
<p>You may have a question - who's fees receiver. In general that's the application-level question, because the creator of RLN app may want to receive them or donate.</p>
|
||||
<p>We recommend to burn the fees.</p>
|
||||
<p>But it's important to understand - to burn (send to zero address or call the burn function in the contract of token) centralized ERC20 stablecoin tokens such as USDT or USDC is the synonymous with transferring money to these companies. What we recommend is to create another contract that'll be fee receiver. The tokens will be locked on the contract, and it'll only contain one function - burn.
|
||||
Anyone can call this burn function, and it'll swap locked tokens to the ETH on any DEX, pay for the caller gas and burn swapped ETH.</p>
|
||||
<div style="break-before: page; page-break-before: always;"></div><h1 id="uses"><a class="header" href="#uses">Uses</a></h1>
|
||||
<p>This section contains list of apps that use <strong>RLN</strong>:</p>
|
||||
<ul>
|
||||
@@ -438,7 +482,7 @@ So, the shares are: \((5, 55), (8, 70), (16, 110)\)</li>
|
||||
</ol>
|
||||
<h3 id="recovering"><a class="header" href="#recovering">Recovering</a></h3>
|
||||
<p>We can take any two shares to recover (as described in the interpolation section) the "secret" polynomial. Zero coefficient (\(a_0\)) in the recovered polynomial is the secret \(S\).</p>
|
||||
<h2 id="important-notes"><a class="header" href="#important-notes">Important notes</a></h2>
|
||||
<h2 id="important-notes-1"><a class="header" href="#important-notes-1">Important notes</a></h2>
|
||||
<p>Arithmetic in this topic is usual for us. However, in real life, <strong>SSS</strong> arithmetic is defined over some finite field. This means that all calculations are carried out modulo some big prime field. In fact, it happens by itself in Circom because the arithmetic there is defined over the finite field, too, so we don't need to do anything extra). </p>
|
||||
<div style="break-before: page; page-break-before: always;"></div><h1 id="research"><a class="header" href="#research">Research</a></h1>
|
||||
<p>In addition to production-ready <strong>circom-rln</strong> version of RLN protocol, there is also wip on <strong>RLN</strong> R&D to reduce proving time and have bigger choice of implementations.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -169,6 +169,50 @@
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="smart-contract"><a class="header" href="#smart-contract">Smart-contract</a></h1>
|
||||
<p>Smart-contract plays an important role in RLN protocol. Having it may confuse you, as you can think that RLN protocol should be used on-chain. However, the registry and slashing are the only mechanisms that happen on-chain. The actual usage of RLN after a user registers, is off-chain, and if they break the rate-limit they will be slashed and removed from the registry on-chain.</p>
|
||||
<p>As it was said smart-contract only plays a registry role in the protocol. Though it's not necessary to use on-chain smart-contract registry - it's a good practice, because the best fit for RLN is <em>non-consensus anonymous environments</em>, and the only thing that should be truly/verifiably consistent is a user set, that's why to store it we need a registry, preferably on a blockchain.</p>
|
||||
<p>You can find a <a href="https://github.com/Rate-Limiting-Nullifier/rln-contract">Foundry project for the RLN registry</a> in our GitHub. It was audited internally by PSE. </p>
|
||||
<p>The project contains:</p>
|
||||
<ul>
|
||||
<li><strong>RLN.sol</strong> - main contract; functionality for registration and withdrawal (or slashing);</li>
|
||||
<li><strong>Verifier.sol</strong> & <strong>IVerifier.sol</strong> - generated contracts for zkSNARK (Groth16) verification used for withdrawal (or slashing).</li>
|
||||
</ul>
|
||||
<p>We'll focus on main components of the registry contract and we'll skip verifier, cause it was generated by SnarkJS.</p>
|
||||
<hr />
|
||||
<h2 id="registry-contract"><a class="header" href="#registry-contract">Registry contract</a></h2>
|
||||
<h3 id="constructor"><a class="header" href="#constructor">Constructor</a></h3>
|
||||
<p>Constructor gets all the necessary parameters for initialization of the contract. These parameters are immutable, so it's not possible to change it after the initialization.</p>
|
||||
<p>It takes following parameters:</p>
|
||||
<ul>
|
||||
<li>minimalDeposit: minimal membership deposit, cost of 1 message;</li>
|
||||
<li>depth: depth of the merkle tree;</li>
|
||||
<li>feePercentage: fee percentage;</li>
|
||||
<li>feeReceiver: address of the fee receiver;</li>
|
||||
<li>freezePeriod: amount of blocks for withdrawal time-lock;</li>
|
||||
<li>_token: address of the ERC20 contract;</li>
|
||||
<li>_verifier: address of the Groth16 Verifier.</li>
|
||||
</ul>
|
||||
<p>Fees play important role in the economical side of the protocol. They prevent self-slashing attack vector, by making it economically inefficient; and also fees prevent money laundering schemes.</p>
|
||||
<h3 id="registration"><a class="header" href="#registration">Registration</a></h3>
|
||||
<p>Function <strong>register</strong> is used for registration. It receives \(identityCommitment\) as the argument as well as stake amount. Then it calculate messageLimit, based on the stake amount:
|
||||
\[messageLimit = amount / MINIMAL\_DEPOSIT\] </p>
|
||||
<p>Then it stores the \(identityCommitment\) in the users' set, and emits an event. Client nodes that need to listen to the event, cause based on that they calculate \(rateCommitment\) value. It's important part, because by doing that we don't need to calculate Poseidon hash on-chain, that's not cheap.</p>
|
||||
<h3 id="withdraw--slashing"><a class="header" href="#withdraw--slashing">Withdraw | Slashing</a></h3>
|
||||
<p>There are two terms: <em>withdraw</em> and <em>slash</em> used in the RLN protocol. Let's define them:</p>
|
||||
<ul>
|
||||
<li><strong>withdraw</strong> - when the account that withdraws an \(identityCommitment\) (and stake) is the same that registered it;</li>
|
||||
<li><strong>slash</strong> - when the account that withdraws an \(identityCommitment\) (and stake) is different to the one that registered it.</li>
|
||||
</ul>
|
||||
<p>It's important to separate these terms, because in withdraw method, users don't have to pay fees. The reason is if it's the same account that's used for withdrawal, then it's clearly not a money laundering. That's not the case with slashing, and that's why users pay fee for slashing.</p>
|
||||
<p>Self slashing is not a problem, cause users will still lose some amount of their stake, so it's economically inefficient. </p>
|
||||
<p>But there was a problem with <em>self withdrawal with front-run</em>. It's when users spam and quickly remove/withdraw themselves before others can do it. The problem is solved with time-lock withdrawal: when users initialize the withdraw, their funds being locked to <strong>freezePeriod</strong> amount of blocks, giving others an opportunity to slash (slashing happens immediately).</p>
|
||||
<p>Withdraw function emits an event, and it's important for client nodes to listen to it, as they should remove the removed \(identityCommitment\) from their membership Merkle tree, because if they don't - removed user will be able to spam.</p>
|
||||
<hr />
|
||||
<h2 id="important-notes"><a class="header" href="#important-notes">Important notes</a></h2>
|
||||
<p>You may have a question - who's fees receiver. In general that's the application-level question, because the creator of RLN app may want to receive them or donate.</p>
|
||||
<p>We recommend to burn the fees.</p>
|
||||
<p>But it's important to understand - to burn (send to zero address or call the burn function in the contract of token) centralized ERC20 stablecoin tokens such as USDT or USDC is the synonymous with transferring money to these companies. What we recommend is to create another contract that'll be fee receiver. The tokens will be locked on the contract, and it'll only contain one function - burn.
|
||||
Anyone can call this burn function, and it'll swap locked tokens to the ETH on any DEX, pay for the caller gas and burn swapped ETH.</p>
|
||||
|
||||
</main>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user