Skip to content
Open
5 changes: 5 additions & 0 deletions packages/snap/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Show a confirmation dialog before signing a PSBT from KeyringHandler and sending a transfer ([#591](https://github.com/MetaMask/snap-bitcoin-wallet/pull/591))
- Add `resolveAccountAddress` method to KeyringHandler for dApp connectivity ([#590](https://github.com/MetaMask/snap-bitcoin-wallet/pull/590))

## [1.10.1]

### Fixed
Expand Down
103 changes: 88 additions & 15 deletions packages/snap/integration-test/keyring-request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.GetUtxo,
params: {
account: { address: account.address },
outpoint: utxos[0]?.outpoint,
},
},
Expand Down Expand Up @@ -210,7 +211,7 @@ describe('KeyringRequestHandler', () => {
'cHNidP8BAI4CAAAAAAM1gwEAAAAAACJRIORP1Ndiq325lSC/jMG0RlhATHYmuuULfXgEHUM3u5i4AAAAAAAAAAAxai8AAUSx+i9Igg4HWdcpyagCs8mzuRCklgA7nRMkm69rAAAAAAAAAAAAAQACAAAAACp2AAAAAAAAFgAUgpMvYEJ/dp36svRJyRtNnpSo7bQAAAAAAAAAAA==';

it('signs a PSBT successfully: sign', async () => {
const response = await snap.onKeyringRequest({
const response = snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -221,6 +222,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
options: {
Expand All @@ -232,7 +234,13 @@ describe('KeyringRequestHandler', () => {
} as KeyringRequest,
});

expect(response).toRespondWith({
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
await ui.ok();

const result = await response;

expect(result).toRespondWith({
pending: false,
result: {
psbt: SIGNED_PSBT,
Expand All @@ -242,7 +250,7 @@ describe('KeyringRequestHandler', () => {
});

it('signs a PSBT successfully: fill and sign', async () => {
const response = await snap.onKeyringRequest({
const response = snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -253,6 +261,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
options: {
Expand All @@ -264,7 +273,13 @@ describe('KeyringRequestHandler', () => {
} as KeyringRequest,
});

expect(response).toRespondWith({
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
await ui.ok();

const result = await response;

expect(result).toRespondWith({
pending: false,
result: {
psbt: expect.any(String), // non deterministic
Expand All @@ -274,7 +289,7 @@ describe('KeyringRequestHandler', () => {
});

it('signs a PSBT successfully: fill, sign and broadcast', async () => {
const response = await snap.onKeyringRequest({
const response = snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -285,6 +300,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
options: {
Expand All @@ -296,7 +312,13 @@ describe('KeyringRequestHandler', () => {
} as KeyringRequest,
});

expect(response).toRespondWith({
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
await ui.ok();

const result = await response;

expect(result).toRespondWith({
pending: false,
result: {
psbt: expect.any(String), // non deterministic
Expand All @@ -317,6 +339,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: 'notAPsbt',
options: {
fill: true,
Expand All @@ -338,6 +361,37 @@ describe('KeyringRequestHandler', () => {
});
});

it('fails if missing account', async () => {
const response = await snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
id: account.id,
origin,
scope: BtcScope.Regtest,
account: account.id,
request: {
method: AccountCapability.SignPsbt,
params: {
psbt: TEMPLATE_PSBT,
feeRate: 3,
options: {
fill: true,
broadcast: true,
},
},
},
} as KeyringRequest,
});

expect(response).toRespondWithError({
code: -32000,
message:
'Invalid format: At path: account -- Expected an object, but received: undefined',
stack: expect.anything(),
});
});

it('fails if missing options', async () => {
const response = await snap.onKeyringRequest({
origin: ORIGIN,
Expand All @@ -350,6 +404,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
},
},
Expand Down Expand Up @@ -382,6 +437,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.FillPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
},
Expand Down Expand Up @@ -409,6 +465,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.FillPsbt,
params: {
account: { address: account.address },
psbt: 'notAPsbt',
},
},
Expand Down Expand Up @@ -444,6 +501,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.ComputeFee,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
},
Expand Down Expand Up @@ -471,6 +529,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.ComputeFee,
params: {
account: { address: account.address },
psbt: 'notAPsbt',
},
},
Expand All @@ -496,7 +555,7 @@ describe('KeyringRequestHandler', () => {

it('broadcasts a PSBT successfully', async () => {
// Prepare the PSBT to broadcast so we have a valid PSBT to broadcast
let response = await snap.onKeyringRequest({
const signResponse = snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -507,6 +566,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignPsbt,
params: {
account: { address: account.address },
psbt: TEMPLATE_PSBT,
feeRate: 3,
options: {
Expand All @@ -518,11 +578,17 @@ describe('KeyringRequestHandler', () => {
} as KeyringRequest,
});

const signUi = await signResponse.getInterface();
assertIsConfirmationDialog(signUi);
await signUi.ok();

const signResult = await signResponse;

const { result } = (
response.response as { result: { result: FillPsbtResponse } }
signResult.response as { result: { result: FillPsbtResponse } }
).result;

response = await snap.onKeyringRequest({
const response = await snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -533,6 +599,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.BroadcastPsbt,
params: {
account: { address: account.address },
psbt: result.psbt,
},
},
Expand All @@ -559,6 +626,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.BroadcastPsbt,
params: {
account: { address: account.address },
psbt: 'notAPsbt',
},
},
Expand All @@ -579,7 +647,7 @@ describe('KeyringRequestHandler', () => {

describe('sendTransfer', () => {
it('sends funds successfully', async () => {
const response = await snap.onKeyringRequest({
const response = snap.onKeyringRequest({
origin: ORIGIN,
method: submitRequestMethod,
params: {
Expand All @@ -590,23 +658,26 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SendTransfer,
params: {
account: { address: account.address },
recipients: [
{
address: 'bcrt1qstku2y3pfh9av50lxj55arm8r5gj8tf2yv5nxz',
amount: '1000',
},
{
address: 'bcrt1q4gfcga7jfjmm02zpvrh4ttc5k7lmnq2re52z2y',
amount: '1000',
},
],
feeRate: 3,
},
},
} as KeyringRequest,
});

expect(response).toRespondWith({
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
await ui.ok();

const result = await response;

expect(result).toRespondWith({
pending: false,
result: {
txid: expect.any(String),
Expand All @@ -626,6 +697,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SendTransfer,
params: {
account: { address: account.address },
recipients: [{ address: 'notAnAddress', amount: '1000' }],
},
},
Expand Down Expand Up @@ -654,6 +726,7 @@ describe('KeyringRequestHandler', () => {
request: {
method: AccountCapability.SignMessage,
params: {
account: { address: account.address },
message: 'Hello, world!',
},
},
Expand Down
42 changes: 42 additions & 0 deletions packages/snap/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,48 @@
},
"confirmation.requestOrigin": {
"message": "Request from"
},
"confirmation.signPsbt.title": {
"message": "Sign Transaction"
},
"confirmation.signPsbt.confirmButton": {
"message": "Sign"
},
"confirmation.signPsbt.psbt": {
"message": "Transaction (PSBT)"
},
"confirmation.signPsbt.options": {
"message": "Options"
},
"confirmation.signPsbt.options.fill": {
"message": "Auto-fill inputs"
},
"confirmation.signPsbt.options.broadcast": {
"message": "Broadcast after signing"
},
"confirmation.signPsbt.outputs": {
"message": "Transaction outputs"
},
"confirmation.signPsbt.output.change": {
"message": "Change"
},
"confirmation.signPsbt.output.opReturn": {
"message": "OP_RETURN (data)"
},
"confirmation.signPsbt.output.unknown": {
"message": "Unknown script"
},
"confirmation.signPsbt.inputs": {
"message": "Inputs"
},
"confirmation.signPsbt.rawPsbt": {
"message": "Raw PSBT"
},
"yes": {
"message": "Yes"
},
"no": {
"message": "No"
}
}
}
Loading
Loading