Skip to content

Commit

Permalink
Refactor packages APIs (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec authored Oct 6, 2023
2 parents c34bccf + 0a13562 commit 60eacdb
Show file tree
Hide file tree
Showing 203 changed files with 6,124 additions and 4,821 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
node: [ '16.x', '18.x' ]
node: [ '18.x' ]
os: [ ubuntu-latest ]

steps:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ contracts/compiled
examples/*/pnpm-lock.yaml
pnpm-debug.log
docs-json
docs
./docs
.next
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16
18
7 changes: 7 additions & 0 deletions demos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `@nucypher/*` Demos

- [`taco-demo`](./taco-demo) - A demo of the `@nucypher/taco` library.
- [`taco-nft-demo`](./taco-nft-demo) - A demo an NFT-based condition using the `@nucypher/taco` library.
- [`nucypher-ts-demo`](https://github.com/nucypher/nucypher-ts-demo) - A demo of PRE in the `nucypher-ts` library.
- [`tdec-sandbox`](https://github.com/nucypher/tdec-sandbox) - A demo of tDec in the `nucypher-ts` library.
- [`tdec-nft-example`](https://github.com/nucypher/tdec-nft-example) - A demo of tDec in the `nucypher-ts` library.
31 changes: 31 additions & 0 deletions demos/taco-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# taco-demo

## Installation

```bash
pnpm install
pnpm start
```

## Usage

In order to run this demo will need a MetaMask with an account funded with some
$MATIC.

In order to connect with the network, the demo uses a public instances of
[Porter](https://docs.threshold.network/app-development/threshold-access-control-tac/porter).

### Polygon

`@nucypher/taco` is in an early release. We recommend **not** using it in
production _just yet_.

### Tapir - Mumbai Testnet

The current release of `@nucypher/taco` supports Ursulas working on Tapir
network and contracts deployed on Mumbai testnet.

## References

This dApp is based on
[`useDapp` example](https://github.com/EthWorks/useDapp/tree/master/packages/example).
38 changes: 38 additions & 0 deletions demos/taco-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "taco-demo",
"version": "0.1.0",
"description": "A usage example for @nucypher/taco",
"private": true,
"author": "Piotr Rosłaniec <[email protected]>",
"scripts": {
"start": "webpack serve --mode development",
"build": "tsc --noEmit && rimraf build && webpack --mode production --progress"
},
"dependencies": {
"@nucypher/taco": "workspace:*",
"@usedapp/core": "^1.2.13",
"buffer": "^6.0.3",
"ethers": "^5.7.1",
"file-loader": "^6.2.0",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-spinners": "^0.13.6"
},
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@types/react": "^18.0.20",
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "^18.0.6",
"copy-webpack-plugin": "^11.0.0",
"esbuild-loader": "^2.20.0",
"html-webpack-plugin": "^5.5.0",
"react-refresh": "^0.14.0",
"rimraf": "^3.0.2",
"stream-browserify": "^3.0.0",
"typescript": "^4.8.3",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
}
}
122 changes: 122 additions & 0 deletions demos/taco-demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {
conditions,
decrypt,
encrypt,
getPorterUri,
initialize,
ThresholdMessageKit,
} from '@nucypher/taco';
import { Mumbai, useEthers } from '@usedapp/core';
import { ethers } from 'ethers';
import React, { useEffect, useState } from 'react';

import { ConditionBuilder } from './ConditionBuilder';
import { Decrypt } from './Decrypt';
import { Encrypt } from './Encrypt';
import { Spinner } from './Spinner';

export default function App() {
const { activateBrowserWallet, deactivate, account, switchNetwork } =
useEthers();

const [loading, setLoading] = useState(false);
const [condition, setCondition] = useState<conditions.Condition>();
const [encryptedMessage, setEncryptedMessage] =
useState<ThresholdMessageKit>();
const [decryptedMessage, setDecryptedMessage] = useState<string>();
const [decryptionErrors, setDecryptionErrors] = useState<string[]>([]);
const [ritualId, setRitualId] = useState<number>(2);

useEffect(() => {
initialize();
switchNetwork(Mumbai.chainId);
}, []);

const encryptMessage = async (message: string) => {
if (!condition) {
return;
}
setLoading(true);

await switchNetwork(Mumbai.chainId);

const provider = new ethers.providers.Web3Provider(window.ethereum);
const encryptedMessage = await encrypt(
provider,
message,
condition,
ritualId,
provider.getSigner(),
);

setEncryptedMessage(encryptedMessage);
setLoading(false);
};

const decryptMessage = async (encryptedMessage: ThresholdMessageKit) => {
if (!condition) {
return;
}
setLoading(true);
setDecryptedMessage('');
setDecryptionErrors([]);

const provider = new ethers.providers.Web3Provider(window.ethereum);
const porterUri = getPorterUri('lynx');
const decryptedMessage = await decrypt(
provider,
encryptedMessage,
provider.getSigner(),
porterUri,
);

setDecryptedMessage(new TextDecoder().decode(decryptedMessage));
setLoading(false);
};

if (!account) {
return (
<div>
<h2>Web3 Provider</h2>
<button onClick={() => activateBrowserWallet()}>Connect Wallet</button>
</div>
);
}

if (loading) {
return <Spinner loading={loading} />;
}

return (
<div>
<div>
<h2>Web3 Provider</h2>
<button onClick={deactivate}> Disconnect Wallet</button>
{account && <p>Account: {account}</p>}
</div>

<h2>Ritual ID</h2>
<p>Replace with your own ritual ID</p>
<input type={'number'} value={ritualId} onChange={(e) => setRitualId(parseInt(e.currentTarget.value))} />

<ConditionBuilder
enabled={true}
condition={condition}
setConditions={setCondition}
/>

<Encrypt
enabled={!!condition}
encrypt={encryptMessage}
encryptedMessage={encryptedMessage!}
/>

<Decrypt
enabled={!!encryptedMessage}
decrypt={decryptMessage}
decryptedMessage={decryptedMessage}
decryptionErrors={decryptionErrors}
/>
</div>
);
}
81 changes: 81 additions & 0 deletions demos/taco-demo/src/ConditionBuilder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {conditions} from '@nucypher/taco';
import {Mumbai, useEthers} from '@usedapp/core';
import React, {useState} from 'react';

interface Props {
condition?: conditions.Condition | undefined;
setConditions: (value: conditions.Condition) => void;
enabled: boolean;
}

const rpcCondition = new conditions.RpcCondition({
conditionType: 'rpc',
chain: Mumbai.chainId,
method: 'eth_getBalance',
parameters: [':userAddress'],
returnValueTest: {
comparator: '>',
value: '0',
},
});

export const ConditionBuilder = ({
condition,
setConditions,
enabled,
}: Props) => {
const {library} = useEthers();

const demoCondition = JSON.stringify((condition ?? rpcCondition).toObj());
const [conditionString, setConditionString] = useState(demoCondition);

if (!enabled || !library) {
return <></>;
}

const prettyPrint = (obj: object | string) => {
if (typeof obj === 'string') {
obj = JSON.parse(obj);
}
return JSON.stringify(obj, null, 2);
};

const makeInput = (
onChange = (e: any) => console.log(e),
defaultValue: string,
) => (
<textarea
rows={15}
onChange={(e: any) => onChange(e.target.value)}
defaultValue={prettyPrint(defaultValue)}
>
{}
</textarea>
);

const conditionJSONInput = makeInput(
setConditionString,
JSON.stringify(rpcCondition.toObj()),
);

const onCreateCondition = (e: any) => {
e.preventDefault();
setConditions(conditions.Condition.fromObj(JSON.parse(conditionString)));
};

return (
<>
<h2>Step 1 - Create A Conditioned Access Policy</h2>
<div>
<div>
<h3>Customize your Conditions</h3>
<div>
<h3>Condition JSON</h3>
{conditionJSONInput}
</div>
</div>
<button onClick={onCreateCondition}>Create Conditions</button>
</div>
</>
);
};
76 changes: 76 additions & 0 deletions demos/taco-demo/src/Decrypt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ThresholdMessageKit } from '@nucypher/taco';
import React, { useState } from 'react';

interface Props {
enabled: boolean;
decrypt: (encryptedMessage: ThresholdMessageKit) => void;
decryptedMessage?: string | undefined;
decryptionErrors: string[];
}

export const Decrypt = ({
decrypt,
decryptedMessage,
decryptionErrors,
enabled,
}: Props) => {
const [encryptedMessage, setEncryptedMessage] = useState('');

if (!enabled) {
return <></>;
}

const onDecrypt = () => {
if (!encryptedMessage) {
return;
}
const mkBytes = Buffer.from(encryptedMessage, 'base64');
const mk = ThresholdMessageKit.fromBytes(mkBytes);
decrypt(mk);
};

const DecryptedMessage = () => {
if (!decryptedMessage) {
return <></>;
}
return (
<>
<h3>Decrypted Message:</h3>
<p>{decryptedMessage}</p>
</>
);
};

const DecryptionErrors = () => {
if (decryptionErrors.length === 0) {
return null;
}

return (
<div>
<h2>Decryption Errors</h2>
<p>Not enough decryption shares to decrypt the message.</p>
<p>Some Ursulas have failed with errors:</p>
<ul>
{decryptionErrors.map((error, index) => (
<li key={index}>{error}</li>
))}
</ul>
</div>
);
};

return (
<div>
<h2>Step 3 - Decrypt Encrypted Message</h2>
<input
value={encryptedMessage}
placeholder="Enter encrypted message"
onChange={(e) => setEncryptedMessage(e.currentTarget.value)}
/>
<button onClick={onDecrypt}>Decrypt</button>
{DecryptedMessage()}
{DecryptionErrors()}
</div>
);
};
Loading

0 comments on commit 60eacdb

Please sign in to comment.