Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wallet-http: put send transaction endpoints behind fund locks. #845

Merged
merged 3 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# HSD Release Notes & Changelog

## Unreleased

### Wallet API:

- HTTP Changes:
- All transaction creating endpoints now accept `hardFee` for specifying the
exact fee.
- All transaction sending endpoints now fundlock/queue tx creation. (no more
conflicting transactions)

## v6.0.0

### Node and Wallet HTTP API
Expand Down
148 changes: 95 additions & 53 deletions lib/wallet/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,9 @@ class HTTP extends Server {
// Send TX
this.post('/wallet/:id/send', async (req, res) => {
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');

const options = TransactionOptions.fromValidator(valid);
const tx = await req.wallet.send(options, passphrase);
const tx = await req.wallet.send(options);

const details = await req.wallet.getDetails(tx.hash());

Expand All @@ -470,14 +469,15 @@ class HTTP extends Server {
// Create TX
this.post('/wallet/:id/create', async (req, res) => {
const valid = Validator.fromRequest(req);
const passphrase = valid.str('passphrase');
const sign = valid.bool('sign', true);

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const options = TransactionOptions.fromValidator(valid);
const tx = await req.wallet.createTX(options);

if (sign)
await req.wallet.sign(tx, passphrase);
await req.wallet.sign(tx, options.passphrase);

const json = tx.getJSON(this.network);

Expand Down Expand Up @@ -1068,23 +1068,26 @@ class HTTP extends Server {
this.post('/wallet/:id/open', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(name, 'Name is required.');
enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createOpen(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendOpen(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createOpen(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1100,7 +1103,6 @@ class HTTP extends Server {
const name = valid.str('name');
const bid = valid.u64('bid');
const lockup = valid.u64('lockup');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1110,15 +1112,19 @@ class HTTP extends Server {
enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createBid(name, bid, lockup, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendBid(name, bid, lockup, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createBid(name, bid, lockup, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand Down Expand Up @@ -1180,29 +1186,39 @@ class HTTP extends Server {
this.post('/wallet/:id/reveal', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);

let mtx;
if (broadcast) {
let tx;

if (!name) {
mtx = await req.wallet.createRevealAll(options);
} else {
mtx = await req.wallet.createReveal(name, options);
}
if (name) {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendReveal(name, options);
} else {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRevealAll(options);
}

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
return res.json(200, tx.getJSON(this.network));
}

let mtx;

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
if (name) {
mtx = await req.wallet.createReveal(name, options);
} else {
mtx = await req.wallet.createRevealAll(options);
}

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1216,29 +1232,39 @@ class HTTP extends Server {
this.post('/wallet/:id/redeem', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');

const options = TransactionOptions.fromValidator(valid);

if (broadcast) {
let tx;

if (name) {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRedeem(name, options);
} else {
// TODO: Add abort signal to close when request closes.
tx = await req.wallet.sendRedeemAll(options);
}

return res.json(200, tx.getJSON(this.network));
}

let mtx;

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
if (!name) {
mtx = await req.wallet.createRedeemAll(options);
} else {
mtx = await req.wallet.createRedeem(name, options);
}

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
return res.json(200, tx.getJSON(this.network));
}

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1253,7 +1279,6 @@ class HTTP extends Server {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const data = valid.obj('data');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1269,15 +1294,19 @@ class HTTP extends Server {
}

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createUpdate(name, resource, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendUpdate(name, resource, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createUpdate(name, resource, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1291,23 +1320,24 @@ class HTTP extends Server {
this.post('/wallet/:id/renewal', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createRenewal(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendRenewal(name, options);
return res.json(200, tx.getJSON(this.network));
}

const mtx = await req.wallet.createRenewal(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1322,7 +1352,6 @@ class HTTP extends Server {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const address = valid.str('address');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

Expand All @@ -1332,15 +1361,19 @@ class HTTP extends Server {

const addr = Address.fromString(address, this.network);
const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createTransfer(name, addr, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendTransfer(name, addr, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createTransfer(name, addr, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1354,23 +1387,26 @@ class HTTP extends Server {
this.post('/wallet/:id/cancel', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createCancel(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendCancel(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createCancel(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1384,23 +1420,24 @@ class HTTP extends Server {
this.post('/wallet/:id/finalize', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createFinalize(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendFinalize(name, options);
return res.json(200, tx.getJSON(this.network));
}

const mtx = await req.wallet.createFinalize(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand All @@ -1414,23 +1451,26 @@ class HTTP extends Server {
this.post('/wallet/:id/revoke', async (req, res) => {
const valid = Validator.fromRequest(req);
const name = valid.str('name');
const passphrase = valid.str('passphrase');
const broadcast = valid.bool('broadcast', true);
const sign = valid.bool('sign', true);

enforce(broadcast ? sign : true, 'Must sign when broadcasting.');
enforce(name, 'Must pass name.');

const options = TransactionOptions.fromValidator(valid);
const mtx = await req.wallet.createRevoke(name, options);

if (broadcast) {
const tx = await req.wallet.sendMTX(mtx, passphrase);
// TODO: Add abort signal to close when request closes.
const tx = await req.wallet.sendRevoke(name, options);
return res.json(200, tx.getJSON(this.network));
}

// TODO: Add create TX with locks for used Coins and/or
// adds to the pending list.
const mtx = await req.wallet.createRevoke(name, options);

if (sign)
await req.wallet.sign(mtx, passphrase);
await req.wallet.sign(mtx, options.passphrase);

const json = mtx.getJSON(this.network);

Expand Down Expand Up @@ -1814,6 +1854,8 @@ class TransactionOptions {
this.subtractIndex = valid.i32('subtractIndex');
this.depth = valid.u32(['confirmations', 'depth']);
this.paths = valid.bool('paths');
this.passphrase = valid.str('passphrase');
this.hardFee = valid.u64('hardFee'),
this.outputs = [];

if (valid.has('outputs')) {
Expand Down
Loading