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

Feat/add origin #14

Draft
wants to merge 6 commits into
base: feat/error-list
Choose a base branch
from
Draft
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: 2 additions & 8 deletions packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/airgap-it/tezos-metamask-snap.git"
},
"source": {
"shasum": "SfXyr9LaibY8HwzSGrBgpfSxZ2lsTin01dLKk4tefLQ=",
"shasum": "ntvGpQQ6EK6wxpx6eXq4lEsYqrocwuPqR9sCK2RixY0=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand All @@ -22,13 +22,7 @@
"snap_manageState": {},
"snap_getBip32Entropy": [
{
"path": [
"m",
"44'",
"1729'",
"0'",
"0'"
],
"path": ["m", "44'", "1729'", "0'", "0'"],
"curve": "ed25519"
}
],
Expand Down
16 changes: 11 additions & 5 deletions packages/snap/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ describe('Test function: onRpcRequest', function () {
);

expect(response).to.deep.equal(returnValue);
expect(sendOperationStub).to.have.been.calledWithExactly(exampleParams);
expect(sendOperationStub).to.have.been.calledWithExactly(
ORIGIN,
exampleParams,
);

expect(getAccountStub.callCount).to.equal(0, 'getAccountStub');
expect(sendOperationStub.callCount).to.equal(1, 'sendOperationsStub');
Expand Down Expand Up @@ -133,7 +136,10 @@ describe('Test function: onRpcRequest', function () {
);

expect(response).to.deep.equal(returnValue);
expect(signPayloadStub).to.have.been.calledWithExactly(exampleParams);
expect(signPayloadStub).to.have.been.calledWithExactly(
ORIGIN,
exampleParams,
);

expect(getAccountStub.callCount).to.equal(0, 'getAccountStub');
expect(sendOperationStub.callCount).to.equal(0, 'sendOperationsStub');
Expand All @@ -159,7 +165,7 @@ describe('Test function: onRpcRequest', function () {
);

expect(response).to.deep.equal(returnValue);
expect(getRpcStub).to.have.been.calledWithExactly();
expect(getRpcStub).to.have.been.calledWithExactly(ORIGIN);

expect(getAccountStub.callCount).to.equal(0, 'getAccountStub');
expect(sendOperationStub.callCount).to.equal(0, 'sendOperationsStub');
Expand All @@ -185,7 +191,7 @@ describe('Test function: onRpcRequest', function () {
);

expect(response).to.deep.equal(returnValue);
expect(setRpcStub).to.have.been.calledWithExactly(exampleParams);
expect(setRpcStub).to.have.been.calledWithExactly(ORIGIN, exampleParams);

expect(getAccountStub.callCount).to.equal(0, 'getAccountStub');
expect(sendOperationStub.callCount).to.equal(0, 'sendOperationsStub');
Expand All @@ -211,7 +217,7 @@ describe('Test function: onRpcRequest', function () {
);

expect(response).to.deep.equal(returnValue);
expect(clearRpcStub).to.have.been.calledWithExactly();
expect(clearRpcStub).to.have.been.calledWithExactly(ORIGIN);

expect(getAccountStub.callCount).to.equal(0, 'getAccountStub');
expect(sendOperationStub.callCount).to.equal(0, 'sendOperationsStub');
Expand Down
10 changes: 5 additions & 5 deletions packages/snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
return tezosGetAccount(origin);

case 'tezos_sendOperation':
return tezosSendOperation(params);
return tezosSendOperation(origin, params);

case 'tezos_signPayload':
return tezosSignPayload(params);
return tezosSignPayload(origin, params);

case 'tezos_getRpc':
return tezosGetRpc();
return tezosGetRpc(origin);

case 'tezos_setRpc':
return tezosSetRpc(params);
return tezosSetRpc(origin, params);

case 'tezos_clearRpc':
return tezosClearRpc();
return tezosClearRpc(origin);

default:
throw METHOD_NOT_FOUND_ERROR();
Expand Down
6 changes: 4 additions & 2 deletions packages/snap/src/rpc-methods/clear-rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Test function: clearRpc', function () {
snapStub.rpcStubs.snap_dialog.resolves(true);
snapStub.rpcStubs.snap_manageState.resolves();

const response = await tezosClearRpc();
const response = await tezosClearRpc('http://localhost:1234');

expect(response.network).to.equal(data.network);
expect(response.nodeUrl).to.equal(data.nodeUrl);
Expand All @@ -41,6 +41,8 @@ describe('Test function: clearRpc', function () {
it('should not clear the RPC if the user rejects the dialog', async function () {
snapStub.rpcStubs.snap_dialog.resolves(false);

await expect(tezosClearRpc()).to.be.rejectedWith('User rejected');
await expect(tezosClearRpc('http://localhost:1234')).to.be.rejectedWith(
'User rejected',
);
});
});
7 changes: 5 additions & 2 deletions packages/snap/src/rpc-methods/clear-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { panel, heading, text } from '@metamask/snaps-ui';
import { panel, heading, text, divider } from '@metamask/snaps-ui';
import { DEFAULT_NODE_URL } from '../constants';
import { USER_REJECTED_ERROR } from '../utils/errors';
import { createOriginElement } from '../ui/origin-element';

export const tezosClearRpc = async () => {
export const tezosClearRpc = async (origin: string) => {
const approved = await snap.request({
method: 'snap_dialog',
params: {
Expand All @@ -12,6 +13,8 @@ export const tezosClearRpc = async () => {
text(
`Do you want to clear the RPC settings and use the default RPC node again?`,
),
divider(),
...createOriginElement(origin),
]),
},
});
Expand Down
6 changes: 4 additions & 2 deletions packages/snap/src/rpc-methods/get-rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Test function: getRpc', function () {

snapStub.rpcStubs.snap_dialog.resolves(true);

const response = await tezosGetRpc();
const response = await tezosGetRpc('http://localhost:1234');

expect(response.network).to.equal(data.network);
expect(response.nodeUrl).to.equal(data.nodeUrl);
Expand All @@ -43,6 +43,8 @@ describe('Test function: getRpc', function () {

snapStub.rpcStubs.snap_dialog.resolves(false);

await expect(tezosGetRpc()).to.be.rejectedWith('User rejected');
await expect(tezosGetRpc('http://localhost:1234')).to.be.rejectedWith(
'User rejected',
);
});
});
5 changes: 4 additions & 1 deletion packages/snap/src/rpc-methods/get-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { panel, heading, text, copyable, divider } from '@metamask/snaps-ui';
import { getRpc } from '../utils/get-rpc';
import { USER_REJECTED_ERROR } from '../utils/errors';
import { createOriginElement } from '../ui/origin-element';

export const tezosGetRpc = async () => {
export const tezosGetRpc = async (origin: string) => {
const rpc = await getRpc();

const approved = await snap.request({
Expand All @@ -17,6 +18,8 @@ export const tezosGetRpc = async () => {
divider(),
text(rpc.network),
copyable(rpc.nodeUrl),
divider(),
...createOriginElement(origin),
]),
},
});
Expand Down
6 changes: 4 additions & 2 deletions packages/snap/src/rpc-methods/send-operation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ describe('Test function: sendOperation', function () {

snapStub.rpcStubs.snap_dialog.resolves(true);

const response = await tezosSendOperation({ payload: { test: 123 } });
const response = await tezosSendOperation('http://localhost:1234', {
payload: { test: 123 },
});

expect(response.opHash).to.equal(data.opHash);
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(1);
Expand All @@ -74,7 +76,7 @@ describe('Test function: sendOperation', function () {
.returns(Promise.resolve({ ed25519: bip32Entropy } as any));

await expect(
tezosSendOperation({ payload: { test: 123 } }),
tezosSendOperation('http://localhost:1234', { payload: { test: 123 } }),
).to.be.rejectedWith('User rejected');
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(1);
expect(walletMethodStub.callCount).to.be.equal(1);
Expand Down
64 changes: 48 additions & 16 deletions packages/snap/src/rpc-methods/send-operation.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,62 @@
import { panel, heading, text, copyable, divider } from '@metamask/snaps-ui';
import BigNumber from 'bignumber.js';
import { getWallet } from '../utils/get-wallet';
import { prepareAndSign } from '../utils/prepare-and-sign';
import { getRpc } from '../utils/get-rpc';
import { to } from '../utils/to';
import { USER_REJECTED_ERROR } from '../utils/errors';
import { TezosTransactionOperation } from '../tezos/types';
import { createOriginElement } from '../ui/origin-element';

export const tezosSendOperation = async (params: any) => {
const mutezToTez = (mutez: string): string => {
return BigNumber(mutez).shiftedBy(-6).toString(10);
};

export const tezosSendOperation = async (origin: string, params: any) => {
const { payload } = params;
const wallet = await getWallet();
const rpc = await getRpc();

const approved = await snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: panel([
heading('Sign Operation'),
text('Do you want to sign the following payload?'),
copyable(JSON.stringify(payload, null, 2)),
divider(),
text(`The operation will be submit to the following node:`),
copyable(rpc.nodeUrl),
]),
},
});
const typedPayload: TezosTransactionOperation[] = payload;

const humanReadable = [];

if (typedPayload[0] && typedPayload[0].kind === 'transaction') {
humanReadable.push(
text(`**To:** ${typedPayload[0].destination}`),
text(`**Amount:** ${mutezToTez(typedPayload[0].amount)} tez`),
text(`**Fee:** ${mutezToTez(typedPayload[0].fee)} tez`),
text(`**Gas Limit:** ${mutezToTez(typedPayload[0].fee)} tez`),
text(`**Storage Limit:** ${mutezToTez(typedPayload[0].fee)} tez`),
);
}

const [approveError, approved] = await to<string | boolean | null>(
snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: panel([
heading('Sign Operation'),
text('Do you want to sign the following payload?'),
...humanReadable,
copyable(JSON.stringify(payload, null, 2)),
divider(),
text(`The operation will be submit to the following node:`),
copyable(rpc.nodeUrl),
divider(),
...createOriginElement(origin),
]),
},
}),
);

if (approveError) {
throw new Error(`APPROVE ERROR ${approveError.message}`);
}

if (!approved) {
throw new Error('User rejected');
throw USER_REJECTED_ERROR();
}

return { opHash: await prepareAndSign(payload, wallet, rpc.nodeUrl) };
Expand Down
18 changes: 12 additions & 6 deletions packages/snap/src/rpc-methods/set-rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('Test function: setRpc', function () {
const data = { network: 'mainnet', nodeUrl: 'https://test.com/' };
const { fetchStub } = setupStubs(snapStub);

const response = await tezosSetRpc(data);
const response = await tezosSetRpc('http://localhost:1234', data);

checkStubs(response, data, fetchStub, snapStub);

Expand All @@ -74,7 +74,7 @@ describe('Test function: setRpc', function () {
const data = { network: 'mainnet', nodeUrl: 'https://test.com' };
const { fetchStub } = setupStubs(snapStub);

const response = await tezosSetRpc(data);
const response = await tezosSetRpc('http://localhost:1234', data);

checkStubs(response, data, fetchStub, snapStub);

Expand All @@ -96,7 +96,7 @@ describe('Test function: setRpc', function () {
.stub(global, 'fetch')
.returns(jsonOk({ hash: 'op...', chain_id: 'testchain' }));

await expect(tezosSetRpc(data)).to.be.rejectedWith(
await expect(tezosSetRpc('http://localhost:1234', data)).to.be.rejectedWith(
'RPC URL needs to start with https://',
);

Expand All @@ -114,7 +114,9 @@ describe('Test function: setRpc', function () {
.stub(global, 'fetch')
.returns(jsonOk({ hash: 'op...', chain_id: 'testchain' }));

expect(tezosSetRpc(data)).to.be.rejectedWith('User rejected');
expect(tezosSetRpc('http://localhost:1234', data)).to.be.rejectedWith(
'User rejected',
);

expect(fetchStub.callCount).to.be.equal(1, 'fetchStub');
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(0);
Expand All @@ -130,7 +132,9 @@ describe('Test function: setRpc', function () {
.stub(global, 'fetch')
.returns(jsonOk({ test: '123' }));

expect(tezosSetRpc(data)).to.be.rejectedWith('Invalid RPC URL');
expect(tezosSetRpc('http://localhost:1234', data)).to.be.rejectedWith(
'Invalid RPC URL',
);

expect(fetchStub.callCount).to.be.equal(1, 'fetchStub');
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(0);
Expand All @@ -146,7 +150,9 @@ describe('Test function: setRpc', function () {
.stub(global, 'fetch')
.rejects(new Error('Invalid RPC URL'));

expect(tezosSetRpc(data)).to.be.rejectedWith('Invalid RPC URL');
expect(tezosSetRpc('http://localhost:1234', data)).to.be.rejectedWith(
'Invalid RPC URL',
);

expect(fetchStub.callCount).to.be.equal(1, 'fetchStub');
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(0);
Expand Down
5 changes: 4 additions & 1 deletion packages/snap/src/rpc-methods/set-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
RPC_INVALID_RESPONSE_ERROR,
USER_REJECTED_ERROR,
} from '../utils/errors';
import { createOriginElement } from '../ui/origin-element';

export const tezosSetRpc = async (params: any) => {
export const tezosSetRpc = async (origin: string, params: any) => {
const { network, nodeUrl }: { network: string; nodeUrl: string } = params;

if (!nodeUrl.startsWith('https://')) {
Expand Down Expand Up @@ -38,6 +39,8 @@ export const tezosSetRpc = async (params: any) => {
divider(),
text(`${network}`),
copyable(nodeUrl),
divider(),
...createOriginElement(origin),
]),
},
});
Expand Down
6 changes: 4 additions & 2 deletions packages/snap/src/rpc-methods/sign-payload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ describe('Test function: signPayload', function () {

snapStub.rpcStubs.snap_dialog.resolves(true);

const response = await tezosSignPayload({ payload: { test: 123 } });
const response = await tezosSignPayload('http://localhost:1234', {
payload: { test: 123 },
});

expect(response).to.deep.equal(data);
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(1);
Expand All @@ -65,7 +67,7 @@ describe('Test function: signPayload', function () {
.returns(Promise.resolve({ ed25519: bip32Entropy } as any));

await expect(
tezosSignPayload({ payload: { test: 123 } }),
tezosSignPayload('http://localhost:1234', { payload: { test: 123 } }),
).to.be.rejectedWith('User rejected');
expect(snapStub.rpcStubs.snap_dialog.callCount).to.be.equal(1);
expect(walletMethodStub.callCount).to.be.equal(1);
Expand Down
7 changes: 5 additions & 2 deletions packages/snap/src/rpc-methods/sign-payload.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { copyable, heading, panel, text } from '@metamask/snaps-ui';
import { copyable, divider, heading, panel, text } from '@metamask/snaps-ui';
import { getWallet } from '../utils/get-wallet';
import { sign } from '../utils/sign';
import { USER_REJECTED_ERROR } from '../utils/errors';
import { createOriginElement } from '../ui/origin-element';

export const tezosSignPayload = async (params: any) => {
export const tezosSignPayload = async (origin: string, params: any) => {
const { payload } = params;
const wallet = await getWallet();

Expand All @@ -15,6 +16,8 @@ export const tezosSignPayload = async (params: any) => {
heading('Sign Payload'),
text('Do you want to sign the following payload?'),
copyable(JSON.stringify(payload)),
divider(),
...createOriginElement(origin),
]),
},
});
Expand Down
Loading