mirror of
https://github.com/tornadocash/tornado-cli.git
synced 2025-07-29 09:18:42 -04:00
new feature - invoice
This commit is contained in:
parent
863474c203
commit
bbb41f1a8c
2 changed files with 306 additions and 154 deletions
26
README.md
26
README.md
|
@ -57,6 +57,32 @@ Transaction mined in block 17036120
|
|||
Done
|
||||
```
|
||||
|
||||
### using invoice
|
||||

|
||||
|
||||
```bash
|
||||
node cli.js invoice ETH 0.1 --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161
|
||||
Connecting to remote node
|
||||
Your remote IP address is xx.xx.xx.xx from xx.
|
||||
Your note: tornado-eth-0.1-5-0x1d9771a7b9f8b6c03d33116208ce8db1aa559d33e65d22dd2ff78375fc6b635f930536d2432b4bde0178c72cfc79d6b27023c5d9de60985f186b34c18c00
|
||||
Your invoice: tornadoInvoice-eth-0.1-5-0x1b680c7dda0c2dd1b85f0fe126d49b16ed594b3cd6d5114db5f4593877a6b84f
|
||||
Backed up deposit note as ./backup-tornado-eth-0.1-5-0x1d9771a7.txt
|
||||
Backed up invoice as ./backup-tornadoInvoice-eth-0.1-5-0x1b680c7d.txt
|
||||
```
|
||||
```bash
|
||||
node cli.js payInvoice tornadoInvoice-eth-0.1-5-0x1b680c7dda0c2dd1b85f0fe126d49b16ed594b3cd6d5114db5f4593877a6b84f --rpc https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161
|
||||
Connecting to remote node
|
||||
Your remote IP address is xx.xx.xx.xx from xx.
|
||||
Tornado contract balance is 823.6 ETH
|
||||
Sender account balance is 0.79544229 ETH
|
||||
Submitting deposit transaction
|
||||
Submitting transaction to the remote node
|
||||
View transaction on block explorer https://goerli.etherscan.io/tx/0x6ded443caed8d6f2666841149532c64bee149a9a8e1070ed4c91a12dd1837747
|
||||
Tornado contract balance is 823.7 ETH
|
||||
Sender account balance is 0.694488819 ETH
|
||||
```
|
||||
|
||||
|
||||
### List of public rpc & relayers for withdrawal
|
||||
|
||||
Infura API key fetched from https://rpc.info (Same one with Metamask)
|
||||
|
|
126
cli.js
126
cli.js
|
@ -157,6 +157,17 @@ async function backupNote({ currency, amount, netId, note, noteString }) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function backupInvoice({ currency, amount, netId, commitmentNote, invoiceString }) {
|
||||
try {
|
||||
await fs.writeFileSync(`./backup-tornadoInvoice-${currency}-${amount}-${netId}-${commitmentNote.slice(0, 10)}.txt`, invoiceString, 'utf8');
|
||||
console.log("Backed up invoice as", `./backup-tornadoInvoice-${currency}-${amount}-${netId}-${commitmentNote.slice(0, 10)}.txt`)
|
||||
} catch (e) {
|
||||
throw new Error('Writing backup note failed:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a deposit
|
||||
* @param currency Сurrency
|
||||
|
@ -207,6 +218,75 @@ async function deposit({ currency, amount }) {
|
|||
return noteString
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* create a Invoice
|
||||
* @param currency Сurrency
|
||||
* @param amount Deposit amount
|
||||
*/
|
||||
async function createInvoice({ currency, amount }) {
|
||||
const deposit = createDeposit({
|
||||
nullifier: rbigint(31),
|
||||
secret: rbigint(31)
|
||||
})
|
||||
const note = toHex(deposit.preimage, 62)
|
||||
const noteString = `tornado-${currency}-${amount}-${netId}-${note}`
|
||||
console.log(`Your note: ${noteString}`)
|
||||
|
||||
const commitmentNote = toHex(deposit.commitment)
|
||||
const invoiceString = `tornadoInvoice-${currency}-${amount}-${netId}-${commitmentNote}`
|
||||
console.log(`Your invoice: ${invoiceString}`)
|
||||
|
||||
await backupNote({ currency, amount, netId, note, noteString })
|
||||
await backupInvoice({ currency, amount, netId, commitmentNote, invoiceString })
|
||||
|
||||
return (noteString, invoiceString)
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a payment
|
||||
* @param currency Сurrency
|
||||
* @param amount Deposit amount
|
||||
*/
|
||||
async function payInvoice({ currency, amount, netId, commitmentNote }) {
|
||||
assert(senderAccount != null, 'Error! PRIVATE_KEY not found. Please provide PRIVATE_KEY in .env file if you deposit')
|
||||
|
||||
if (currency === netSymbol.toLowerCase()) {
|
||||
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account' })
|
||||
const value = isTestRPC ? ETH_AMOUNT : fromDecimals({ amount, decimals: 18 })
|
||||
console.log('Submitting deposit transaction')
|
||||
await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, toHex(commitmentNote), []).encodeABI(), value)
|
||||
await printETHBalance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printETHBalance({ address: senderAccount, name: 'Sender account' })
|
||||
} else {
|
||||
// a token
|
||||
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printERC20Balance({ address: senderAccount, name: 'Sender account' })
|
||||
const decimals = isTestRPC ? 18 : config.deployments[`netId${netId}`][currency].decimals
|
||||
const tokenAmount = isTestRPC ? TOKEN_AMOUNT : fromDecimals({ amount, decimals })
|
||||
if (isTestRPC) {
|
||||
console.log('Minting some test tokens to deposit')
|
||||
await generateTransaction(erc20Address, erc20.methods.mint(senderAccount, tokenAmount).encodeABI())
|
||||
}
|
||||
|
||||
const allowance = await erc20.methods.allowance(senderAccount, tornado._address).call({ from: senderAccount })
|
||||
console.log('Current allowance is', fromWei(allowance))
|
||||
if (toBN(allowance).lt(toBN(tokenAmount))) {
|
||||
console.log('Approving tokens for deposit')
|
||||
await generateTransaction(erc20Address, erc20.methods.approve(tornado._address, tokenAmount).encodeABI())
|
||||
}
|
||||
|
||||
console.log('Submitting deposit transaction')
|
||||
await generateTransaction(contractAddress, tornado.methods.deposit(tornadoInstance, toHex(commitmentNote), []).encodeABI())
|
||||
await printERC20Balance({ address: tornadoContract._address, name: 'Tornado contract' })
|
||||
await printERC20Balance({ address: senderAccount, name: 'Sender account' })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate merkle tree for a deposit.
|
||||
* Download deposit events from the tornado, reconstructs merkle tree, finds our deposit leaf
|
||||
|
@ -847,6 +927,29 @@ function parseNote(noteString) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Tornado.cash note
|
||||
* @param invoiceString the note
|
||||
*/
|
||||
function parseInvoice(noteString) {
|
||||
const noteRegex = /tornadoInvoice-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<commitmentNote>[0-9a-fA-F]{64})/g
|
||||
const match = noteRegex.exec(noteString)
|
||||
if (!match) {
|
||||
throw new Error('The note has invalid format')
|
||||
}
|
||||
|
||||
const netId = Number(match.groups.netId)
|
||||
const buf = Buffer.from(match.groups.commitmentNote, 'hex')
|
||||
const commitmentNote = toHex(buf.slice(0, 32))
|
||||
|
||||
return {
|
||||
currency: match.groups.currency,
|
||||
amount: match.groups.amount,
|
||||
netId,
|
||||
commitmentNote
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDepositData({ amount, currency, deposit }) {
|
||||
try {
|
||||
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount })
|
||||
|
@ -1054,6 +1157,29 @@ async function main() {
|
|||
await init({ rpc: program.rpc, currency, amount, torPort: program.tor, localMode: program.local })
|
||||
await deposit({ currency, amount })
|
||||
})
|
||||
|
||||
program
|
||||
.command('invoice <currency> <amount>')
|
||||
.description(
|
||||
'Create invoice of specified currency and amount from default eth account and return the invoice (to pay) and note (to claim). The currency is one of (ETH|DAI|cDAI|USDC|cUSDC|USDT). The amount depends on currency, see config.js file or visit https://tornado.cash.'
|
||||
)
|
||||
.action(async (currency, amount) => {
|
||||
currency = currency.toLowerCase()
|
||||
await init({ rpc: program.rpc, currency, amount, torPort: program.tor, localMode: program.local })
|
||||
await createInvoice({ currency, amount })
|
||||
})
|
||||
|
||||
program
|
||||
.command('payInvoice <invoice>')
|
||||
.description(
|
||||
'pay invoice of specified currency and amount from default eth account. The currency is one of (ETH|DAI|cDAI|USDC|cUSDC|USDT). The amount depends on currency, see config.js file or visit https://tornado.cash.'
|
||||
)
|
||||
.action(async (invoice) => {
|
||||
const { currency, amount, netId, commitmentNote } = parseInvoice(invoice)
|
||||
await init({ rpc: program.rpc, currency, amount, torPort: program.tor, localMode: program.local })
|
||||
await payInvoice({ currency, amount, netId, commitmentNote })
|
||||
})
|
||||
|
||||
program
|
||||
.command('withdraw <note> <recipient> [ETH_purchase]')
|
||||
.description(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue