# Demo app: Before and after UPA

## Demo app using UPA

Clients submit solutions $$(c, d, e, f)$$ for the equation:

$$a \* b = c \* d + e + f$$

to a smart contract, which counts the number of solutions it has seen. Elements $$a$$ and $$b$$ are not published on-chain, and instead a ZK proof is used to show know knowledge of them.

## Client changes

**Before UPA:** The client directly submits their solution `publicInputs`, along with a `proof`:

```typescript
await demoApp.submitSolution(proof, publicInputs);
```

**After UPA:** The client first submits their solution and proof to the UPA contract. Then the client waits for UPA to verify the proof before submitting the solution to the simple-app contract:

```typescript
const submissionHandle = await upaClient.submitProofs(circuitId, proof, publicInputs);

await upaClient.waitForSubmissionVerified(submissionHandle);

await demoApp.submitSolution(publicInputs);
```

## App smart contract changes

**Before UPA:** The contract checks that the solution is valid by using  `this.verifyProof` to directly verify the proof on-chain.

```solidity
function submitSolution(
    bytes calldata proof,
    uint256[4] calldata solution
) public returns (bool r) {
    bool isProofCorrect = this.verifyProof(proof, solution);
    require(isProofCorrect, "Proof was not correct");
```

\
**After UPA:** `this.verifyProof` is replaced by `upaVerifier.isVerified`. We don't need to send the proof, only the solution:

```typescript
function submitSolution(
    uint256[4] calldata solution
) public returns (bool r) {
    bool isProofCorrect = upaVerifier.isVerified(circuitId, solution);
    require(isProofCorrect, "Proof was not correct");
```

Here, the client saves on gas costs as this proof is not verified individually on-chain.

## Demo repository

<https://github.com/NebraZKP/demo-app>
