SundaeSwap Labs has always strived to be as transparent as we can, and now that the ISO Stake Pool Operator vote has concluded, we’d like to share our learnings and lessons from the process.
Originally, the ISO SPO vote was designed to support dApp enabled wallets only. However, that would have limited wallet options to Nami and, given the current penetration of Nami, we had serious concerns about leaving out a significant portion of the community.
As a solution, we opted to borrow a page of the NFT drop playbook and to use the specific amount of ADA sent to identify a particular action. In this case, sending a specific amount of ADA to yourself would represent a ranked choice vote. We reduced the number of choices from 3 down to 2 to minimize the amount of ADA one needed to participate.
On paper, this approach sounded fine:
- With the exception of making change, very few users send ADA to themselves so the transactions would be easy to identify and the number of false positives should be low
- And while many wallets constantly generate new payment keys, wallets keep the staking keys constant.
Beginning with the Shelley era, Cardano encodes addresses as bech32 encoding of a payment address and an optional staking address. Conceptually, you can think of the address as a prefix (addr1 for mainnet and addr_test1 for testnet), followed by the payment key, followed by the staking key.
Each transaction submitted to the blockchain must also include a set of signatures. These signatures provide proof that the submitter has the right to spend the assets included in the transaction. To spend assets, the submitter only needs to sign using the payment key.
And therein lies the problem:
The Big Issue
The payment key and staking key have separate private keys. For a simple asset transfer, a signature with the staking key is not required. For the ISO SPO vote, this means that a clever adversary could potentially have used a valid payment address and a fraudulent staking address, giving the impression they controlled significantly more ADA than they actually do.
We had planned for this eventuality in the ISO; it’s why you will need a dApp-enabled wallet to retrieve ISO rewards. But in trying to make the ISO SPO vote accessible to as large a population as possible, we neglected to take this into account when we set the voting mechanism.
Given that we realized the oversight only after the ISO SPO vote had begun, we discussed mid-vote the alternatives. Again, for transparency and to hope that others can learn from our mistake, we share here the options we considered:
Option 1 — Restart with Nami Only
One option was to halt the vote and restart it and require that users use the Nami wallet. By doing this, our dApp could ensure that transactions were signed with BOTH the payment keys and the staking keys. While technically possible, it would mean that only a small fraction of the Cardano community would be deciding the election which didn’t sit well with us.
Option 2 — Require Delegation Confirmation
As a second option, we could require that all participants redelegate their stake either to the existing pool or a different pool. When delegating stake, the wallet will sign the transaction with both the payment key and the staking key. Unfortunately, you cannot also specify the amount to send, otherwise, we would have used this for the voting mechanism.
While secure, it would require that (a) everyone vote again to confirm their selection and (b) voters would be charged the fees associated with changing their delegation.
Option 3 — Watch plus Option 2
Not satisfied with either of those two options, we went with the third option which involved monitoring activity on the blockchain and acting only out of necessity if it became apparent that fraudulent activity had risen to a level where it could potentially affect the outcome. If it appeared the level of potential fraud wouldn’t have a chance of impacting the outcome, we would let the vote proceed and release a postmortem once voting ended. Releasing this document during the election would have only encouraged potential adversaries.
If we had concerns about the vote outcome, we would reserve the option of announcing the issue and requiring voters to confirm their choice via Option 2.
We felt this third option best ensured maximum community participation and the integrity of the election.
Some of the checks we then made to ensure the integrity of the vote included:
- Ensuring the staking address for all inputs and outputs matched. A lazy adversary might only change the stake address on the output UTXO and leave the original stake address on the input UTXO.
- When Smaug had the “verify your vote” feature available, we were periodically asking him if anyone had reported results other than what they expected.
- Spot checking for changed votes. We assumed the adversary would need to test their system and they may not be considering the blockchain was being monitored. While extremely rare, we did find a single staking address that voted 31 times leading us to believe that some probing was happening.
We continue to sift through the election results, but we are comfortable that we made the right choice and, more importantly, that there were no issues that rose to a level that would have affected the election outcome.
Impact on the ISO
As mentioned above, we had already spent a significant amount of time considering this issue for our ISO. The primary risk scenario we explored looks like this:
- A user stakes ADA into a pool participating in the ISO
- An adversary attempts to fraudulently claim staking rewards by submitting a transaction signed with a valid payment key, but references a fraudulent staking key
- The ISO inadvertently delivers rewards to adversary
In this scenario, an adversary could steal the rewards from any number of ISO participants.
Fortunately, the mechanism to prevent this is rather straightforward. When redeeming ISO rewards, do not accept transactions that only include the payment address. Require users sign with both their payment keys and their staking keys. This can easily be accomplished through a dApp which can require both signatures prior to submitting the transaction.
By the time the ISO launches, we expected the number of dApp enabled wallets to be significantly higher than today.
Recommendation to Other ISOs
We have already communicated this document to other teams running ISOs to bring their attention to the potential risk. In short, our recommendation is, when issuing rewards based on the staking key:
- Verify the user signed with both the payment keys and the staking keys
- Provide a dApp to redeem rewards
- Optionally use smart contracts to deliver the rewards
By sharing this information with the community, we hope to make Cardano a stronger ecosystem that teams can have confidence in building on.