Hi @adi, I have a secret contract that is trying to read the state of an Ethereum contract. Specifically, I have a struct that I need to read. Is this possible or do I have to hold all relevant state in the secret contract?
Hey @pmp , great question! Unfortunately you won’t be able to read from ETH contract state and do anything with that info in the context of your secret contract. The ETH callback, if applicable, is the last part of the computation and so only after your secret contract portion of the computation is done, will trigger the final ETH callback. Hopefully this addresses your question
@pmp what is the use of ethereum state in your secret contract. We are looking for operator / relayer design patterns at times to facilitate secret contract. If you can provide more info we can potentially help with design patterns.
Hi @can, so I’m working on converting the Rock, Paper, Scissors app to Discovery. Most everything can be done within a secret contract, except handling funds when users bet on a game. My instinct was to have the moves be encrypted and stored on Enigma, while the bet amounts would be public and stored on Ethereum along with the funds.
However, I see this creating an issue where the Enigma contract can’t verify if a user has joined a game on the Ethereum contract (and committed funds) before calculating who has won, and therefore can inadvertently reveal the first user’s move.
Say that each move has two parts:
On the first move, a user starts a game on Ethereum, sends funds for their bet, and gets a game ID. Then they call the Enigma contract, passing the game ID and their encrypted move.
On the second move, a user joins a game on Ethereum and sends their funds matching the first user’s bet. Then they call the Enigma contract, passing the game ID and their encrypted move. Upon receiving the second move, the Enigma contract calculates the winner and calls the Ethereum contract passing the winning address.
Now suppose the second user doesn’t commit funds on the Ethereum contract. Instead they call the Enigma contract directly and pass their move and the game ID they want to test. The Enigma contract calculates the winner and calls the Ethereum contract. Now, the function on the Ethereum contract will likely fail because no user has joined that game, but now the second user is able to look at the failed transaction and see whether their move would have won, lost, or tied. They can keep trying moves until they know the winning move and then play the game properly.
Obviously, I can just make it so that the Ethereum function cancels the game and returns funds if the function gets called before the second player has committed funds, but that’s not ideal from the perspective of the first user. It would have been nice if Enigma was able to verify the state of an Ethereum contract before revealing information.
Alternatively, I can just keep the same design pattern as the first iteration of Rock, Paper, Scissors where all the state (including encrypted values) is kept on Ethereum and Enigma is just passed the encrypted values to do a calculation and then does a callback to an Ethereum function. But like the last version, I would still need a way to verify that the values sent to the Enigma contract are the same as what is in the state of the Ethereum contract.
I’d be happy to hear and suggestions you might have.
Hey @pmp – yes, this is a great question. This use-case is dependent on deposits on eth. So we have a few options (as you noted). The best ones (in my opinion) are…
1 - use a relayer / operator. This is dependent on users being able to encrypt their choices in such a way that the relayer isn’t able to see them. We’re currently researching the best way to do this, and should have more details soon.
2 - Have the Ethereum contract cancel the game if the secret contract function calls it as player 2 has played but didn’t pay, and thus it does not have the appropriate funds. As you noted, this is not optimal (because users all lose ENG gas and ETH gas in this process).
Interesting game concept to flush out the ENG – ETH handshake framework.
- Is it possible to implement zk-SNARKS?
- What if we mandate
It’s true that Enigma network can’t read Ethereum state (except the staking contract). Using an operator, we should be able to replicate the state of the deposit contract inside enigma. *In other words each time a user sends a TX to the deposit contract, a relayer can add that balance to a secret contract that matches the ethereum deposit contract state. In this case the sums of funds in both contracts must be equal.
If that’s the case both bets and moves can come to Enigma network encrypted. Enigma network can determine whether the bet is <= balance of the player and discard bets that exceed a player’s balance
@can just to further my understanding, the operator is like an oracle in Ethereum? just a server that watches for events on Ethereum and updates a secret contract that it has sole control of?
That can be an option - I’m not saying it’s the right one but it seems like it would address most of the problems we are facing
what would the benefit / purpose of zk here be? to conceal the payment or deposits?
And regarding the pay before play – it would be great, but as discussed we would need to use an operator or relayer to achieve this.
See here for a discussion of operators in context of ERC-777
cc @pmp this might be interesting to you too
So I’ve been thinking about the best way to go about this and I’ve realized its unnecessary to try to synchronize the game states across the two chains. Instead, all of the gameplay can take place on Enigma, and it would be completely agnostic to any betting done by anyone on Ethereum. For the Ethereum contract, betting would be open to anyone, and odds could be automatically set within the smart contract logic. This way, all players would only interact with the Enigma contract. All game state would be set by the Enigma contract on the Ethereum contract. The Enigma contract won’t need to know whether the second player has bet on the game, or any other state that is held on the Ethereum contract.
So here is how the game flow would go:
Player 1 calls newGame() Enigma. The pass their move and their address. Enigma starts a new game and creates a gameID, setting the player address and move to the state. Then Enigma calls the Ethereum contract newGame() passing the gameID.
The Ethereum contract’s newGame() function emits a NewGame event which allows it to show up on the front-end.
Anybody can make bets on the game by calling bet() passing the gameID, their bet whether player1 will win/lose/tie, and the value of their bet.
The second player will make a move by calling joinGame() on the Enigma contract, passing gameID and their move. The Enigma contract will calculate the winner and pass the game outcome to the Ethereum contract.
Now that the results are in, users that have made winning bets can withdraw their funds by calling the withdraw() function on the Ethereum contract.
For this pattern, it might make more sense to have built delays to allow for users to make bets. e.g. The second player may only join a game after a day has passed.
I could see this pattern be generally applied to all sorts of betting games. For that matter, you could have a single Ethereum contract that takes bets on many different games whose outcome is dependent on Enigma contracts. e.g. roulette, poker, crypto kitties fights, etc.
Hey @pmp, this is very cool… I have a few questions
- if non-participants can bet on the games, how could a non-participant know that the game isn’t rigged between two accounts held by the same person? For example:
- I start a game, and I bet on myself to win.
- I participate in my own game, intentionally losing
- If anyone who took the other side, I get their bet when the game resolves.
I think this is a really interesting model for games that are already taking place / possibly a way to do private prediction markets. But I think untethering play from betting could be challenging for this particular case of a two-person game with no sybil prevention.
Why did you suggest the 24 h delay? To enable time for bids to be made?
Yes, that is the reason for the delay. But you’re right, if one participant can control the outcome, no one can trust it. Back to the drawing board.
I suppose you could limit the betting to the addresses who are in the game. However, then I would have to do verification of the addresses within the Enigma contract and pass them out to the Ethereum contract. Since its only two users, we wouldn’t set odds. Instead, the users would be able to bet whatever they want, but the contract will just use the smaller bet and return anything above it to the user who bet more. And if a user doesn’t bet, then all funds are returned to the other user.
Yeah, I think what you described would be the best approach.
That said, I really like the idea of odds-setting. It could be a great mechanic for a different use-case…
@ainsley Agreed. Like you said, it just requires games that aren’t dependent on user input. How does Enigma handle random number generation? I assume it can do it better than solidity (which can’t do it at all!)
SGX-based randomness is available-- There’s an example of how to use it here in the coinflip example
Hey @pmp , I figured we should just confirm the design we discussed for RPS…
the simplest approach:
- User A and B make fixed-amount deposits to an Ethereum contract
- User A submits her move to Secret Contract
- User B submits his move to Secret Contract
- Secret Contract executes game logic
- Secret Contract calls Ethereum Contract function with address of winner and address of loser.
- Ethereum contract checks to see if both addresses have paid the deposit.
---- If yes, winner takes all.
---- If no, game is cancelled and funds are returned respectively.
In this scenario, you can be griefed but the negative consequences are small, and the rate of play is dramatically improved over commit-reveal. We may be able to improve on this in the future.
And I also want to confirm-- you’re still blocked on how to pass the Ethereum address of the task creator to the secret contract, right?
This is what I was thinking:
- User A starts a new game on the Secret Contract and submits their move. The secret contract verifies the user and submits the new game on the Ethereum contract.
- User A places a bet on the game on the Ethereum contract. The Ethereum contract verifies that the msg.sender is the same as the player address that was sent from the secret contract.
- User B places a bet on the game.
- User B submits their move to the secret contract. The contract verifies the user and calculates the winner. It then sends the GameID, Winner address, and User B address to the Ethereum contract. The Ethereum contract confirms if that a bet was made and User B is the address that made the bet. If either are false, the bets are refunded. The contract then sets the winner of the game.
- If there was a successful bet, the winner may withdraw their winnings from the Ethereum contract.
The main advantage I think this design has is that i doesn’t require multiple rounds of coordination between two players.
However, I still need a good method of verifying the address of the user in a secret contract. I saw on this contract that there is a verify function: https://github.com/enigmampc/enigma-core/blob/develop/examples/eng_wasm_contracts/erc20/src/lib.rs#L92
Since the function requires the signature to be verified with a public key (H256) but I need to pass the verified address (H160) to the Ethereum contract, I’ll still need to derive the address from the public key in order to pass it on to the Ethereum contract. Do any enigma libraries have a method to do that? Also, does enigma.js have a way of getting the public key from an Ethereum account or will I have to rely on ethereum.js for that?