diff --git a/example/zeto/package-lock.json b/example/zeto/package-lock.json index a610f4618..dcca8146a 100644 --- a/example/zeto/package-lock.json +++ b/example/zeto/package-lock.json @@ -33,253 +33,10 @@ "typescript": "^5.6.3" } }, - "../../sdk/typescript/node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "license": "MIT" - }, - "../../sdk/typescript/node_modules/@noble/curves": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "../../sdk/typescript/node_modules/@noble/hashes": { - "version": "1.3.2", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "../../sdk/typescript/node_modules/@types/node": { - "version": "22.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.8" - } - }, - "../../sdk/typescript/node_modules/aes-js": { - "version": "4.0.0-beta.5", - "license": "MIT" - }, - "../../sdk/typescript/node_modules/asynckit": { - "version": "0.4.0", - "license": "MIT" - }, - "../../sdk/typescript/node_modules/axios": { - "version": "1.7.7", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "../../sdk/typescript/node_modules/combined-stream": { - "version": "1.0.8", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "../../sdk/typescript/node_modules/copy-file": { - "version": "11.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.11", - "p-event": "^6.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../sdk/typescript/node_modules/delayed-stream": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "../../sdk/typescript/node_modules/ethers": { - "version": "6.13.4", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "../../sdk/typescript/node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "../../sdk/typescript/node_modules/follow-redirects": { - "version": "1.15.9", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "../../sdk/typescript/node_modules/form-data": { - "version": "4.0.1", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "../../sdk/typescript/node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "../../sdk/typescript/node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "../../sdk/typescript/node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "../../sdk/typescript/node_modules/p-event": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "p-timeout": "^6.1.2" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../sdk/typescript/node_modules/p-timeout": { - "version": "6.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../sdk/typescript/node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT" - }, - "../../sdk/typescript/node_modules/tslib": { - "version": "2.7.0", - "license": "0BSD" - }, - "../../sdk/typescript/node_modules/typescript": { - "version": "5.6.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "../../sdk/typescript/node_modules/undici-types": { - "version": "6.19.8", - "license": "MIT" - }, - "../../sdk/typescript/node_modules/uuid": { - "version": "11.0.2", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, - "../../sdk/typescript/node_modules/ws": { - "version": "8.17.1", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -291,6 +48,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -299,11 +58,15 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -313,34 +76,46 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.0", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/acorn": { "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", "bin": { @@ -352,6 +127,8 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -363,11 +140,15 @@ }, "node_modules/arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, "node_modules/copy-file": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-file/-/copy-file-11.0.0.tgz", + "integrity": "sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==", "dev": true, "license": "MIT", "dependencies": { @@ -383,11 +164,15 @@ }, "node_modules/create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -396,16 +181,22 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, "node_modules/make-error": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/p-event": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", "dev": true, "license": "MIT", "dependencies": { @@ -420,6 +211,8 @@ }, "node_modules/p-timeout": { "version": "6.1.3", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.3.tgz", + "integrity": "sha512-UJUyfKbwvr/uZSV6btANfb+0t/mOhKV/KXcCUTp8FcQI+v/0d+wXqH4htrW0E4rR6WiEO/EPvUFiV9D5OI4vlw==", "dev": true, "license": "MIT", "engines": { @@ -435,6 +228,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -476,7 +271,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -488,17 +285,23 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { diff --git a/example/zeto/src/index.ts b/example/zeto/src/index.ts index 194f99bc7..b965b7e5e 100644 --- a/example/zeto/src/index.ts +++ b/example/zeto/src/index.ts @@ -25,25 +25,73 @@ async function main() { const bank2 = `bank2@node2`; // Deploy a Zeto token to represent cash (CBDC) - logger.log("Deploying Zeto CBDC token..."); + logger.log("Use case #1: Privacy-preserving CBDC token, using private minting..."); + logger.log("- Deploying Zeto token..."); const zetoFactory = new ZetoFactory(paladin3, "zeto"); - const zetoCBDC = await zetoFactory.newZeto(cbdcIssuer, { + const zetoCBDC1 = await zetoFactory.newZeto(cbdcIssuer, { tokenName: "Zeto_AnonNullifier", }); - if (zetoCBDC === undefined) { + if (zetoCBDC1 === undefined) { logger.error("Failed!"); return; } - logger.log(`Success! Zeto deployed at: ${zetoCBDC.address}`); + logger.log(` Zeto deployed at: ${zetoCBDC1.address}`); - logger.log("Deploying ERC20 token..."); + // Issue some cash + logger.log("- Issuing CBDC to bank1 and bank2 with private minting..."); + let receipt = await zetoCBDC1.mint(cbdcIssuer, { + mints: [ + { + to: bank1, + amount: 100000, + }, + { + to: bank2, + amount: 100000, + }, + ] + }); + if (receipt === undefined) { + logger.error("Failed!"); + return; + } + logger.log(" Success!"); + + // Transfer some cash from bank1 to bank2 + logger.log("- Bank1 transferring CBDC to bank2 to pay for some asset trades ..."); + receipt = await zetoCBDC1.using(paladin1).transfer(bank1, { + transfers: [ + { + to: bank2, + amount: 1000, + }, + ] + }); + if (receipt === undefined) { + logger.error("Failed!"); + return; + } + logger.log(" Success!\n"); + + logger.log("Use case #2: Privacy-preserving CBDC token, using public minting of an ERC20 token..."); + logger.log("- Deploying Zeto token..."); + const zetoCBDC2 = await zetoFactory.newZeto(cbdcIssuer, { + tokenName: "Zeto_AnonNullifier", + }); + if (zetoCBDC2 === undefined) { + logger.error("Failed!"); + return; + } + logger.log(` Zeto deployed at: ${zetoCBDC2.address}`); + + logger.log("- Deploying ERC20 token to manage the CBDC supply publicly..."); const cbdcIssuerAddress = await paladin1.resolveVerifier( cbdcIssuer, Algorithms.ECDSA_SECP256K1, Verifiers.ETH_ADDRESS ); - const txId = await paladin3.sendTransaction({ + const txId1 = await paladin3.sendTransaction({ type: TransactionType.PUBLIC, from: cbdcIssuer, data: { @@ -53,51 +101,69 @@ async function main() { abi: erc20Abi.abi, bytecode: erc20Abi.bytecode, }); - if (txId === undefined) { + if (txId1 === undefined) { logger.error("Failed!"); return; } - const result1 = await paladin3.pollForReceipt(txId, 5000); + const result1 = await paladin3.pollForReceipt(txId1, 5000); if (result1 === undefined) { logger.error("Failed!"); return; } const erc20Address = result1.contractAddress; - logger.log(`Success! ERC20 deployed at: ${erc20Address}`); + logger.log(` ERC20 deployed at: ${erc20Address}`); - logger.log("Setting ERC20 to the Zeto token contract ..."); - const result2 = await zetoCBDC.setERC20(cbdcIssuer, { + logger.log("- Setting ERC20 to the Zeto token contract ..."); + const result2 = await zetoCBDC2.setERC20(cbdcIssuer, { _erc20: erc20Address as string }); - if (result1 === undefined) { + if (result2 === undefined) { logger.error("Failed!"); return; } - logger.log(`Success! ERC20 configured on the Zeto contract`); + logger.log(` ERC20 configured on the Zeto contract`); - // Issue some cash - logger.log("Issuing CBDC to bank1 and bank2 ..."); - let receipt = await zetoCBDC.mint(cbdcIssuer, { - mints: [ - { - to: bank1, - amount: 100000, - }, - { - to: bank2, - amount: 100000, - }, - ] + logger.log("- Issuing CBDC to bank1 with public minting in ERC20..."); + const bank1Address = await paladin1.resolveVerifier( + bank1, + Algorithms.ECDSA_SECP256K1, + Verifiers.ETH_ADDRESS + ); + const txId2 = await paladin3.sendTransaction({ + type: TransactionType.PUBLIC, + from: cbdcIssuer, + to: erc20Address, + data: { + "amount": 100000, + "to": bank1Address, + }, + function: "mint", + abi: erc20Abi.abi, }); - if (receipt === undefined) { + if (txId2 === undefined) { + logger.error("Failed!"); + return; + } + const result3 = await paladin3.pollForReceipt(txId2, 5000); + if (result3 === undefined) { + logger.error("Failed!"); + return; + } + logger.log(" Success!"); + + logger.log("- Bank1 deposit ERC20 balance to Zeto ..."); + const result4 = await zetoCBDC2.using(paladin1).deposit(bank1, { + amount: 10000 + }); + if (result4 === undefined) { logger.error("Failed!"); return; } - logger.log("Success!"); + logger.log(` Bank1 deposit successful`); // Transfer some cash from bank1 to bank2 - logger.log("Bank1 transferring CBDC to bank2 to pay for some asset trades ..."); - receipt = await zetoCBDC.using(paladin1).transfer(bank1, { + logger.log("- Bank1 transferring CBDC to bank2 to pay for some asset trades ..."); + receipt = await zetoCBDC2.using(paladin1).transfer(bank1, { transfers: [ { to: bank2, @@ -109,7 +175,23 @@ async function main() { logger.error("Failed!"); return; } - logger.log("Success!"); + logger.log(" Success!"); + + logger.log("- Bank1 withdraws Zeto back to ERC20 balance ..."); + const result5 = await zetoCBDC2.using(paladin1).withdraw(bank1, { + amount: 1000 + }); + if (result5 === undefined) { + logger.error("Failed!"); + return; + } + logger.log(` Bank1 withdraw successful`); + + logger.log("\nSuccess!"); +} + +function getFunctionAbi(abi: any, functionName: string): any { + return abi.find((element: any) => element.name === functionName); } if (require.main === module) { diff --git a/sdk/typescript/src/domains/zeto.ts b/sdk/typescript/src/domains/zeto.ts index 88d1d40b8..cdb4f9715 100644 --- a/sdk/typescript/src/domains/zeto.ts +++ b/sdk/typescript/src/domains/zeto.ts @@ -51,6 +51,28 @@ const zetoPrivateAbi = [{ } ], "outputs": [] +}, { + "type": "function", + "name": "deposit", + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "outputs": [] +}, { + "type": "function", + "name": "withdraw", + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "outputs": [] }]; const zetoPublicAbi = [{ @@ -65,6 +87,138 @@ const zetoPublicAbi = [{ "outputs": [], "stateMutability": "nonpayable", "type": "function" +}, { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "outputs", + "type": "uint256[]" + }, + { + "components": [ + { + "internalType": "uint256[2]", + "name": "pA", + "type": "uint256[2]" + }, + { + "internalType": "uint256[2][2]", + "name": "pB", + "type": "uint256[2][2]" + }, + { + "internalType": "uint256[2]", + "name": "pC", + "type": "uint256[2]" + } + ], + "internalType": "struct Commonlib.Proof", + "name": "proof", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" +}, { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "nullifiers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "output", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[2]", + "name": "pA", + "type": "uint256[2]" + }, + { + "internalType": "uint256[2][2]", + "name": "pB", + "type": "uint256[2][2]" + }, + { + "internalType": "uint256[2]", + "name": "pC", + "type": "uint256[2]" + } + ], + "internalType": "struct Commonlib.Proof", + "name": "proof", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" +}]; + +const erc20Abi = [{ + "type": "function", + "name": "mint", + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "outputs": [] +}, { + "type": "function", + "name": "approve", + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "outputs": [] }]; export const zetoConstructorABI = { @@ -93,6 +247,14 @@ export interface ZetoTransfer { amount: string | number; } +export interface ZetoDepositParams { + amount: string | number; +} + +export interface ZetoWithdrawParams { + amount: string | number; +} + export class ZetoFactory { private options: Required; @@ -132,6 +294,7 @@ export class ZetoFactory { export class ZetoInstance { private options: Required; + private erc20?: string; constructor( private paladin: PaladinClient, @@ -145,7 +308,9 @@ export class ZetoInstance { } using(paladin: PaladinClient) { - return new ZetoInstance(paladin, this.address, this.options); + const zeto = new ZetoInstance(paladin, this.address, this.options); + zeto.erc20 = this.erc20; + return zeto; } async mint(from: string, data: ZetoMintParams) { @@ -181,6 +346,75 @@ export class ZetoInstance { from, data, }); + const result = await this.paladin.pollForReceipt(txID, POLL_TIMEOUT_MS); + if (result === undefined) { + throw new Error("Failed to set ERC20"); + } + this.erc20 = data._erc20; + return result; + } + + async deposit(from: string, data: ZetoDepositParams) { + // first approve the Zeto contract to draw the amount from our balance in the ERC20 + const txID1 = await this.paladin.sendTransaction({ + type: TransactionType.PUBLIC, + abi: erc20Abi, + function: "approve", + to: this.erc20, + from, + data: { value: data.amount, spender: this.address }, + }); + const result1 = await this.paladin.pollForReceipt(txID1, POLL_TIMEOUT_MS); + if (result1 === undefined) { + throw new Error("Failed to approve transfer"); + } + + const depositID = await this.paladin.prepareTransaction({ + type: TransactionType.PRIVATE, + abi: zetoPrivateAbi, + function: "deposit", + to: this.address, + from, + data, + }); + const result2 = await this.paladin.pollForPreparedTransaction(depositID, this.options.pollTimeout); + if (result2 === undefined) { + throw new Error("Failed to prepare deposit"); + } + + const txID2 = await this.paladin.sendTransaction({ + type: TransactionType.PUBLIC, + abi: zetoPublicAbi, + function: "deposit", + to: this.address, + from, + data: result2!.transaction.data, + }); + return this.paladin.pollForReceipt(txID2, POLL_TIMEOUT_MS); + } + + async withdraw(from: string, data: ZetoWithdrawParams) { + const withdrawID = await this.paladin.prepareTransaction({ + type: TransactionType.PRIVATE, + abi: zetoPrivateAbi, + function: "withdraw", + to: this.address, + from, + data, + }); + const result1 = await this.paladin.pollForPreparedTransaction(withdrawID, this.options.pollTimeout); + if (result1 === undefined) { + throw new Error("Failed to prepare withdraw"); + } + + const txID = await this.paladin.sendTransaction({ + type: TransactionType.PUBLIC, + abi: zetoPublicAbi, + function: "withdraw", + to: this.address, + from, + data: result1!.transaction.data, + }); return this.paladin.pollForReceipt(txID, POLL_TIMEOUT_MS); } }