Coder Social home page Coder Social logo

polymorpher / one-wallet Goto Github PK

View Code? Open in Web Editor NEW
109.0 14.0 46.0 58.06 MB

1wallet | Modulo OTP Wallet - unconventional keyless, non-custodial wallet secured by Google Authenticator. EVM-compatible, smart contract operated, with composable security.

Home Page: https://1wallet.crazy.one

License: Apache License 2.0

JavaScript 86.84% Solidity 11.81% Shell 0.21% HTML 1.02% SCSS 0.01% Less 0.11%
cryptocurrency blockchain wallet harmony harmony-one evm ethereum crypto bitcoin otp

one-wallet's Introduction

Modulo OTP Wallet | 1wallet on Harmony

The project started as an open source project, known as 1wallet on Harmony. It was sponsored by Harmony and developed for use on Harmony. Later, it evolved into the OTP Wallet part of Modulo, a solution for secure, frictionless, programmable non-custodial wallet infrastructure.

The open source project assumes no responsibility for theft, loss, or security issues. Use it at your own risk. For commercial concerns, please contact Modulo. Examples of commercial concerns are: guidance for integration, security protection, loss prevention, service-level agreements, reliable APIs, cross-chain use cases, or custom solutions.

Overview

1wallet (OTP Wallet) is designed for people who want the best and the latest from the world of crypto, but do not want to deal with senseless "mnemonic words", "private keys", or "seed phrases".

You don't need to be technical to use 1wallet. It is:

  • Simple: to create a wallet, just scan a QR code using the Google Authenticator app
  • Secure: authorize transactions with 6-digit code from Google Authenticator. No private keys or passwords to take care of.
  • Durable: easily restore wallet by scanning QR code exported by Google Authenticator, or recover funds using another wallet.
  • Smart: configurable spending limit, composable security, and auto-recover mechanisms. Imagine a (physical) wallet that has an embedded computer - it can do a lot more than a plain old wallet that only carries your money around.

Try it at

Technical Blurb

1wallet is an unconventional keyless, non-custodial smart contract wallet.

As a smart contract wallet, it can do many things a traditional wallet couldn't do: setting up daily spending and transfer limit, recover funds using another address, automatically track tokens (ERC/HRC-20, 721, 1155), automatically interact with other smart contracts, and a lot more.

As a keyless wallet, 1wallet is protected by dynamically generated one-time-password from Google Authenticator every 30 seconds. No private key or password is stored at the client. This removes the biggest vulnerability for hacking and theft: you cannot lose private keys if you don't have it! It also removes the hassle of managing them and being forced to remember or write down a bunch of random recovery phrases.

Since Google Authenticator operates offline and is well insulated1 on your phone, it is much more secure than a private key wallet which usually stores a password protected private key on your hard drive in a file easy-to-access location, such as MetaMask. Once your wallet file is copied and your password is leaked, your money is gone.

1wallet is non-custodial. Only you, who controls the Google Authenticator that scanned the setup QR code, can access and control the wallet. The wallet's operations do not rely on any centralized server operated by any company.

1wallet is EVM compatible and may operate on multiple networks. It was first launched on Harmony network in Sep 2021

[1]: Unless you use rooted or jailbreak devices, in which case you need to take care of security insulation by yourself

Design and Technical Specification

Please visit the Wiki page: https://github.com/polymorpher/one-wallet/wiki

Quick Start

We assume you are on macOS or Linux. Windows is not supported as a development environment at this time.

First, you need to install all essential dependencies and apply a patch to one of the dependencies. To do this, simply run the following at the root directory of this project:

./scripts/setup.sh

Next, try starting a local web client:

cd code/client
yarn run dev

Follow the link from terminal (https://localhost:3000), you should now see 1wallet client in your browser, hosted locally.

For more advanced setup, such as using a locally hosted relayer (/code/relayer), the command line interface (/code/cli), and debugging the smart contract via Truffle (/code), please refer to README file in the corresponding folders:

Directory Structure

  • /code: Primary code base. Contains all code related to 1wallet.
  • /wiki: Mirroring Wiki and Protocol, so people can contribute and make pull requests.
  • /smartotp: Early research code from SmartOTP, created by Ivan Homoliak, mildly refactored by @polymorpher in ES2020 for debugging and running on Harmony network. Smart contract, testing, and authenticator code only.
  • /legacy: legacy code forked from an early TOTP demo by Quoc Le, refactored and rebuilt by @polymorpher for testing and benchmarking, and discontinued in June 2021.

Discussions

Please visit our issues page.

License

See https://github.com/polymorpher/one-wallet/blob/master/LICENSE. The license shall be governed by and construed in accordance with the laws of the State of California, United States of America. I accept services of processes by email and Telegram chats @aaronqli.

one-wallet's People

Contributors

brayden-ooi avatar cylim avatar evil-maid avatar givp avatar haolinj avatar johnwhitton avatar polymorpher avatar taoalpha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

one-wallet's Issues

Update stats badge

“global 1wallet accounts: 190”
“global 1wallet balances: 420 ONE”

link to verifiable dashboard, or the source code that calculate the numbers, or at the least an explanation on /docs.

1wallet app library

1wallet app library

The library should allow developers to onboard a user who does not yet have a wallet, or connect a user’s existing wallet to their app. The library should allow the app to

  1. create a new wallet
  2. authenticate the user,
  3. retrieve a user’s wallet information, balance, and transaction history,
  4. perform a transfer
  5. authorize a request (by signature) that may have a time-limit on its validity
  6. revoke an existing authorization

Multiple methods of integration should be provided to developers, because apps may have different user interaction flow and onboarding processes. Some methods are more complex than others and may take weeks to develop the first version. Here, we list the proposed methods by how fast we can develop these methods and make them ready for developers.

Redirect

This method is ideal for web apps to work with web-based 1wallet (https://1wallet.crazy.one).

The user is redirected to a /request endpoint of the site hosting the wallet client (e.g. https://1wallet.crazy.one/request). The specific nature of the request would be specified by GET parameters, e.g. callback URL, app name, reason, action to be performed, any specific wallet, and more. The user would be able to choose a wallet (if one is not specified), inspect the request, and click a button to grant or deny the request. In either case, the user would be redirected back to the app itself.

If the request is granted, the callback would attach information necessary for the app to further process the request, e.g. signature and data, in cases of an authorization or authentication, or transaction id, in cases of a transfer, or just a wallet address, in cases of creating a new wallet. The information should be minimally sufficient. The library itself can perform most read operations (e.g. retrieving wallet information) without using Redirect or requesting an authorization.

Wallet Connect

This method is ideal for a mobile 1wallet client to connect with a web-based app. This is discussed in detail in Part IV of #5. In fact, its core mechanism and data flow is similar to Redirect method. Evaluating this method for a second time, I find its additional complexity is only justified in the narrow scope of mobile 1wallet client working with a web-based app, because Redirect method is significantly easier to implement for a web-to-web integration, and Redirect method can be similarly implemented for a scenario connecting mobile 1wallet to mobile based app: the app could use deep link to redirect to the 1wallet mobile app (or simply open a browser link which triggers the activation of the 1wallet mobile app), and the 1wallet mobile app can perform a callback similarly to the original app.

Import

This method is ideal for apps or other web clients that intend to function as a wallet, and to perform all operations such as transfer, authorization, and signing inside the app. In these operations, OTP would still be required from the user.

The process begins by the app asking the user (via a function call to the library) to select a local file previously exported from 1wallet that contains the state of the wallet and the proofs the wallet generated. For a complete export of a standard 1wallet that has a 1-year lifespan, the file should be around 64MB. The export can be a partial export, in which case it only contains proofs needed for a subset of time ranges, and the size of the file would be substantially less. After the user selects a file, the library would process the file and essentially generates a copy of the 1wallet inside the app, and store a copy of the proofs in IndexedDB under the app’s domain. The app can then use functions from the library to perform the desired operations (subject to user’s approval using OTPs). Note that, a large amount of implementation work should be expected by using this approach, since the app would essentially have to implement the UI and user interactions related to all the operations by the app itself. The app would be unable to leverage existing 1wallet UI as in the Redirect method. The library does not provide any UI either. It only provides the core functions.

We will add export functionality to our 1wallet client soon (https://1wallet.crazy.one)

IPFS

This method serves the purpose as in the Import method. The core mechanism of this method is similar to Import, except the proofs needed by the wallet at any given point of time would be dynamically loaded from IPFS. The app still needs to get one piece of information for the library: the hseed from the client. The hseed is necessary to produce the proof needed for every operation on the wallet. The hseed is 18-26 bytes long (e.g. a hexadecimal string of 36-52 characters long), depending on the setting and version of the wallet.

This method requires the IPFS version of the implementation of Scrambled Memory Layout (revised) (#63) to function. It may take some time before we can get to it and make it work reliability.

After the above implementation is complete, we will add a feature for the user to display and copy the hseed from our 1wallet client (https://1wallet.crazy.one).

Upcoming changes v0.9.0: upgradable wallet, domain name binding, conditionally triggered auto-recovery, recover tokens

  • Upgradable wallet
  • Domain name binding
  • Conditionally triggered auto-recovery
  • Recover tokens
  1. Wallets created on or after v0.9.0 will have the following functionality: Instead of creating new wallet and migrating assets, the user will be able to upgrade their wallets by clicking a "Upgrade" button when new versions are available. After the upgrade, the user would receive a new wallet address. The old address will forward all funds received to the new address. The old address will also automatically forward all ERC721 and 1155 tokens received, but not ERC20. However, the new address will be able to pull the ERC20 tokens from the old address (with the press of a button), by causing the old address to transfer those tokens to the new address. Each wallet will keep a record of which wallet will be forwarding funds to this wallet, and whether this wallet is forwarding funds to another wallet (upon an upgrade or recovery event)
  2. Domain name binding: each wallet will keep a record of the domain name purchased and bound to this wallet, if any. This information will be displayed in "about" section of the wallet, and is retrievable through a public function on the smart contract.
  3. Conditionally triggered auto-recovery: Sending 1.0 ONE from recovery address to the wallet is only effective when the wallet has not been performing any operation for a period of 14 days. "Performing any operation" is defined as successfully completing a reveal function call without being reverted. This is to prevent abuse of the recovery functionality, so that it is more likely than not that the wallet owner truly has lost access to the wallet, otherwise the security of the wallet would be entirely delegated to the recovery address, as discussed here: #56 (comment) . This also ensures 1wallet treasury cannot tamper with users' funds if they actively use their wallets, since 1wallet treasury will be the default recovery address after v0.8.2 (#75)
  4. Recover tokens: During recovery, ERC721 and 1155 tokens will be automatically recovered to the recovery address. Automatically tracked ERC20 tokens will also be automatically recovered, but those untracked ERC20 tokens will not be. ERC20 tokens are automatically tracked when the user performs at least one transfer of the ERC20 token from the wallet. If the user received the token, but have never transferred it out, the token will not be automatically tracked. However, the recovery address can call a function on the wallet (after recovery is already done) to manually pull the tokens to the recovery address. If the recovery address is another 1wallet, that can be done by simply pressing a button on the UI.

Violating PoS protocol assumptions by 2/3+ attack (increasing a motivation by OTP-only transfers)

Although Harmony blockchain assumes up to 1/3 of malicious staking power to ensure liveness & safety of BFT, the attacker might have the motivation to stake more than this threshold, in particular more than 2/3 of the total stake.

51% attack in PoW

The classic example of violating the minimal honest threshold occurred in PoW blockchain in so-called 51% attack, where the malicious party executed inter-chain exchange, while it was able to revert the weaker blockchain even time to finality has elapsed, and thus accomplished double-spending (e.g., ETC in 2019).

2/3 attack in PoS of Harmony

While the inter-chain exchange is a potential motivation for 51% or 2/3+ attacks, on top of that Harmony contains another motivation that the attacker might benefit from: the nature of commit/reveal protocol in OneWallet using only OTPs - if the commit tx can be reverted after reveal is published, then the 2/3+ attacker can arbitrarily change the address of the transfer to malicious address(es). Assuming a single user using OneWallet will not make the motivation for this attack high. However, if there were millions of users, transferring billions of ONE token within a single staking epoch, then the motivation is substantially increased. The attacker is basically capable of reverting and replacing all OneWallet transfers within the epoch (very close to the end of the epoch). At the early beginning of the next epoch, the attacker can withdraw the funds or at least hide by some mixers.

Slashing from the stake

Even the beacon chain does not help - if attacker has more than 2/3 of the staking power, she will likely have more than 2/3 even in the beacon chain, so it does not help. When the majority attacker finishes the epoch, it is too late to slash her for signing two different blocks at the same height in a shard since the staked amount was already withdrawn and anonymized.

Example and preventive constrains

So, this potential attack should be subject to adjustment of the maximum amount for OTP-only confirmed transfer. If we were to assume 20% of the total block gas limit of the epoch attributed to OneWallet transfers and overall cost of one transfer equal to 367k (i.e., 115k for commit and 252 for the reveal) of gas, then we would end up with ~1.4M txs per epoch (80M / 367k * 2^15 * 0.2). If we were to assume the limit of OTP-confirmed transfer equal to 500$, then the overall transferred amount would be equal to 714M$, which is around 2x higher than the current value of the stake - 376M$ (0.082 * 4562251726). However, these parameters might change, and I demonstrated it only as a model example. Therefore, it is important to keep the upper limit of OTP-only transfers as low as possible (e.g., 100 USD). Also, it is important to monitor the total amount of ONE tokens transferred by OneWallet with regard to the total stake value, while keeping the total stake high enough to make such an attack improfittable (although another issue is a combination of such an attack with double-spending during inter-chain exchange).

Client v0.8.0 (wallet version 8.0) may cause funds to be unspendable and unrecoverable

This issue applies to wallets created by scanning a single OTP code. Double OTP wallets are not affected.

The client mistakenly creates the wallet expecting two OTPs to be used, even if the user did not tick "use second code to enhance security". As a result, the user never got a chance to scan the second OTP, but the wallet is generated in a way such that it is only usable with two OTPs. Therefore, the user would never be able to spend or recover funds in the wallet.

I have upgraded the client to version 0.8.1 (https://github.com/polymorpher/one-wallet/tree/v0.8.1). The problem no longer exists. I have added warning messages in the UI to alert users not to use the wallet if its version is 8.0.

The problem can be prevented with more thorough end-to-end testing. Since the issue was at the client side, the automated testing at core and smart contract levels are not sufficient. More automated tests should be added to the client as well.

REMEDY:

If your wallet is created with a recovery address, simply recover the funds by going to "Recovery" tab and click "Recover".

If your wallet is created without a recovery address and you have funds in that wallet, please reply below or contact me

TODO: 1wallet documentations and tutorials

Priority 1

  • Step-by-step guide: connect dApp to 1wallet for all 6 operations in 1wallet app library #73
  • Quick tutorial: 1wallet transfer - how does it work
  • Quick tutorial: 1wallet signing: how does it work (authorization, authentication, revocation)
  • Quick tutorial: verifying signature with smart contract wallet using EIP-1271

Priority 2

  • 1wallet app library Redirect API interfaces and requirements
  • 1wallet app library Redirect examples with mock dApp

Priority 3

  • 1wallet core documentation
  • 1wallet app library - Import step-by-step guide
  • 1wallet app library - Import usage examples with mock dApp

Priority 4

  • 1wallet relayer APIs
  • 1wallet smart contract public functions
  • 1wallet web client anatomy by components

Priority 5

Part IV. 1: Prevent man-in-the-middle attacks which attackers may steal the user's funds by using a revealed secret to forge commit and reveals using higher-priority, competing transactions

As described in the TODO list of #5 , to quote from Part IV:

Additionally, during the week of 6/21/2021, a potential man-in-the-middle attack is identified (during a conversation with @ivan-homoliak-sutd), where the attacker may stall the user's commit using an overwhelming amount of spam transactions, and insert the attacker's own commit and reveal in the same block ahead of the user's reveal using an overwhelmingly high amount of gas. A solution to completely prevent this is already found and will be implemented very soon.

It would require quite some efforts from the attacker to make the attack happen, but this is still a high-priority security issue. Here is a summary of the details from the conversation:

Ivan H, [Jun 21, 2021 at 2:32:18 PM]:
I think that I found a security issue in the current commit/reveal protocol. Assume that user just submits reveal tx with OTP and attacker front runs the user's reveal tx: she steals OTP and create malicious commit tx followed by a malicious reveal tx in the same block (by putting higher tx fees than user).

The solution reminds me the 3-stage protocol to replace rootHash in SmartOTPs bended for our purposes: 1) submit h(OTP, params), 2) submit params, 3) submit OTP. However, we do not like 3 txs and it could be reduced to 2 txs: 1) submit h(OTP, params) + params, where store both args in a list. 2) submit OTP + its proof, and find the 1st matching entry in the list. In this case the attacker can only make a later entry in the list than the user, so his entry will not match as the first, when revealing OTP.

Aaron Li:
You are right, there is a problem. It should be fixed. Nonce doesn’t completely solve it.

Assume the attacker is using the same revealed EOTP after the commit block is confirmed, but before the EOTP expires at the end of the time interval. Let’s also assume for simplicity that maxOperationsPerInterval is 1. Each time a commit is revealed, the nonce is incremented by 1 (should be 2, will revise and explain later). If an attacker commits another operation during this time period using nonce 0, he would have to have both his commit and reveal both completed before the user’s reveal is completed. That means he would have to complete both within the same and current block, otherwise the user’s reveal would take precedence and the nonce would already be incremented, which would result the attack to fail.

Now let’s consider the attacker attempting to complete both commit and reveal within the same and current block, which the user’s reveal is pending. This is a problem, since a miner can decide either way. One solution is to prevent the smart contract from allowing commit-reveal both in the same block. But a very sophisticated attacker could in theory fill in so much garbage in the block and prevent the user’s reveal from being confirmed at all, while having his own commit confirmed. With this delay, the attacker may reveal successfully in the next block.

Your method of submitting the parameters at commit time is much more reliable. I will do that, but with a modification so the hash of the parameters are submitted instead of the actual parameters, so we can use a universal commit function for multiple types of operations, and the type and parameters are not revealed during commit.
Actually, it does not prevent the said attack. Because the attacker’s new commit hash would be different. I think the commit hash has to be h(EOTP + nonce) for this to work. Nonce would be 0 in the simplest case which maxOperationsPerInterval=1

Whereupon following the exchange above, Ivan and I spent another ~40 minutes and discussed the commit tracking data structure and mechanisms. Different proposals were made. The next steps are to document these proposals and implement one of them as fast as possible since this is a high priority issue.

Clear OTP input boxes after the user types in the wrong code

One user demonstrated that after she typed the wrong code, she had to manually click each box for each digit, delete the digit inside, then type the new one. It feels painful.

It is also unclear whether the in-memory buffer is keeping more than 6-digits when this happens, even though only 6-digits are displayed.

We should automatically remove all digits and re-focus on the first digit's box when user types the wrong code. This applies to everywhere where we require OTP input (Create, Transfer, Set Recovery Address)

Contract cleanup

Now client security is implemented (mostly), the cleanup per discussion in #60 should be implemented.

No majorVersion change needed.

Withdrawing ONEs from Binance to 1wallet would always fail - the funds would be reverted back to Binance, but Binance would assume the transaction is successful and pocket the funds

A user reported his withdrawal from Binance never arrived 1wallet. Upon my investigations, the transaction is https://explorer.harmony.one/tx/0x23a85ead531a1981f84d13911ff4d1424c2ac9ae31551e4ef9dbc8379ef16255

Although the transaction is reverted, Binance did not refund the user the balance. Therefore the 60 ONEs are deducted from the user's account and pocketed by Binance.

I tried to do the same by withdrawing ~165 ONEs from my Binance account to my own 1wallet account. Surprisingly, I encountered the same issue: Binance shows my transaction was successful, and deducted my 165 ONEs from my Binance account. In reality, the transaction was also reverted. The ONEs never reached my wallet. They went back to Binance's but they did not refund it to my account.

Here is the reason that withdrawal transactions from Binance are always reverted: Binance sets a gas limit of 21000 for the transaction. Since 21000 is precisely the amount of gas required to cover only the base transaction, it would not be enough for a smart contract wallet since the wallet needs to execute code when it receives the funds (e.g. emitting an event). It would not be a problem if you sent the payment from any other wallet (e.g. the Chrome extension wallet, or other 1wallet), since by default these wallets always set a slightly higher gas limit than 21000. For example the Chrome extension wallet sets a gas limit of 25000 by default.

I have reported this issue to Binance and Harmony. In the meantime, users are advised NOT to withdraw directly from Binance to 1wallet.

Purchase NFT in Harmony daVinci marketplace directly from wallet

Support staking on Harmony from ONE Wallet

The main difference between staking from a smart contract wallet (like this one) and staking from an externally owned account is that a smart contract wallet does not have a key to sign the staking transaction. Thus, special procedures must be created to reconcile this difference if we are to support staking from ONE wallet.

To give the reader some background context, let us first examine the status quo procedure to validate a staking request from a private-key based wallet (i.e. externally owned account, or EOA). This is documented briefly in Harmony documentation. Here is a more elaborated description:

  1. first, the EOA wallet signs a staking transaction and sends an RPC request under hmy_sendrawstakingtransaction carrying a StakingTransaction.
  2. The node receiving the RPC request would invoke the RPC's handler, which performs a series of operations and eventually validates the transaction before adding it to a transaction pool
  3. During the validation in (2), the sender's signature is verified using the standard ECDSA algorithm based on the signature (r, s, v values) provided by the EOA wallet within the transaction. See 1, 2, 3, 4, and eventually 5.

Since smart contract wallets cannot keep the private key for ECDSA, it generally cannot produce ECDSA signatures unless the signing is deferred to a client which has the private key and would request approval from the user to sign. Nonetheless, the signature produced by the client would be a signature for the client's EOA wallet's address, which is not valid for the smart contract wallet's address. However, a more fundamental issue is that ONE Wallet does not have private key at the client side at all, nor uses private key anywhere (aside from being part of the composable authentication scheme in the future, which is not yet implemented and should be considered as an advanced security feature). Therefore, it is not possible to use the same procedure under RPC hmy_sendrawstakingtransaction to implement staking from ONE Wallet.

I see two three approaches to solve to this problem.

  1. Create a standard staking smart contract and a pool service protocol. Based on the contract and the protocol, establish multiple staking pools that offers staking as an on-chain service. Each staking pool would manage its own EOA wallets that aggregates the staked ONEs, and perform the actual using pre-existing RPC call (hmy_sendrawstakingtransaction) and the status quo procedure. Obviously, this approach relies on the honesty and security of the pools. If a pool is hacked, or becomes malicious and runs away with the staked ONEs, all users who staked their funds to that pool would lose their funds.

  2. Modify the EVM code and add a special function to the smart contract that allows staking as a native function call. The signature validation should be performed by calling isValidSignature function on the contract, per EIP-1271 . This approach is much more secure, but the implementation can be complex. I am not familiar with that part of the code so at this time I only know it would not be as simple as adding a precompiled contract, since this native function would call non-native function to validate the signature, and would have side effects (changing balance of the contract). This approach also requires all validators to upgrade to a new version of Harmony node once the implementation is done.

  3. See the comment below #9 (comment)

Testing

Hey there, I am looking to help test the wallet via android. If I could be of service please let me know. Thank you.

Optimize argon2 running speed (WebAssembly + C)

We need to improve the speed of argon2 so that users won't need to wait for too long to create a wallet (i.e. generate 1M leaves). The wait time is ideally <30 seconds, and should definitely be no more than 1 minute. Based on experimentation with parameter settings with equivalent difficulty but without generating hashes in batch, a running time at ~10 seconds should be achievable in a single thread. See also my notes in #64 and #65 and the quoted text below. To summarize, low hanging fruit techniques are

  • parallelization (worker + memory transfer) (some helpful notes: https://web.dev/webassembly-threads/ )
  • reduce repetitive memory operations (in C)
  • align bytes with hash block size

We can also utilize https://github.com/gpujs/gpu.js if these techniques are insufficient, but it should be very unlikely. It could also be a lot of work (to maintain) and should not be implemented unless necessary.

It should also be noted that the implementation relies on a customized Argon2 that made it more efficient for computing hashes in batch: https://github.com/polymorpher/argon2-browser. Note that there is still a lot of room for improvement in the customized version. For example, right now each hash computation still triggers a full initialization and destruction sequence in the underlying C code, which involves a large number of malloc and free. They can be improved by doing malloc and free only once for the entire batch. The javascript code could also parallelize the workload and obtain at least 2-4x speed boost for today's typical hardware. A deeper dive into the C code may also allow us to remove salt and align each input to a single 32-byte word, and optimize the code further for 32-byte blocks of input. With these improvements, it can be expected that the randomness bits can be improved to ~20 with argon2, i.e. close to ~1M as originally proposed in Client Security.

Other than these low hanging fruits, we can identify further bottleneck by comprehensively profiling and benchmarking the C code.

Stake directly from wallet via staking pool contract and participating nodes

Since #9 might take a few more weeks to implement at https://github.com/harmony-one/harmony, my thoughts on a poor man's version of staking support are summarized as below.

  1. (Upon the press of a button on the UI) ONE Wallet users will transfer ONEs to a staking contract which acts as a staking pool. The contract will record contributions from each wallet
  2. The staking contract will also record a list of participating nodes who are required to put down a deposit to participate.
  3. The nodes may set their own fees for participation. The fees will be rewarded to the node and are a percentage of the payout of the staking/delegation reward from the node.
  4. Once in a while (exact time period is to be determined), if the accumulated user contributions reach a minimum threshold, the ONEs will be distributed and loaned to participating nodes based on their credit limits. The credit limits are defined below.
  5. The credit limits of a participating node are maintained on the staking contracts. The limit for each node is the amount of deposit by the node, plus the sum of historical fees payout via staking participation. As a result, this limit will grow over time and incentivize good behavior and long term participation from participating nodes. The limit also ensures bad behavior from new participating node would not incur damage. The limit also makes it potentially more rewarding for the nodes to put down the deposit and participate, compared to just use the deposit and stake/delegate on their own.
  6. The nodes are required to stake or delegate the distribution loaned to them and report back to the contract.
  7. The participating nodes may vote to remove and ban a node if the node fails to fulfill its duty to stake/delegate, and report. The removed nodes' deposit is forfeited, and is paid back to wallets (not participating nodes).
  8. A node may withdraw from participation, and it must return all payout via staking and delegation to the contract minus its fees, before it can get back its deposit.
  9. A wallet user may withdraw its stake, and the contract will pay a variable-rate staking reward set periodically by consensus from the participating nodes.
  10. The contract may require the participating nodes to furnish additional deposit to replenish the decreased balance due to a user's withdrawal. Nodes failing to comply may be removed from the pool and have its deposit returned.

As a simplified version, we may start with only one participating node and leave all the voting mechanisms for later implementation. This simplification will also make the staking contract very easily to implement. The node essentially will be a trusted node holding all staked funds from wallet users. It may be sufficient until total wallet balance becomes high, and the usage of this feature becomes significant enough.

Upcoming changes for v0.8.2: UI updates

Upcoming changes for v0.8.2:

  • Less ambiguous wallet names
  • Smart address input box
  • ETH style address toggle
  • Mandatory recover address and 1wallet treasury

Wallet Name

Wallets will be named using three mnemonic words. Only 1 word will be displayed (with ...) in wallet listing screen. The full name will be used in Google Authenticator. The full 3-word name will also be displayed in detailed view. The address of the wallet will be abbreviated by default to save space.

image

Address Input

Addresses used in the past will be stored and suggested as input in all applicable places (such as transfer)

image

Settings

Developer related settings and tools will be hidden by default (such as relayer password and address). They can be toggled to become visible by visiting https://1wallet.crazy.one/dev. To hide them again, visit https://1wallet.crazy.one/nodev

image

Address Style

ETH-style address (a.k.a hexadecimal address, or checksum address) will be displayed when the user hovers their mouse over any address for at least 1 second. The copy button will copy the address-format currently being displayed. ETH-style address will be displayed using a slightly different color to highlight the visual difference.

image

Recovery Address

This is related to issue #72

The recovery address will become mandatory. If the user has at least one existing 1wallet, the first wallet will be chosen by default. For users creating their very first 1wallet, the default option will be 1wallet treasury, at address:

one1qtev73wafwkt5zga0pgzmw3m9ap354xnf4qlmg  (0x02F2cF45DD4bAcbA091D78502Dba3B2F431a54D3)

A warning box would be displayed to strongly advises the user to use a recovery address under their control instead of 1wallet treasury, such as one obtained from the Chrome extension wallet.

The warning will explain to the user what 1wallet treasury is: a safe-box controlled by a multi-signature DAO that requires 3 signatures from its 5 owners to authorize any transfer. If the user chooses 1wallet treasury as the recovery address, the funds can be recovered to 1wallet treasury if the user loses the authenticator, or there are bugs in the software (such as #72) that causes the wallet to be inaccessible. However, the process to reclaim the funds from the treasure may be complex.

Cannot restore 1wallet

When trying to restore the 1wallet I can input the wallet address and scan the QR code but it gets stuck at the "Restoring your wallet" page. Will not get past the "Recomputing proofs for each time interval" check.

Unreasonably large bundle size (5MB) of web client

As I was migrating code from https://github.com/hashmesan/harmony-totp , I noticed the web-client is packing up a large number of packages. The current bundle size is >5MB. This is unacceptable for production use beyond the MVP stage. I suspect many of them are unnecessary.

I will make a note here in case anyone would be interested in helping out on this.

I have already ruled out polyfill - it is not the suspect.

image

Client Security - Revision of Scrambled Memory Layout method

As pointed out by Shashank Agrawal, the current documented method does not materially increase the number of operations required for an attacker to brute-force the correct input (OTP code, or double OTP, or with Controlled Randomness). The reasoning is not complex: the attacker can simply iterate through all possible inputs, and follow the documented method to reconstruct the neighbor, and generate the Merkle Proof required as usual.

The analysis only makes sense for brute-forcing the position of the leaves. It is not the correct analysis for an attacker aiming to recover the OTP for a given timestamp.

However, the method may still be very effective in preventing brute-force attack. To see that, first consider in the context of ASIC and GPU attack. The method would be effective in preventing such attack because the whole scrambled memory layout has to be loaded in memory for each brute-force attempt, and the scrambled memory layout can be made arbitrarily large by inserting noise into the output space, it makes any ASIC and GPU attack challenging because those massive parallel devices have difficulty fitting a large volume of memory or being forced to randomly access a non-local memory space.

Now, consider if we extend the projected scrambled memory layout space (for storing chunks) to an exceedingly large space (e.g. 2^256) instead of a dense array of size 4M as documented. The space can be stored off-memory and off-disk, e.g. on IPFS, or a local virtual filesystem. The space can be shared with other users, whose data fill in the gaps and serve as the noise for the attacker. Because the real user knows the correct OTP(s), he can very efficiently retrieve the correct chunks from this large space. On the other hand, the attacker has to make one retrieval per brute-force attempt. Retrieval from IPFS (or a local filesystem) is a non-trivial operation and can take several hundred milliseconds to several seconds (or several hundred microseconds to several milliseconds, in local virtual filesystem). The attacker's brute-force attack would be bottlenecked by the retrieval operation, hence be doomed to fail.

We still need to be careful with the size of the OTP space to prevent the attacker from being able to enumerate all OTPs (hence locations) and download all possible chunks upfront. A single OTP would not be sufficient because the total size would be 10^6 * 4 * 8 bytes = 32MB. Controlled randomness cannot be used here because legitimate users would also have to make µ retrievals to validate their own enumeration on the random parameter. But consider when two OTPs are used in conjunction, the size of the space by enumeration would be 10^12 * 4 * 8 bytes = 32TB, which should be sufficient to prevent an attacker from downloading all possible chunks upfront.

Upcoming changes for v0.8.3: Human-readable domain names registration for 1wallet accounts

After a wallet is created, the user may purchase a domain name powered by crazy.one in the wallet UI to associate the wallet with that name, such that other 1wallet users can transfer funds to the domain name instead of being forced to use the long address (one1.... or 0x....) for transferring funds. A domain name can be as cheap as 1 ONE. For more details, please visit https://medium.com/harmony-one/harmony-community-launches-crazy-one-the-first-subdomain-nft-7db95bc53326

A proposed flow is as the following:

Next to the wallet's address, a "purchase" button will be displayed next to the “copy” button. The purchase button is only displayed if the wallet is not associated with a domain name. The same button is also be visible under “About” tab of the wallet.

When the user clicks the purchase button, a new screen (similar to transfer or setRecovery) is displayed to guide the user through the domain purchase step-by-step. First, the user needs to choose a name. The UI would look similar to [input box].crazy.one. The UI would give the user a quote immediately as the user types the name, and inform the user whether the domain is available or not. When the user finalizes the name, she can click the buy button, at which time the wallet will check whether the user has sufficient balance. If so, the wallet moves to the standard transfer screen with title “associate wallet with domain xxx”. The user needs to follow the standard procedure for transfer (i.e. requiring OTP input) to complete the purchase.

Prompt to Google Authenticator app when setup QR code is scanned, instead of deferring the decision to user's phone

One user reported when she scanned the QR code using the camera app on her phone, she got redirected to Duo Mobile app instead of Google Authenticator. This is problematic for three reasons:

  1. Duo Mobile app's clock is ~10 seconds off, often gives the user incorrect OTP code. This particular user reported that she "tried at least 5 times but the wallet also said the code is incorrect", so she gave up.
  2. Duo Mobile doesn't display issuer correctly ("Third Party" instead of "Harmony").
  3. Duo Mobile cannot export the entry as an QR code. The user cannot Restore the wallet from the authenticator.

Relayer Rate Limiting

Done in d5310f2

All relayer parts in #5 are implemented except for prioritization logics, which are not necessary at this stage.

Information transparency on fields in the wallet display

Questions:

  1. What does 'Expires In' mean to me? This seems to be a worrying point of transferring more currency into the wallet with an adequate description here.
  2. Daily Limit? Is this meaning buying NFTs or transferring out of the wallet per day? I assume it only means to send somewhere else. We should reassure users of this action variable.
  3. What is the relayer and lock feature? More context and info should be supplied somewhere. Maybe in a /FAQ page to avoid making extra features that may be a higher lift.

Add Beta label to UI

The demo link is visible in our docs so we should add a beta label in case people stumble upon it.

TODO before launching to a larger set of users (10k-100k people)

This document is based on v0.0.1 of ONE Wallet, released on 6/18/2021: https://github.com/polymorpher/one-wallet/tree/7e6aed60fc19b317fe733112bf18739775f05c5c/code .

I. Client Security

In v0.0.1 of ONE Wallet, the client may act on its own without any input from the authenticator. This complies with the design in Protocol v0.0.3, but is certainly undesirable. This issue makes the wallet as vulnerable as MetaMask, which is known to be prone to large scale client-side hacks. This must be improved before the wallet can be released to beta users, so we can avoid major security incidents later.

The core weakness resides in the small search space in how EOTP is generated from an OTP and several other client-side parameters (hseed, nonce). See code at

// 4 bytes for OTP, 2 bytes for nonce, 26 bytes for seed hash

Since the OTP is confined to a 6-digit numerical number, and the generation process relies on SHA256, the right OTP (and by extension, its EOTP) at any given time can be easily enumerated by brute-force, for any given leaf hash value. See for the code of doing so at

const bruteforceEOTP = ({ hseed, nonce = 0, leaf }) => {

Over the weekend of 6/18/2021 I designed several methods to address this issue, with the goal so that the client cannot act on its own without the correct OTP code from the authenticator. Different candidate methods have different security strengths, and some of them are composable (introducing multiplicative complexity) with each other. For extreme security, I also considered the use of a generic private-key signing device, Yubikey. My plan is to document these methods in detail this week and submit them for review as soon as possible. While they are being reviewed, I will implement them by the 6/30/2021, and make another iteration in the following week based on the review feedback.

Another miscellaneous issue is that the client should ensure a commit is confirmed on the blockchain, before sending out a reveal. This is necessary to prevent man-in-the-middle attacks, which the attacker may stall both the client's commit and reveal and insert the attacker's own altered commit and reveal using the revealed proofs provided by the client.

Overall, here is the TODO list (best viewed on desktop to show indentions correctly):

  • 1. Make the client resilient to brute-force attacks
    • a. Implement a new method that imposes a difficulty parameter on operation execution
      • i. Make the difficulty parameter control the extra degree of randomness in EOTP generation process
      • ii. Control the difficulty parameter such that given an OTP, it shall not take more than 5 seconds to execute.
      • iii. Ensure the difficulty parameter does not slow down the Merkle Tree generation process during wallet creation
      • iv. Restrict the randomness introduced by the difficulty parameter to a deterministic process controlled by the authenticator seed (OTP Seed), so the wallet may still be fully recovered from the authenticator.
    • b. Replace EOTP hash function with a stronger candidate, Argon2
      • i. Explain the weaknesses of alternative candidates: scrypt, bcrypt, sha256, keccak256
      • ii. Brute-force resilliance estimation utility for the candidates
    • c. Document and analyze this method and the choice of the hash function
      • #18
      • ii. Benchmark scripts and results
  • 2. Offer Double OTP as a composable authentication method for enhanced security:
    • a. Implementation
      • i. Construction at wallet creation time
      • ii. Construction after the wallet is already created
    • b. Description and analysis of its security strength in Wiki
  • 3. Make a one-time recovery EOTP residing on the client that is time-independent
  • #39

II. Basic User Interface

In v0.0.1 of ONE Wallet, the user is asked to provide a 0x... style recovery address during the wallet creation process. The user is also asked to specify a daily spending limit for the wallet (defaults to 1000 ONE). Both parameters are optional. In addition, the user is provided the option to adjust the wallet lifespan between 6 months and 2 years (defaults to 1 year).

This process creates too much friction on the user. It was suggested in a feedback session on 6/18/2021 to remove or hide the spending limit and recovery address input boxes, such that the user would ordinarily complete the creation process by a series of clicks (and one OTP input) without having to make a decision on an appropriate daily spending limit or choosing a recovery address. Thus, most (if not all) users would create a wallet with default settings (daily spending limit at 1000 ONE, and no recovery address). Afterwards, the user may adjust the daily spending limit and the recovery address on the user interfacing showing this particular wallet. This simplified creation process removes any perceived complexity or friction on the user, and reduces the burden of customer support and operations.

I concur with this suggestion. Specifically, I am more inclined towards hiding these settings such that it may only be set after the user conciously makes a decision of setting them upfront, e.g. by clicking "advanced settings", similar to the current UI for adjusting wallet lifespan.

In addition to this change, the page that allows the user to restore a wallet locally from the authenticator is yet to be implemented. The current client bundle size (~10MB before gzip, or ~2MB after gzip) needs to be reduced to ideally less than 2MB before gzip, so that an user with an average Internet connection can load the wallet within less than 2 seconds. Each second after 2 second may increase bounce rate by ~5%. See also previous issue #2

In summary, here is the TODO list:

  • #6
  • #8
  • #7
  • 4. Add buttons and a screen on wallet display page, that allow the user to increase or decrease the wallet's spending limit
    • a. If the user does not use any composable authentication method (i.e. has not set double OTP)
      • i. Bound the limit to be no less than 0, and no more than 2x of the current limit + 100 ONE.
      • ii. The new limit only takes effect on the next day.
      • iii. Provide hints that advises the user: if they want a much higher limit but do not want to wait, they should create a new wallet and set a higher limit upfront.
    • b. If the user has already set a composable authentication method, require the user to use the composable authentication method (double OTP) to adjust the limit
      • i. The new limit is no longer bounded, but only takes effects on the next day.
  • 5. Substantially reduce client bundle size
  • #11
  • #12
  • #38

III. Basic Relayer Protection

In the current release, the Test Relayer is exposed to the public. Although the Test Relayer implements basic authentication by requiring a shared secret value in every request's header, the shared secret value is provided at the client as plaintext. This means an attacker can easily spam the Relayer with frivilous wallet creation or commit requests, and deplete the small gas reserve the Relayer keeps for paying transaction gas fees on behalf of legitimate users. During beta testing, it is highly likely that at least one person out of 1000 people would attempt to do so.

While improvements on the blockchain are still pending review (e.g. harmony-one/bounties#35) to gradually and fundamentally remove the necessity of Relayer, it is imperative for us to implement protection mechanisms to provide basic resilience against typical DDOS attack such as the one described above. To do so, I plan to implement a combination of traditional techniques in web services: fingerprinting, rate-limiting, delayed response, and response prioritization. These protections are optional if any user wants to run their own Relayer, but they will be activated on the Test Relayer we provide to beta users. A helpful paper on this subject is Host Fingerprinting and Tracking on the Web: Privacy and Security Implications

Here is the TODO list:

  • 1. Compute stateless incoming request fingerprints using the hash of concatenations of geo-IP, user-agent, HTTP ACCEPT header, and wallet root hash.
  • 2. Impose rate-limits for requests based on fingerprints. Requests exceeding rate limits per fingerprint will be responded with error-429 (Too Many Requests), subject to a delay that is doubled per consecutive error-429 resposnes, starting from 1 second.
    • a. Wallet creation: 1 per minute per fingerprint, and 30 per minute globally
      • i. Implement response prioritization: if a request is capped by global rate limit, it will be placed in a priority queue instead of responded with error-429 error. A counter will be kept for the number of requests in the queue per geo-IP, user-agent, and fingerprint. When an item is placed in queue, its priority will be set to -1 multiply by the sum of the counter values for its corresponding geo-IP, user-agent, and fingerprint. The server periodically (at a small interval) picks the request with the highest priority to serve. Any request staying for more than 10 seconds is automatically removed.
    • b. Commit: 30 per minute per fingerprint
    • c. Reveal (of any kind): 30 per minute per fingerprint
    • d. Others: 6 per minute per fingerprint
  • 3. Implement response prioritization: when an incoming requests exceeds the rate limit, it will be placed in a priority queue for the type of the request. The request with the smallest The priority is determined as the following: the sum of number of requests from each of the following

IV. Smart Contract

The smart contract needs to be adjsuted to reflect the new, one-time recovery mechanism specified in Part I §3. It should also allow one-time setup of the recovery address as specified in Part II §3, as well as the daily spending limit adjustment specified in Part II §4. The double-OTP activation specified in Part I §2(a)(ii) would require the smart contract to add another root hash value1, since the Merkle Tree generated by double-OTPs would be different than the original. After activating double-OTP, all operations2 that require root hash value verification should be verified against the new root hash value instead.

[1] We keep the original root-hash value so we can still use it to identify the wallet and use it as a flag to indicate the wallet has double OTP activated.

[2] This does not include recovery.

Additionally, during the week of 6/21/2021, a potential man-in-the-middle attack is identified (during a conversation with @ivan-homoliak-sutd), where the attacker may stall the user's commit using an overwhelming amount of spam trasactions, and insert the attacker's own commit and reveal in the same block ahead of the user's reveal using an overwhelmingly high amount of gas. A solution to completely prevent this is already found and will be implemented very soon.

In summary, the TODO list is below:

  • #47
    • a. Smart contract implementation
    • b. Truffle test implementation
    • c. Protocol specification
  • 2. Implement the new recovery mechanism (Part I §3, Part II §3)
    • a. Smart contract implementation
    • b. Truffle test implementation
    • c. Protocol specification
  • 3. Implement the daily spending limit mechanism (Part II §4)
    • a. a. Smart contract implementation
    • b. Truffle test implementation
    • c. Protocol specification
  • 4. Implement activation of double OTP (Part I §2(a)(ii))
    • a. Smart contract implementation
    • b. Truffle test implementation
    • c. Protocol specification
  • 5. Wrap up reviews for two outstanding pull requests:

V. Wiki and Protocol Specification

There are substantial developments of the fundamental protocols and design since Protocol v0.0.3 and Wiki v0.1.4. The TODO list consists of the major components:

  • 1. The introduction of the new methods for client security in Part I
    • #19
    • b. Double OTP
    • c. Yubikey or other generic, tamper-proof private-key based signing device.
  • #20
  • 3. The user experience considerations and flow design in Part II
  • 4. The smart contract and protocol updates in Part IV
  • 5. Feedback from Ivan @ivan-homoliak-sutd
    • a. From review and revisions on the initial design (tens of pages)
    • b. Review and feedback on the smart contract #3 and #4
    • c. Discussions with others who are working on this project

VI. Connect Wallet with dApps

Traditionally, web dApps connects to a browser-extension wallet (e.g. MetaMask) by using an "provider" instance exposed by the wallet in the browser session. As wallets and dApps are moving towards mobile platforms, this communication architecture is replaced by a standard interface and bridged architecture, such as WalletConnect. In WalletConnect, implementation variations between different wallets are also conveniently abstracted away. This enables smart contract wallet to implement support for this universal connection method, and allow the user to connect the smart contract wallet from a dApp. After a dApp is connected, the dApp may initiate operations from its own user interface (such as buying and selling NFT, sending funds to a swap exchange), and ask the user to approve the operations in the wallet user interface, whenever approval is needed (such as sending a transaction, signing a transaction to be sent later).

Implementing WalletConnect opens doors to a wide array of applications for ONE Wallet, as long as the dApp also implements WalletConnect. However, there is no reference implementation of WalletConnect for smart wallet available aside from Argent (https://github.com/argentlabs/argent-contracts/tree/develop/contracts), which has no documentation on the workflow or the extent of support and integration. WalletConnect only provides mobile platform libraries (React Native, Swift, Kotlin) for development. To support WalletConnect, we need to make our implementation for the complete technical specification of WalletConnect.

The amount of work required for a reliable implementation is very significant. Thus, this section should be considered as optional prior to launching to beta users, and it should have lower priority than the TODO lists in Part I through V.

To reduce the implementation complexity and workload, we should also prioritize on supporting only the most common JSON-RPC method: eth_sendTransaction, which the dApp to request the wallet to send a transaction. We should also limit the initial use case for calling this method to sending funds only, as opposed to submitting arbitrary data to the blockchain.

The other JSON-RPC methods personal_sign, eth_sign, eth_signTypedData, eth_signTransaction, eth_sendRawTransaction mostly deal with non-realtime use cases which a transaction is signed at first but sent much later. They are uncommon use cases, yet they introduce a very high amount of implementation complexity - since smart contract wallets do not have the concept of "sending raw transaction", and ONE Wallet does not have the ability to send trasactions and attach arbitrary data at this time. To validate signatures, we will also need to implement the smart contract signature validation interface per EIP-1271. This will require us to create new commit-reveal methods and state-variables specifically for storing signatures and hashes of signed messages on the smart contract.

The tentative TODO list:

  • 1. Implement encrypted connection and session management, per WalletConnect spec
  • 2. Implement user interface for parsing a WalletConnect QR code (via copy-paste) and parsing the underlying wc:... connection string.

VII. Staking

DoS vulnerability in secure commit-reveal mechanism (major version 6)

Shortly after core wallet major version 6 is released (and overall version 0.4) in #56, Andrianna Polydouri and her team from Common Prefix discovered a DoS issue:

In the previous version a commit tx would require only one hash containing all the information for both merkle proof and operation's parameters. In the new version proof's hash and parameters' hash are separated and saved in the commitLocker mapping under key value hash. The reasoning behind this is that if an attacker tried to front-run upon victim's reveal tx, her attack would fail since she would try to commit under the same hash value, which is already committed to.

The attacker cannot "steal" the amount that the victim would transfer anymore, however she can easily cause DoS for any user by front-running any commit transaction and "reserving" the commitLocker[hash] with arbitrary paramsHash.

Let's say that a user wants to execute a tx and he submits a commit tx (hash, paramsHash1) for this purpose. Then the attacker will front-run this tx and first submit her commit tx (hash, paramsHash2). paramsHash2 could be just garbage. The attacker's commit tx is executed first getting the commitment under hash reserved, so resulting in user's tx to fail (cannot commit to the same hash).
Now the user should submit another commit tx with a different hash' and the same paramsHash1, but the attacker can repeat the attack. And this can be repeated again and again. The attacker cannot steal funds but she can delay user's transactions, considering she is able to front-run his transactions, for as long as she wants.

I proposed the following solution, which appears to be effective upon a preliminary review

You are right. Each commitHash should allow multiple entries, instead of just one. Each paramsHash should be accompanied with another hash, which is hash(paramsHash . eotp) - call it verificationHash

Since the attacker does not know eotp, it cannot generate a correct verificationHash. If the attacker wants to frontrun, while the real eotp is being revealed, the attacker may commit another value to commitHash with (paramsHash2, verificationHash2), with his own parameters.

We can prevent the frontrun by only allow executing the first entry that has a valid verficationHash. Since the user’s (paramsHash, verificationHash) is always commited before attacker’s (paramsHash2, verificationHash2), the attacker would be unable to get (paramsHash2, verificationHash2) executed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.