diff --git a/.yarn/versions/6944eba2.yml b/.yarn/versions/6944eba2.yml new file mode 100644 index 0000000..1ff113f --- /dev/null +++ b/.yarn/versions/6944eba2.yml @@ -0,0 +1,8 @@ +undecided: + - "@tornado/sdk-monorepo" + - "@tornado/sdk-chain" + - "@tornado/sdk-core" + - "@tornado/sdk-crypto" + - "@tornado/sdk-data" + - "@tornado/sdk-utils" + - "@tornado/sdk-web" diff --git a/@tornado/sdk-chain/package.json b/@tornado/sdk-chain/package.json index cb3e0aa..eaec6c7 100644 --- a/@tornado/sdk-chain/package.json +++ b/@tornado/sdk-chain/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -80,5 +80,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk-core/package.json b/@tornado/sdk-core/package.json index 108f739..7cce33f 100644 --- a/@tornado/sdk-core/package.json +++ b/@tornado/sdk-core/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.10-alpha", "engines": { "node": "^18" }, @@ -83,5 +83,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk-core/src/index.ts b/@tornado/sdk-core/src/index.ts index 7732689..1921bc4 100644 --- a/@tornado/sdk-core/src/index.ts +++ b/@tornado/sdk-core/src/index.ts @@ -147,11 +147,8 @@ export class Core extends Synchronizer { } private _checkProvider(parentCallName: string): void { - try { - this._chain?.id - } catch (err) { + if (!this._chain) throw ErrorUtils.getError('Core.' + parentCallName + ': you must first connect a provider!') - } } async connect(provider: Provider): Promise { @@ -161,12 +158,14 @@ export class Core extends Synchronizer { } getInstances(keys: Array<{ token: string; denomination: number | string }>): Array { + this._checkProvider('getInstances') return keys.map((key) => Contracts.getInstance(String(this.chain.id), key.token, String(key.denomination), this.chain.provider) ) } getInstance(token: string, denomination: number | string): TornadoInstance { + this._checkProvider('getInstance') return this.loadInstance(this.chain.id, token, denomination) } @@ -591,6 +590,8 @@ export class Core extends Synchronizer { instances: Array, options?: Options.Core.Deposit ): Array { + this._checkProvider('buildDepositTransactions') + const depositsPerInstance = options?.depositsPerInstance ?? new Array(instances.length).fill(1) const doNotPopulate = options?.doNotPopulate ?? false diff --git a/@tornado/sdk-crypto/package.json b/@tornado/sdk-crypto/package.json index 24b66a9..c437cc7 100644 --- a/@tornado/sdk-crypto/package.json +++ b/@tornado/sdk-crypto/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -75,5 +75,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk-data/package.json b/@tornado/sdk-data/package.json index 54f0b68..0a58696 100644 --- a/@tornado/sdk-data/package.json +++ b/@tornado/sdk-data/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -79,5 +79,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk-utils/package.json b/@tornado/sdk-utils/package.json index f1fb53c..fdfe5fb 100644 --- a/@tornado/sdk-utils/package.json +++ b/@tornado/sdk-utils/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -68,5 +68,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk-web/package.json b/@tornado/sdk-web/package.json index 4abe675..d8aaa6e 100644 --- a/@tornado/sdk-web/package.json +++ b/@tornado/sdk-web/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -76,5 +76,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/@tornado/sdk/package.json b/@tornado/sdk/package.json index 8f63ee6..8d36e39 100644 --- a/@tornado/sdk/package.json +++ b/@tornado/sdk/package.json @@ -13,7 +13,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.10-alpha", "engines": { "node": "^18" }, @@ -61,5 +61,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" } diff --git a/README.md b/README.md index 55ea69d..1367d47 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ SDK to integrate your protocol with Tornado Cash. -[Check out the docs here.](./docs/ABOUT.md) +[Please check out the docs here.](./docs/ABOUT.md) + +You SHOULD familiarize yourself with features [still considered experimental](./docs/EXPERIMENTAL.md). You may also read, [a note on testing.](./docs/TESTS.md) diff --git a/docs/ABOUT.md b/docs/ABOUT.md index 1470514..a833754 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,7 +1,8 @@ # Tornado Cash SDK -A collection of Typescript packages which enable you to easily use the Tornado Cash protocol. +A collection of Typescript packages which enable you to easily use the Tornado Cash protocol. Please note that you should familiarize yourself with any still experimental functions, this will be the first link below. +* [Experimental features](./EXPERIMENTAL.md) * [Installation](./INSTALLATION.md) * [Usage](./USAGE.md) diff --git a/docs/EXPERIMENTAL.md b/docs/EXPERIMENTAL.md new file mode 100644 index 0000000..1713380 --- /dev/null +++ b/docs/EXPERIMENTAL.md @@ -0,0 +1,9 @@ +# Functions which are still considered experimental + +Ranked by danger. + +* **Core.buildDepositProof(s)** ➡️ because we still need more testnet tests. Nominally, should work though. Use at own risk. Very very likely won't break. + +* **Relayer.handleWithdrawal** ➡️ because no test relayer has been yet available to handle this. Will likely break. + +* **Core.loadNotes** ➡️ more tests are needed on filtering behaviour. Likely won't break. \ No newline at end of file diff --git a/docs/USAGE.md b/docs/USAGE.md index b494827..c51b11a 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -4,12 +4,16 @@ ```ts import * as Tornado from "@tornado/sdk" +import { providers } from "ethers" async function main() { // Get the core Tornado Cash logic. const core = new Tornado.Core() - // Build tx + // Connect a provider + await core.connect(new providers.JsonRpcProvider("https://some.rpc.url")) + + // Build tx (synchronous) const tx = core.buildDepositTransaction(core.getInstance("usdc", "100")) // Print the tx to console @@ -21,59 +25,63 @@ main() ### Build a withdrawal transaction +This is _still_ considered experimental, I will flag it as _not experimental_ after a certain number of production tests. + ```ts import * as Tornado from "@tornado/sdk" +import { providers, BigNumber } from "ethers" async function main() { - // The address to receive the funds... - const receiverAddress = "0x0000000000000000000000000000000000000000" + // The address to receive the funds... + const receiverAddress = "0x0000000000000000000000000000000000000000" - // Get the core Tornado Cash logic. - const core = new Tornado.Core() + // Get the core Tornado Cash logic. + const core = new Tornado.Core() - // Get a regular ethers v5 provider. - const provider = new providers.JsonRpcProvider("ENTER YOUR RPC URL HERE!") + // Get a regular ethers v5 provider. + const provider = new providers.JsonRpcProvider("https://some.rpc.url") - // This time we need to connect the provider - await core.connect(provider) + // This time we need to connect the provider + await core.connect(provider) - // We also need a relayer - const relayer = new Tornado.Web.Relayer({ - url: "https://" + "ENTER YOUR CHOSEN RELAYER DOMAIN HERE", - // Web can also instead provide a TorHttpClient or an (ethers v5) TorProvider - httpClient: new Tornado.Web.RegularHttpClient() - }) + // We also need a relayer + const relayer = new Tornado.Web.Relayer({ + url: "https://" + "some.relayer.org", + // Web can also instead provide a TorHttpClient or an (ethers v5) TorProvider + httpClient: new Tornado.Web.RegularHttpClient() + }) - // We always have to fetch the current properties of a relayer - await relayer.fetchProperties() + // We always have to fetch the current properties of a relayer + await relayer.fetchProperties() - // Once that is done let's get an instance we have a proof of - const instance = core.getInstance("eth", "0.1") + // Once that is done let's get an instance we have a proof of + const instance = core.getInstance("eth", "0.1") - // We have to load the note, the arguments can be - // indexes - indexes according to which you may choose the notes in cache - // keys - the keys according to which you may choose the notes in cache - // In our case we've set indexes to undefined and choosing our notes according to the instance - // And then selecting the first one of those - const note = (await core.loadNotes(undefined, { - network: core.chain.id, - token: "eth", - denomination: "0.1" - }))[0] + // We have to load the note, the arguments can be + // indexes - indexes according to which you may choose the notes in cache + // keys - the keys according to which you may choose the notes in cache + // In our case we've set indexes to undefined and choosing our notes according to the instance + // And then selecting the first one of those + const note = (await core.loadNotes(undefined, { + network: '' + core.chain.id, + token: "eth", + denomination: "0.1" + }))[0] - // Now build the proof - const proof = await core.buildDepositProof(instance, relayer.properties, receiverAddress, note, { - // Defaults - checkNotesSpent: true, - checkKnownRoot: true, - merkleTreeHeight: 20, - tokenDecimals: 18, - ethPurchaseAmounts: [BigNumber.from(0)], - gasPrice: undefined, - gasPriceCushion: undefined, - }) + // Now build the proof + const proof = await core.buildDepositProof(instance, relayer.properties, receiverAddress, note, { + // Defaults after the function populates as a showcase + // You can also leave all of this out and it will set it by itself + checkNotesSpent: true, + checkKnownRoot: true, + merkleTreeHeight: 20, + tokenDecimals: 18, + ethPurchaseAmounts: [BigNumber.from(0)], // When doing multiple proofs, more elements in array + gasPrice: undefined, + gasPriceCushion: undefined, + }) - console.log(proof) + console.log(proof) } main() @@ -82,28 +90,30 @@ main() ### Synchronize Deposit Events Over Clearnet Without Sync Logs ```ts -import { providers } from "ethers" import * as Tornado from "@tornado/sdk" +import { providers } from "ethers" async function sync() { - // Get a regular ethers v5 provider. - const provider = new providers.JsonRpcProvider("ENTER YOUR RPC URL HERE!") + // Get a regular ethers v5 provider. + const provider = new providers.JsonRpcProvider("https://some.rpc.url") - // Get the core Tornado Cash logic. - const core = new Tornado.Core() + // Get the core Tornado Cash logic. + const core = new Tornado.Core() - // Connect the provider (necessary) - await core.connect(provider) + // Connect the provider (necessary) + await core.connect(provider) - // Get the instance to sync - const instance = await core.getInstance("eth", 0.1) + // Get the instance to sync + const instance = await core.getInstance("eth", 0.1) - // Sync! Output will be in the project dir in the cache folder - await core.syncDeposits(instance) + // Sync! Output will be in the project dir in the cache folder + await core.syncDeposits(instance) - // Now export it as an archive! - await core.exportAsArchive('Deposits1ETH0.1') + // Now export it as an archive! + await core.exportAsArchive('Deposits1ETH0.1') } + +sync() ``` ### Synchronize Deposit Events Over Tor Without Sync Logs @@ -112,31 +122,31 @@ async function sync() { import * as Tornado from "@tornado/sdk" async function sync() { - // Get a torified ethers v5 provider. - // You can set the port to 9150 if you use Tor Browser! - const provider = new Tornado.Web.TorProvider("ENTER YOUR RPC URL HERE!", { port: 9050 }) + // Get a torified ethers v5 provider. + // You can set the port to 9150 if you use Tor Browser! + const provider = new Tornado.Web.TorProvider("https://some.rpc.url", { port: 9050 }) - // Get the core Tornado Cash logic. - const core = new Tornado.Core() + // Get the core Tornado Cash logic. + const core = new Tornado.Core() - // Connect the provider (necessary) - await core.connect(provider) + // Connect the provider (necessary) + await core.connect(provider) - // Get the instance to sync - const instance = await core.getInstance("eth", 0.1) + // Get the instance to sync + const instance = core.getInstance("eth", 0.1) - // Sync! - await core.syncDeposits(instance, - { - // In this example, we're forcing to sync from the start block such that - // if some RPC doesn't index all events, that we can rerun and insert other - // elements not found in the former. PouchDB handles the insertions. - startBlock: Tornado.Data.Onchain.getInstanceDeployBlockNumSync("1", "eth", "0.1") - } - ) + // Sync! + await core.syncDeposits(instance, + { + // In this example, we're forcing to sync from the start block such that + // if some RPC doesn't index all events, that we can rerun and insert other + // elements not found in the former. PouchDB handles the insertions. + startBlock: Tornado.Data.Onchain.getInstanceDeployBlockNumSync("1", "eth", "0.1") + } + ) - // Export as archive again! - await core.exportAsArchive('Deposits1ETH0.1') + // Export as archive again! + await core.exportAsArchive('Deposits1ETH0.1') } sync() @@ -147,8 +157,7 @@ sync() ```ts import * as Tornado from "@tornado/sdk" -/// You can implement this however you want. -function logListener(...args: any[]) { +let logListener = function (...args: any[]) { if (args.length === 3) { console.debug(`\nSync will be started with SB: ${args[0]}, TB: ${args[1]}, BD: ${args[2]}\n`) } else if (args.length == 2) { @@ -157,26 +166,31 @@ function logListener(...args: any[]) { } async function sync() { - // Get a torified ethers v5 provider. - const provider = new Tornado.Web.TorProvider("https://eth.llamarpc.com", { port: 9150 }) + // Get a torified ethers v5 provider. + const provider = new Tornado.Web.TorProvider("https://eth.llamarpc.com", { port: 9150 }) - // Get the core Tornado Cash logic. - const core = new Tornado.Core() + // Get the core Tornado Cash logic. + const core = new Tornado.Core() - // Connect the provider (necessary) - await core.connect(provider) + // Connect the provider (necessary) + await core.connect(provider) - // Get the instance to sync - const instance = await core.getInstance("eth", 0.1) + // Get the instance to sync + const instance = core.getInstance("eth", 0.1) - // Log - core.on('debug', logListener) + // Log + core.on('debug', logListener) - // Sync! - await core.syncDeposits(instance) + // Sync! + await core.syncDeposits(instance, + { + // Always sync from start if we want to do multiple RPCs + startBlock: Tornado.Data.Onchain.getInstanceDeployBlockNumSync("1", "eth", "0.1") + } + ) - // Log - core.off('debug', logListener) + // Log + core.off('debug', logListener) } sync() diff --git a/docs/api/index.html b/docs/api/index.html index 9f1d895..67eb81f 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -13,7 +13,8 @@

@tornado/sdk

Tornado Cash SDK

SDK to integrate your protocol with Tornado Cash.

-

Check out the docs here.

+

Please check out the docs here.

+

You SHOULD familiarize yourself with features still considered experimental.

You may also read, a note on testing.

Contributions are welcome, we are here for freedom after all!

See HISTORY.md for a development log.

diff --git a/package.json b/package.json index 978b0fe..e0b078d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "crypto", "zk" ], - "version": "0.0.8-alpha", + "version": "0.0.9-alpha", "engines": { "node": "^18" }, @@ -104,5 +104,6 @@ "tsconfig-paths@4.2.0": { "unplugged": true } - } + }, + "stableVersion": "0.0.8-alpha" }