stellar-plus
Version:
beta version of stellar-plus, an all-in-one sdk for the Stellar blockchain
308 lines (307 loc) • 18 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const freighterApi = tslib_1.__importStar(require("@stellar/freighter-api"));
const stellar_sdk_1 = require("@stellar/stellar-sdk");
const freighter_1 = require("../../../../stellar-plus/account/account-handler/freighter");
const errors_1 = require("../../../../stellar-plus/account/account-handler/freighter/errors");
const network_1 = require("../../../../stellar-plus/network");
jest.mock('@stellar/freighter-api', () => ({
getPublicKey: jest.fn(),
isConnected: jest.fn(),
isAllowed: jest.fn(),
setAllowed: jest.fn().mockResolvedValue(true),
signTransaction: jest.fn(),
getNetworkDetails: jest.fn(),
signAuthEntry: jest.fn(),
}));
const MOCKED_GET_PUBLIC_KEY = freighterApi.getPublicKey;
const MOCKED_IS_CONNECTED = freighterApi.isConnected;
const MOCKED_IS_ALLOWED = freighterApi.isAllowed;
const MOCKED_SET_ALLOWED = freighterApi.setAllowed;
const MOCKED_SIGN_TRANSACTION = freighterApi.signTransaction;
const MOCKED_GET_NETWORK_DETAILS = freighterApi.getNetworkDetails;
const MOCKED_SIGN_AUTH_ENTRY = freighterApi.signAuthEntry;
const mockFreighterIsInstalled = (status) => {
MOCKED_IS_CONNECTED.mockResolvedValue(status);
};
const mockFreighterIsAllowed = (status) => {
MOCKED_IS_ALLOWED.mockResolvedValue(status);
};
const mockFreighterGetPublicKey = (pk) => {
MOCKED_GET_PUBLIC_KEY.mockResolvedValue(pk);
};
const mockFreighterGetNetworkDetailsTestnet = () => {
MOCKED_GET_NETWORK_DETAILS.mockResolvedValue({ networkPassphrase: (0, network_1.TestNet)().networkPassphrase });
};
const mockFreighterGetNetworkDetailsWrongNetwork = () => {
MOCKED_GET_NETWORK_DETAILS.mockResolvedValue({ networkPassphrase: 'wrong network' });
};
const TESTNET_CONFIG = (0, network_1.TestNet)();
const MOCKED_PK = 'GAUFIAL2LV2OV7EA4NTXZDVPQASGI5Y3EXZV2HQS3UUWMZ7UWJDQURYS';
describe('FreighterAccountHandlerClient', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('Initialization', () => {
it('should initialize with the networkConfig', () => {
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
expect(fah).toBeDefined();
});
});
describe('Connect', () => {
it('should load and set the public key when connected', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetNetworkDetailsTestnet();
mockFreighterGetPublicKey(MOCKED_PK);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.connect();
expect(MOCKED_IS_CONNECTED).toHaveBeenCalled();
expect(MOCKED_IS_ALLOWED).toHaveBeenCalled();
expect(MOCKED_GET_PUBLIC_KEY).toHaveBeenCalled();
expect(MOCKED_GET_NETWORK_DETAILS).toHaveBeenCalled();
expect(fah.getPublicKey()).toBe(MOCKED_PK);
}));
it('should trigger permission if extension is not allowed', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(false);
mockFreighterGetNetworkDetailsTestnet();
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.connect();
expect(MOCKED_IS_CONNECTED).toHaveBeenCalled();
expect(MOCKED_SET_ALLOWED).toHaveBeenCalled();
expect(MOCKED_GET_PUBLIC_KEY).not.toHaveBeenCalled();
expect(MOCKED_GET_NETWORK_DETAILS).not.toHaveBeenCalled();
expect(fah.getPublicKey()).toBe('');
}));
it('should trigger permission if extension is not allowed then load the public key and call the provided callback', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_IS_ALLOWED.mockResolvedValue(true).mockResolvedValueOnce(false); // will return false once then only true
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
const mockedCallBack = jest.fn().mockImplementationOnce((pk) => {
// Necessary to break AAA here to ensure assertion only when callback is called
expect(MOCKED_GET_PUBLIC_KEY).toHaveBeenCalled();
expect(pk).toBe(MOCKED_PK);
expect(mockedCallBack).toHaveBeenCalledExactlyOnceWith(MOCKED_PK);
expect(MOCKED_IS_CONNECTED).toHaveBeenCalledTimes(2);
expect(MOCKED_IS_ALLOWED).toHaveBeenCalledTimes(2);
expect(MOCKED_SET_ALLOWED).toHaveBeenCalledOnce();
});
yield fah.connect(mockedCallBack);
}));
it('should not load public key if extension is allowed to the wrong network', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsWrongNetwork();
mockFreighterIsAllowed(true);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.connect();
expect(MOCKED_IS_CONNECTED).toHaveBeenCalledOnce();
expect(MOCKED_IS_ALLOWED).toHaveBeenCalledOnce();
expect(MOCKED_GET_NETWORK_DETAILS).toHaveBeenCalledOnce();
expect(MOCKED_GET_PUBLIC_KEY).not.toHaveBeenCalled();
expect(fah.getPublicKey()).toBe('');
}));
describe('Disconnect', () => {
it('should reset the publick key', () => {
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
jest.replaceProperty(fah, 'publicKey', MOCKED_PK);
fah.disconnect();
expect(fah.getPublicKey()).toBe('');
});
});
});
describe('Load Public Key', () => {
it('should not load the public key if freighter is not installed', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(false);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
expect(MOCKED_SET_ALLOWED).not.toHaveBeenCalled();
expect(MOCKED_GET_PUBLIC_KEY).not.toHaveBeenCalled();
expect(fah.getPublicKey()).toBe('');
}));
it('should not load the public key if freighter is installed but not allowed', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(false);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
expect(MOCKED_SET_ALLOWED).not.toHaveBeenCalled();
expect(MOCKED_GET_PUBLIC_KEY).not.toHaveBeenCalled();
expect(fah.getPublicKey()).toBe('');
}));
it('should not load the public key if freighter is connected to the wrong network', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetNetworkDetailsWrongNetwork();
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
expect(MOCKED_SET_ALLOWED).not.toHaveBeenCalled();
expect(MOCKED_GET_PUBLIC_KEY).not.toHaveBeenCalled();
expect(fah.getPublicKey()).toBe('');
}));
it('should load the public key if freighter is installed and allowed', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetNetworkDetailsTestnet();
mockFreighterGetPublicKey(MOCKED_PK);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
expect(MOCKED_GET_PUBLIC_KEY).toHaveBeenCalled();
expect(fah.getPublicKey()).toBe(MOCKED_PK);
}));
it('should trigger permission when enforceConnection is true and then load the public key and trigger the callback', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_IS_ALLOWED.mockResolvedValue(true).mockResolvedValueOnce(false); // will return false once then only true
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
const mockedCallBack = jest.fn().mockImplementationOnce((pk) => {
// Necessary to break AAA here to ensure assertion only when callback is called
expect(MOCKED_GET_PUBLIC_KEY).toHaveBeenCalled();
expect(pk).toBe(MOCKED_PK);
expect(mockedCallBack).toHaveBeenCalledExactlyOnceWith(MOCKED_PK);
expect(MOCKED_IS_CONNECTED).toHaveBeenCalledTimes(2);
expect(MOCKED_IS_ALLOWED).toHaveBeenCalledTimes(2);
expect(MOCKED_SET_ALLOWED).toHaveBeenCalledOnce();
});
yield fah.loadPublicKey(mockedCallBack, true);
}));
});
describe('Core signing features', () => {
it('should sign a transaction with freighter', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_SIGN_TRANSACTION.mockResolvedValue('signedTx');
const mockedTx = {
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
const signedTx = yield fah.sign(mockedTx);
expect(mockedTx.toXDR).toHaveBeenCalledOnce();
expect(MOCKED_SIGN_TRANSACTION).toHaveBeenCalledExactlyOnceWith('mocked xdr', {
networkPassphrase: TESTNET_CONFIG.networkPassphrase,
accountToSign: MOCKED_PK,
});
expect(signedTx).toBe('signedTx');
}));
it('should sign a fee bump transaction with freighter', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_SIGN_TRANSACTION.mockResolvedValue('signedTx');
const mockedTx = {
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
const signedTx = yield fah.sign(mockedTx);
expect(mockedTx.toXDR).toHaveBeenCalledOnce();
expect(MOCKED_SIGN_TRANSACTION).toHaveBeenCalledExactlyOnceWith('mocked xdr', {
networkPassphrase: TESTNET_CONFIG.networkPassphrase,
accountToSign: MOCKED_PK,
});
expect(signedTx).toBe('signedTx');
}));
it('should sign a soroban authorization entry with freighter', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_SIGN_AUTH_ENTRY.mockResolvedValue('signedAuthEntry');
const mockedAuthEntry = {
credentials: jest.fn(),
rootInvocation: jest.fn(),
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const spyXdr = jest.spyOn(stellar_sdk_1.xdr.SorobanAuthorizationEntry, 'fromXDR').mockImplementationOnce(() => mockedAuthEntry);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
const signedAuthEntry = yield fah.signSorobanAuthEntry(mockedAuthEntry, 0, TESTNET_CONFIG.networkPassphrase);
expect(mockedAuthEntry.toXDR).toHaveBeenCalledOnce();
expect(MOCKED_SIGN_AUTH_ENTRY).toHaveBeenCalledExactlyOnceWith('mocked xdr', {
accountToSign: MOCKED_PK,
});
expect(spyXdr).toHaveBeenCalledExactlyOnceWith('signedAuthEntry', 'base64');
expect(signedAuthEntry).toBe(mockedAuthEntry);
}));
});
describe('Errors', () => {
const MOCKED_ERROR = new Error('mocked error');
it('should throw when failed to load public key', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetNetworkDetailsTestnet();
MOCKED_GET_PUBLIC_KEY.mockRejectedValue(MOCKED_ERROR);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield expect(fah.loadPublicKey()).rejects.toThrow(errors_1.FAHError.failedToLoadPublicKeyError(MOCKED_ERROR));
}));
it('should throw when failed to sign transaction', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
const mockedTx = {
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
MOCKED_SIGN_TRANSACTION.mockRejectedValue(MOCKED_ERROR);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
yield expect(fah.sign(mockedTx)).rejects.toThrow(errors_1.FAHError.failedToSignTransactionError(MOCKED_ERROR));
}));
it('should throw when trying to sign a transaction with Freighter when it is not connected', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(false);
const mockedTx = {
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield expect(fah.sign(mockedTx)).rejects.toThrow(errors_1.FAHError.freighterIsNotConnectedError());
}));
it('should throw when failed to sign a soroban authorization entry', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
const mockedAuthEntry = {
credentials: jest.fn(),
rootInvocation: jest.fn(),
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
MOCKED_SIGN_AUTH_ENTRY.mockRejectedValue(MOCKED_ERROR);
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
yield expect(fah.signSorobanAuthEntry(mockedAuthEntry, 0, TESTNET_CONFIG.networkPassphrase)).rejects.toThrow(errors_1.FAHError.failedToSignAuthEntryError(MOCKED_ERROR));
}));
it('should throw when trying to sign a soroban authorization entry with Freighter when it is not connected', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(false);
const mockedAuthEntry = {
credentials: jest.fn(),
rootInvocation: jest.fn(),
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield expect(fah.signSorobanAuthEntry(mockedAuthEntry, 0, TESTNET_CONFIG.networkPassphrase)).rejects.toThrow(errors_1.FAHError.freighterIsNotConnectedError());
}));
it('should throw when trying to sign a soroban authorization entry with Freighter when it is connected to a different network than the one requested to sign for', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
mockFreighterIsInstalled(true);
mockFreighterIsAllowed(true);
mockFreighterGetPublicKey(MOCKED_PK);
mockFreighterGetNetworkDetailsTestnet();
const mockedAuthEntry = {
credentials: jest.fn(),
rootInvocation: jest.fn(),
toXDR: jest.fn().mockReturnValue('mocked xdr'),
};
const fah = new freighter_1.FreighterAccountHandlerClient({ networkConfig: TESTNET_CONFIG });
yield fah.loadPublicKey();
yield expect(fah.signSorobanAuthEntry(mockedAuthEntry, 0, 'wrong network')).rejects.toThrow(errors_1.FAHError.cannotSignForThisNetwork('wrong network', TESTNET_CONFIG.networkPassphrase));
}));
});
});