-
Notifications
You must be signed in to change notification settings - Fork 34
EIP-0017 - proxy contracts #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
33eab08
Add initial sections of eip17
anon-real ac0bbee
Fix some typos
anon-real a0411e7
Added contract structure
anon-real 69a447d
Added contract structure
anon-real 70ada51
Fix some typos
anon-real 8097b81
Fix some typos
anon-real 95c16a2
Fix some typos
anon-real f3a2a1d
Fix typo
anon-real 0de9474
Fix condition location
anon-real 7d1f4da
Fix typo
anon-real 7a8ac92
Fix typo
anon-real 88386ce
Fix typo
anon-real b90278f
Fix typo
anon-real File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,4 +52,4 @@ sheet.scala | |
| project/project/ | ||
|
|
||
| local.conf | ||
|
|
||
| .DS_Store | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| # Proxy contracts | ||
|
|
||
| * Author: anon_real | ||
| * Status: Proposed | ||
| * Created: 05-May-2021 | ||
| * License: CC0 | ||
| * Forking: not needed | ||
|
|
||
| ## Motivation | ||
|
|
||
| Outsourcing transaction generation to an external service/dApp can be useful or needed in various circumstances. For example, avoiding wallet limitations to generate any transaction on behalf of the user - [Ergo Assembler](https://github.com/anon-real/ergo-assembler) is designed for this purpose. Another example is to scale dApps to be able to fulfill many requests without double-spending or data invalidation - SigmaUSD dApp can use proxy contracts to avoid bank double-spending and ERG/USD oracle data invalidation. | ||
|
|
||
|
|
||
| ## Background | ||
| The idea of proxy contracts came to life with the [Ergo Assembler](https://github.com/anon-real/ergo-assembler) which helped dApp developments like [Ergo Auction House](https://ergoauctions.org/), [ErgoUtils](https://ergoutils.org/), and [SigmaUSD web interface](https://sigmausd.io/#/) despite not having a wallet-bridge like MetaMask (Ethereum wallet) in the ecosystem. | ||
|
|
||
| During this time, the structure of proxy contracts evolved as some malicious users tried to take advantage of some minor vulnerabilities, mostly in the [SigmaUSD dApp](https://sigmausd.io/#/). | ||
|
|
||
| ## The structure | ||
| In the beginning, the sole purpose of proxy contracts was to protect users from losing their funds (not to be cheated) when they outsource their assets to engage with some dApp. While the initial structure succeeded to achieve this, it proved to be not sufficient for the whole dApp infrastructure to work without malicious activities. | ||
|
|
||
| For example, a malicious whale tried to take advantage of this simple structure by stealing UI fees from SigmaUSD web interface developers for some period of time. This happened because the proxy contracts were simply only trying to protect users from malicious activities, not the dApp infrastructure. | ||
scalahub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The same whale tried to prevent user's requests (minting/redeeming) from being executed by the assemble service by retuning their funds as soon as funds were broadcasted in the network. This happened also because of the same reasons. | ||
|
|
||
| Generally, proxy contracts should be designed to: | ||
| - prevent dApp developers or any other attacker from taking advantage of user's funds in any manner | ||
| - preserve the integrity of the dApp by preventing attacks like the ones explained in the above examples. | ||
|
|
||
| To achieve all of the above, the below contract structure is proposed as an example: | ||
|
|
||
scalahub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ```scala | ||
| { | ||
| // dApp-specific part ensuring that user will receive what he is paying for | ||
| val properFundUsage = { | ||
| val userOut = OUTPUTS(1) | ||
| userOut.propositionBytes == fromBase64("$userAddress") && // user must be the recipient | ||
| userOut.tokens(0)._1 == fromBase64("$scTokenId") && // user must receive SigmaUSD | ||
| userOut.tokens(0)._2 >= $scAmountL && // the amount of SigmaUSD must be at least what user is paying for | ||
| HEIGHT < $timestampL // this part is always true (timestamp is the unix-timestamp at the time of the request), it will cause compiled address to differ everytime | ||
| } | ||
|
|
||
| // ensuring dApp integrity is preserved - any dApp specific condition to ensure designed procedures won't be violated | ||
| val UIFeeOk = OUTPUTS(2).propositionBytes == fromBase64("$implementor") && OUTPUTS.size == 4 // UI fee must go to UI devs not any random person who assembles the transaction | ||
| val properBank = OUTPUTS(0).tokens(2)._1 == fromBase64("$bankNFT") // the real bank box of the sigmaUSD protocol must be used so not any random person can behave as the bank box | ||
| val dAppWorksFine = properFundUsage && UIFeeOk && properBank | ||
|
|
||
| // in any case, whether assembler refuses to execute the request or the request fails for any reason, user must be able to get back his funds | ||
| val returnFunds = { | ||
| val total = INPUTS.fold(0L, {(x:Long, b:Box) => x + b.value}) - $returnFee // only refund transactions's fee must be deducted from user's funds | ||
scalahub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| OUTPUTS(0).value >= total && OUTPUTS(0).propositionBytes == fromBase64("$userAddress") // user must receive the appropriate amount | ||
| && (PK("$assemblerNodeAddr") || HEIGHT > $refundHeightThreshold) && // either dApp-specific node can return user's funds or some time (block) has to be passed first. This is useful for many reasons. | ||
anon-real marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| OUTPUTS.size == 2 // only refund box and transaction fee box is needed | ||
scalahub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| sigmaProp(dAppWorksFine || returnFunds) // either dApp must work as it is supposed to or user's funds must be returned | ||
anon-real marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| ``` | ||
| The above contract is the proxy contract of minting operation in the [SigmaUSD dApp](https://sigmausd.io/#/). Anything started with `$` in the contract must be provided to it based on the user's request at the time of compilation. | ||
|
|
||
| The contract has three main parts: | ||
| - Ensuring proper usage of user's funds, i.e., user will receive what he is paying for in proper amount without anyone being able to cheat. | ||
| - Ensuring the integrity of the dApp procesures. | ||
anon-real marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - Ensuring that user will be refunded in any case of failures. | ||
|
|
||
|
|
||
| Now we will go through some parts of the above contract which are both important and ambiguous at the first glance. | ||
|
|
||
| - `(PK("$assemblerNodeAddr") || HEIGHT > $refundHeightThreshold)`: Either dApps's specific node can refund the user (at any time) or some time has to be passed for refunding without any secrets involved. This part prevents malicious users from sending refunds to users, preventing user's request (minting, in this case) from being executed. The same logic can be used to only allow a certain (or multiple) entities to execute requests. This enables dApps to control the order of execution which makes scaling dApps possible as it allows them to control doulbe-spending and other similar problems. | ||
anon-real marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - `HEIGHT < $timestampL`: This will result in different address every time the contract is compiled. This is useful from the UI perspective to be able to track user's requests in an address-specific manner. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.