Skip to content

Commit

Permalink
Merge pull request #187 from liquality/add-extra-outputs-to-send-tran…
Browse files Browse the repository at this point in the history
…saction

Add sendBatchTransactions
  • Loading branch information
matthewjablack committed Jul 23, 2019
2 parents 6805efe + 54dcb31 commit 29116bc
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 10 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"bootstrap": "lerna bootstrap --force-local",
"test": "cross-env NODE_ENV=test nyc mocha packages/*/test/unit $npm_package_options_mocha",
"test:swap": "cross-env NODE_ENV=test nyc mocha test/integration/swap $npm_package_options_mocha",
"test:tx": "cross-env NODE_ENV=test nyc mocha test/integration/tx $npm_package_options_mocha",
"watch": "cross-env WEBPACK_WATCH=true lerna run build --parallel",
"build:dev:node": "lerna run build:node --stream",
"build:dev:browser": "lerna run build:browser --stream",
Expand Down
44 changes: 42 additions & 2 deletions packages/bitcoin-ledger-provider/lib/BitcoinLedgerProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ export default class BitcoinLedgerProvider extends LedgerProvider {
if (inputs && outputs) {
let change = outputs.find(output => output.id !== 'main')

if (change) {
change = change.value
if (change.length) {
change = change[0].value
}

return {
Expand Down Expand Up @@ -281,6 +281,46 @@ export default class BitcoinLedgerProvider extends LedgerProvider {
return this.getMethod('sendRawTransaction')(signedTransaction)
}

async sendBatchTransaction (transactions) {
const app = await this.getApp()

let totalValue = 0

transactions.forEach((tx) => {
if (tx.data) {
const scriptPubKey = padHexStart(tx.data)
tx.to = pubKeyToAddress(scriptPubKey, this._network.name, 'scriptHash')
}
totalValue += tx.value
})

const unusedAddress = await this.getUnusedAddress(true)
const { inputs, change } = await this.getInputsForAmount(totalValue)

const ledgerInputs = await this.getLedgerInputs(inputs)
const paths = inputs.map(utxo => utxo.derivationPath)

let outputs = []
transactions.forEach((tx) => {
const outputScript = this.createScript(tx.to)
outputs.push({ amount: this.getAmountBuffer(tx.value), script: Buffer.from(outputScript, 'hex') })
})

if (change) {
const changeScript = this.createScript(unusedAddress)
outputs.push({ amount: this.getAmountBuffer(change), script: Buffer.from(changeScript, 'hex') })
}

const serializedOutputs = app.serializeTransactionOutputs({ outputs }).toString('hex')
const signedTransaction = await app.createPaymentTransactionNew(
ledgerInputs,
paths,
unusedAddress.derivationPath,
serializedOutputs
)
return this.getMethod('sendRawTransaction')(signedTransaction)
}

async getLedgerAddresses (startingIndex, numAddresses, change = false) {
const walletPubKey = await this.getWalletPublicKey(this._baseDerivationPath)
const compressedPubKey = compressPubKey(walletPubKey.publicKey)
Expand Down
9 changes: 9 additions & 0 deletions packages/client/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@ export default class Chain {
return this.client.getMethod('sendTransaction')(to, value, data, from)
}

/**
* Create, sign & broad a transaction with multiple outputs.
* @param {string[]} transactions - to, value, data, from.
* @return {Promise<string>} Resolves with a signed transaction.
*/
async sendBatchTransaction (transactions) {
return this.client.getMethod('sendBatchTransaction')(transactions)
}

/**
* Broadcast a signed transaction to the network.
* @param {!string} rawTransaction - A raw transaction usually in the form of a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import MetaMaskConnector from 'node-metamask'
import { Client, Provider, providers, crypto } from '../../../packages/bundle/lib'
import { sleep } from '../../../packages/utils'
import { Client, Provider, providers, crypto } from '../../packages/bundle/lib'
import { sleep } from '../../packages/utils'
import { findLast } from 'lodash'
import config from './config'

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions test/integration/swap/chainToChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { crypto } from '../../../packages/bundle/lib'
import { chains, initiateAndVerify, claimAndVerify, getSwapParams, mineBitcoinBlocks, connectMetaMask } from './common'
import config from './config'
import { chains, initiateAndVerify, claimAndVerify, getSwapParams, mineBitcoinBlocks, connectMetaMask } from '../common'
import config from '../config'

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

Expand Down
4 changes: 2 additions & 2 deletions test/integration/swap/secretGeneration.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/* eslint-disable no-unused-expressions */
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { chains, metaMaskConnector } from './common'
import config from './config'
import { chains, metaMaskConnector } from '../common'
import config from '../config'

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

Expand Down
4 changes: 2 additions & 2 deletions test/integration/swap/singleChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import _ from 'lodash'
import { crypto, providers } from '../../../packages/bundle/lib'
import { chains, initiateAndVerify, claimAndVerify, refundAndVerify, getSwapParams, expectBalance, sleep, mineBitcoinBlocks, deployERC20Token, connectMetaMask } from './common'
import config from './config'
import { chains, initiateAndVerify, claimAndVerify, refundAndVerify, getSwapParams, expectBalance, sleep, mineBitcoinBlocks, deployERC20Token, connectMetaMask } from '../common'
import config from '../config'

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

Expand Down
59 changes: 59 additions & 0 deletions test/integration/tx/transactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-env mocha */
/* eslint-disable no-unused-expressions */
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { chains } from '../common'
import config from '../config'

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

chai.use(chaiAsPromised)
chai.use(require('chai-bignumber')())

function testTransaction (chain) {
it('Sent value to 1 address', async () => {
const addr = (await chain.client.wallet.getUnusedAddress()).address
const value = config[chain.name].value

const balBefore = await chain.client.chain.getBalance(addr)
await chain.client.chain.sendTransaction(addr, value)
await chains.bitcoinWithNode.client.chain.generateBlock(1)
const balAfter = await chain.client.chain.getBalance(addr)

expect(balBefore.plus(value).toString()).to.equal(balAfter.toString())
})
}

function testBatchTransaction (chain) {
it('Sent value to 2 addresses', async () => {
const addr1 = 'n2LYtVFhTMy7S924ff666uRF1qEvGb9nF6'
const addr2 = 'n2gEtQHgtKoxUYyXzkzmVdbFPB3kt6Ea6R'
const value = config[chain.name].value

const bal1Before = await chain.client.chain.getBalance(addr1)
const bal2Before = await chain.client.chain.getBalance(addr2)
await chain.client.chain.sendBatchTransaction([{ to: addr1, value }, { to: addr2, value }])
await chains.bitcoinWithNode.client.chain.generateBlock(1)
const bal1After = await chain.client.chain.getBalance(addr1)
const bal2After = await chain.client.chain.getBalance(addr2)

expect(bal1Before.plus(value).toString()).to.equal(bal1After.toString())
expect(bal2Before.plus(value).toString()).to.equal(bal2After.toString())
})
}

describe('Send Transactions', function () {
this.timeout(config.timeout)

describe('Bitcoin - Ledger', () => {
testTransaction(chains.bitcoinWithLedger)
})
})

describe('Send Batch Transactions', function () {
this.timeout(config.timeout)

describe('Bitcoin - Ledger', () => {
testBatchTransaction(chains.bitcoinWithLedger)
})
})

0 comments on commit 29116bc

Please sign in to comment.