Skip to content

Commit

Permalink
feat: increase test coverage, deterministic stealth meta address gen, (
Browse files Browse the repository at this point in the history
…#46)

* feat: improve coverage

* feat: coverage to .98

* package: update viem

* feat: large num of announcements to 100 for testing speed

* feat: biome for linting and formatting (#56)

* feat: deterministic gen stealth meta address (#60)

* fix: valid compressed key input type clarity

* feat: get stealth meta address from keys

* feat: is valid pub key

* feat: is valid key tests

* feat: gen keys from sig

* feat: extract portions into own func for testing

* feat: get stealth meta address from signature

* feat: example for gen stealth meta address from sig

* Update examples/generateDeterministicStealthMetaAddress/README.md

* feat: send and receive test (#62)

* feat: handle just passing the stealth meta-address directly

* feat: send and receive test

---------

Co-authored-by: Gary Ghayrat <[email protected]>
  • Loading branch information
marcomariscal and garyghayrat committed May 4, 2024
1 parent 126062a commit d7ddf54
Show file tree
Hide file tree
Showing 79 changed files with 1,969 additions and 697 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ jobs:
bun install
bun test --coverage
lint:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Bun
uses: oven-sh/setup-bun@v1

- name: Check formatting
- name: Check
run: |
bun install
bun run prettier -c src/
bun run check
1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Configuration and development tools
.prettierrc
.bun
tsconfig.json
README.md
Expand Down
11 changes: 0 additions & 11 deletions .prettierrc

This file was deleted.

43 changes: 43 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
"vcs": {
"root": ".",
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"files": {
"include": ["src/**/*.ts", "examples/**/*.ts", "biome.json"]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"ignore": [],
"attributePosition": "auto",
"indentStyle": "tab",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80
},
"javascript": {
"globals": ["NodeJS"],
"formatter": {
"enabled": true,
"lineWidth": 80,
"indentWidth": 2,
"indentStyle": "space",
"quoteStyle": "single",
"arrowParentheses": "asNeeded",
"trailingComma": "none"
}
}
}
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion bunfig.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[test]
coverageSkipTestFiles = true
coverageThreshold = 0
coverageThreshold = 0.8
root = "./src"
10 changes: 5 additions & 5 deletions examples/checkStealthAddress/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {
VALID_SCHEME_ID,
checkStealthAddress,
generateRandomStealthMetaAddress,
generateStealthAddress,
VALID_SCHEME_ID,
generateStealthAddress
} from '@scopelift/stealth-address-sdk';

// User's keys (for example purposes, real values should be securely generated and stored)
const {
stealthMetaAddressURI,
spendingPublicKey: userSpendingPublicKey,
viewingPrivateKey: userViewingPrivateKey,
viewingPrivateKey: userViewingPrivateKey
} = generateRandomStealthMetaAddress();

// Generate a stealth address
const { stealthAddress, ephemeralPublicKey, viewTag } = generateStealthAddress({
schemeId: VALID_SCHEME_ID.SCHEME_ID_1,
stealthMetaAddressURI,
stealthMetaAddressURI
});

console.log(`Stealth Address: ${stealthAddress}`);
Expand All @@ -29,7 +29,7 @@ const isForUser = checkStealthAddress({
spendingPublicKey: userSpendingPublicKey,
userStealthAddress: stealthAddress, // User's known stealth address
viewingPrivateKey: userViewingPrivateKey,
viewTag, // From the announcement
viewTag // From the announcement
});

console.log(`Is the announcement for the user? ${isForUser}`);
2 changes: 1 addition & 1 deletion examples/computeStealthKey/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ const stealthPrivateKey = computeStealthKey({
ephemeralPublicKey,
schemeId,
spendingPrivateKey,
viewingPrivateKey,
viewingPrivateKey
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_RPC_URL='Your rpc url'
1 change: 1 addition & 0 deletions examples/generateDeterministicStealthMetaAddress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Generate Deterministic Stealth Meta-Address Example
Binary file not shown.
12 changes: 12 additions & 0 deletions examples/generateDeterministicStealthMetaAddress/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<h1>Generate Deterministic Stealth Meta-address Example</h1>
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>
81 changes: 81 additions & 0 deletions examples/generateDeterministicStealthMetaAddress/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useState } from "react";
import ReactDOM from "react-dom/client";
import { Address, createWalletClient, custom } from "viem";
import { sepolia } from "viem/chains";
import "viem/window";

import { generateStealthMetaAddressFromSignature } from "@scopelift/stealth-address-sdk";

/**
* This React component demonstrates the process of generating a stealth meta-address deterministically using a user-signed message
* It's deterministic in that the same stealth meta-address is generated for the same user, chain id, and message
* It utilizes Viem's walletClient for wallet interaction
*
* @returns The component renders a button to first handle connecting the wallet, and a subsequent button to handle stealth meta-address generation
*
* @example
* To run the development server: `bun run dev`.
*/
const Example = () => {
// Initialize your configuration
const chain = sepolia; // Example Viem chain

// Initialize Viem wallet client if using Viem
const walletClient = createWalletClient({
chain,
transport: custom(window.ethereum!),
});

// State
const [account, setAccount] = useState<Address>();
const [stealthMetaAddress, setStealthMetaAddress] = useState<`0x${string}`>();

const connect = async () => {
const [address] = await walletClient.requestAddresses();
setAccount(address);
};

const signMessage = async () => {
// An example message to sign for generating the stealth meta-address
// Usually this message includes the chain id to mitigate replay attacks across different chains
// The message that is signed should clearly communicate to the user what they are signing and why
const MESSAGE_TO_SIGN = `Generate Stealth Meta-Address on ${chain.id} chain`;

if (!account) throw new Error("A connected account is required");

const signature = await walletClient.signMessage({
account,
message: MESSAGE_TO_SIGN,
});

return signature;
};

const handleSignAndGenStealthMetaAddress = async () => {
const signature = await signMessage();
const stealthMetaAddress =
generateStealthMetaAddressFromSignature(signature);

setStealthMetaAddress(stealthMetaAddress);
};

if (account)
return (
<>
{!stealthMetaAddress ? (
<button onClick={handleSignAndGenStealthMetaAddress}>
Generate Stealth Meta-Address
</button>
) : (
<div>Stealth Meta-Address: {stealthMetaAddress}</div>
)}
<div>Connected: {account}</div>
</>
);

return <button onClick={connect}>Connect Wallet</button>;
};

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<Example />
);
21 changes: 21 additions & 0 deletions examples/generateDeterministicStealthMetaAddress/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "example-generate-deterministic-stealth-meta-address",
"private": true,
"type": "module",
"scripts": {
"dev": "vite"
},
"dependencies": {
"@types/react": "^18.2.61",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^4.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@scopelift/stealth-address-sdk": "latest",
"viem": "latest",
"vite": "latest"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}
17 changes: 17 additions & 0 deletions examples/generateDeterministicStealthMetaAddress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"skipLibCheck": true,
"jsx": "react",
},
"include": ["."],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
});
17 changes: 10 additions & 7 deletions examples/getAnnouncements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import {
ERC5564_CONTRACT,
VALID_SCHEME_ID,
createStealthClient,
getAnnouncements,
getAnnouncements
} from '@scopelift/stealth-address-sdk';

// Example parameters
const chainId = 11155111; // Example chain ID for Sepolia
const rpcUrl = process.env.RPC_URL!; // Your env rpc url that aligns with the chainId;
const rpcUrl = process.env.RPC_URL; // Your env rpc url that aligns with the chainId;
if (!rpcUrl) throw new Error('Missing RPC_URL environment variable');
const fromBlock = BigInt(12345678); // Example ERC5564 announcer contract deploy block for Sepolia, or the block in which the user registered their stealth meta address (as an example)

// Initialize the stealth client
Expand All @@ -27,29 +28,31 @@ const schemeId = BigInt(VALID_SCHEME_ID.SCHEME_ID_1);
const ERC5564Address = ERC5564_CONTRACT.SEPOLIA; // only for Sepolia for now

async function fetchAnnouncements() {
if (!rpcUrl) throw new Error('Missing RPC_URL environment variable');

// Example call to getAnnouncements action on the stealth client
// Adjust parameters according to your requirements
const announcements = await stealthClient.getAnnouncements({
ERC5564Address,
args: {
schemeId,
caller,
caller
// Additional args for filtering, if necessary
},
fromBlock,
fromBlock
// toBlock: 'latest',
});

// Alternatively, you can use the getAnnouncements function directly
const otherAnnouncements = await getAnnouncements({
await getAnnouncements({
// pass in the rpcUrl and chainId to clientParams
clientParams: { rpcUrl, chainId },
ERC5564Address,
args: {
schemeId,
caller,
stealthAddress,
},
stealthAddress
}
});

console.log('Fetched announcements:', announcements);
Expand Down
11 changes: 6 additions & 5 deletions examples/getAnnouncementsForUser/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {
ERC5564_CONTRACT,
VALID_SCHEME_ID,
createStealthClient,
createStealthClient
} from '@scopelift/stealth-address-sdk';

// Example parameters
const chainId = 11155111; // Example chain ID for Sepolia
const rpcUrl = process.env.RPC_URL; // Your env rpc url that aligns with the chainId;
if (!rpcUrl) throw new Error('Missing RPC_URL environment variable');
const fromBlock = BigInt(12345678); // Example ERC5564 announcer contract deploy block for Sepolia, or the block in which the user registered their stealth meta address (as an example)

// Initialize the stealth client
const stealthClient = createStealthClient({ chainId, rpcUrl: rpcUrl! });
const stealthClient = createStealthClient({ chainId, rpcUrl });

// Use the address of your calling contract if applicable
const caller = '0xYourCallingContractAddress';
Expand All @@ -37,11 +38,11 @@ async function fetchAnnouncementsForUser() {
ERC5564Address,
args: {
schemeId,
caller,
caller
// Additional args for filtering, if necessary
},
fromBlock, // Optional fromBlock parameter (defaults to 0, which can be slow for many blocks)
toBlock: 'latest', // Optional toBlock parameter (defaults to latest)
toBlock: 'latest' // Optional toBlock parameter (defaults to latest)
});

// Example call to getAnnouncementsForUser action on the stealth client
Expand All @@ -51,7 +52,7 @@ async function fetchAnnouncementsForUser() {
spendingPublicKey,
viewingPrivateKey,
includeList: ['0xSomeEthAddress, 0xSomeOtherEthAddress'], // Optional include list to only include announcements for specific "from" addresses
excludeList: ['0xEthAddressToExclude'], // Optional exclude list to exclude announcements for specific "from" addresses
excludeList: ['0xEthAddressToExclude'] // Optional exclude list to exclude announcements for specific "from" addresses
});

return userAnnouncements;
Expand Down
Loading

0 comments on commit d7ddf54

Please sign in to comment.