@exodus/web3-ethereum 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export * from './provider/index.js';
2
- export * from './simulation/index.js';
1
+ export { EthereumProvider } from './provider/index.js';
2
+ export { simulateTransaction } from './simulation/index.js';
3
+ export { ExodusEthereumWallet } from './wallet-standard/index.js';
package/lib/index.js CHANGED
@@ -1,2 +1,3 @@
1
- export * from './provider/index.js';
2
- export * from './simulation/index.js';
1
+ export { EthereumProvider } from './provider/index.js';
2
+ export { simulateTransaction } from './simulation/index.js';
3
+ export { ExodusEthereumWallet } from './wallet-standard/index.js';
@@ -1,5 +1 @@
1
- import type { EVMConstants } from './types.js';
2
- export declare const CHAIN_IDS: {
3
- [key: string]: number;
4
- };
5
- export declare const ENABLED_EVMS: EVMConstants[];
1
+ export declare const SIMULATION_SUPPORTED_ASSET_NAMES: string[];
@@ -1,32 +1 @@
1
- export const CHAIN_IDS = {
2
- avalanchec: 43114,
3
- bsc: 56,
4
- ethereum: 1,
5
- ethereumclassic: 61,
6
- ethereumgoerli: 5,
7
- fantommainnet: 250,
8
- harmonymainnet: 1666600000,
9
- matic: 137,
10
- };
11
- export const ENABLED_EVMS = [
12
- {
13
- assetName: 'ethereum',
14
- shouldSimulate: true,
15
- },
16
- {
17
- assetName: 'matic',
18
- shouldSimulate: false,
19
- },
20
- {
21
- assetName: 'bsc',
22
- shouldSimulate: false,
23
- },
24
- {
25
- assetName: 'avalanchec',
26
- shouldSimulate: false,
27
- },
28
- {
29
- assetName: 'fantommainnet',
30
- shouldSimulate: false,
31
- },
32
- ];
1
+ export const SIMULATION_SUPPORTED_ASSET_NAMES = ['ethereum']; // just ethereum for now
@@ -1,16 +1 @@
1
- import type { EthTransaction } from '@exodus/web3-ethereum-utils';
2
- import type { Asset, EthBalanceChanges } from './types.js';
3
- export declare const simulateTransaction: (assets: Record<string, Asset>, transaction: EthTransaction, network: string) => Promise<{
4
- assetName: string;
5
- advancedDetails: never[];
6
- balanceChanges: EthBalanceChanges;
7
- displayInfo: {
8
- title: string;
9
- };
10
- txFee: unknown;
11
- txFeeDetails: {
12
- gasLimit: number;
13
- maxFeePerGas: number | undefined;
14
- gasPrice: number;
15
- };
16
- }>;
1
+ export { simulateTransaction } from './simulation.js';
@@ -1,70 +1 @@
1
- import { retrieveSideEffects } from '@exodus/ethereum-api';
2
- import { createCurrency, formatAccounts, getEthereumDisplayInfo, supportedNetworkEvms, hexToBN, isEthTransferTx, } from './utils.js';
3
- const computeBalanceChanges = async (asset, shouldSimulate, transaction) => {
4
- const assetName = asset.name;
5
- let balanceChanges = {
6
- willReceive: [],
7
- willSend: [],
8
- willApprove: [],
9
- };
10
- if (isEthTransferTx(transaction)) {
11
- const txValue = hexToBN(transaction.value).toString();
12
- balanceChanges.willSend.push({
13
- balance: createCurrency({
14
- amount: txValue,
15
- denominator: asset.currency.defaultUnit.power,
16
- symbol: asset.displayTicker,
17
- }),
18
- });
19
- }
20
- else {
21
- try {
22
- const sideEffect = await retrieveSideEffects({
23
- assetName,
24
- shouldSimulate,
25
- transaction,
26
- });
27
- if (sideEffect) {
28
- balanceChanges = formatAccounts(sideEffect);
29
- }
30
- }
31
- catch (error) {
32
- console.error('Ethereum transaction simulation failed.', error);
33
- }
34
- }
35
- return balanceChanges;
36
- };
37
- const getTxFeeDetails = (asset, transaction) => {
38
- const maxFeePerGasBn = transaction.maxFeePerGas
39
- ? hexToBN(transaction.maxFeePerGas)
40
- : undefined;
41
- const gasPriceBn = hexToBN(transaction.gasPrice);
42
- const gasBn = hexToBN(transaction.gas);
43
- return {
44
- txFee: asset.currency.baseUnit(gasBn.mul(maxFeePerGasBn || gasPriceBn).toString()),
45
- txFeeDetails: {
46
- gasLimit: gasBn.toNumber(),
47
- maxFeePerGas: maxFeePerGasBn?.toNumber(),
48
- gasPrice: gasPriceBn.toNumber(),
49
- },
50
- };
51
- };
52
- export const simulateTransaction = async (assets, transaction, network) => {
53
- const evm = supportedNetworkEvms.get(network);
54
- if (!evm) {
55
- throw new Error(`unsupported network, ${network}`);
56
- }
57
- const { assetName, shouldSimulate } = evm;
58
- const asset = assets[assetName];
59
- const balanceChanges = await computeBalanceChanges(asset, shouldSimulate, transaction);
60
- const { txFee, txFeeDetails } = getTxFeeDetails(asset, transaction);
61
- const displayInfo = getEthereumDisplayInfo(balanceChanges);
62
- return {
63
- assetName,
64
- advancedDetails: [],
65
- balanceChanges,
66
- displayInfo,
67
- txFee,
68
- txFeeDetails,
69
- };
70
- };
1
+ export { simulateTransaction } from './simulation.js';
@@ -0,0 +1,16 @@
1
+ import type { EthTransaction } from '@exodus/web3-ethereum-utils';
2
+ import type { Asset, EthBalanceChanges } from './types.js';
3
+ export declare const simulateTransaction: (asset: Asset, transaction: EthTransaction) => Promise<{
4
+ assetName: string;
5
+ advancedDetails: never[];
6
+ balanceChanges: EthBalanceChanges;
7
+ displayInfo: {
8
+ title: string;
9
+ };
10
+ txFee: unknown;
11
+ txFeeDetails: {
12
+ gasLimit: number;
13
+ maxFeePerGas: number | undefined;
14
+ gasPrice: number;
15
+ };
16
+ }>;
@@ -0,0 +1,67 @@
1
+ import { retrieveSideEffects } from '@exodus/ethereum-api';
2
+ import { SIMULATION_SUPPORTED_ASSET_NAMES } from './constant.js';
3
+ import { createCurrency, formatAccounts, getEthereumDisplayInfo, hexToBN, isEthTransferTx, } from './utils.js';
4
+ const computeBalanceChanges = async (asset, shouldSimulate, transaction) => {
5
+ const assetName = asset.name;
6
+ let balanceChanges = {
7
+ willReceive: [],
8
+ willSend: [],
9
+ willApprove: [],
10
+ };
11
+ if (isEthTransferTx(transaction)) {
12
+ const txValue = hexToBN(transaction.value).toString();
13
+ balanceChanges.willSend.push({
14
+ balance: createCurrency({
15
+ amount: txValue,
16
+ denominator: asset.currency.defaultUnit.power,
17
+ symbol: asset.displayTicker,
18
+ }),
19
+ });
20
+ }
21
+ else {
22
+ try {
23
+ const sideEffect = await retrieveSideEffects({
24
+ assetName,
25
+ shouldSimulate,
26
+ transaction,
27
+ });
28
+ if (sideEffect) {
29
+ balanceChanges = formatAccounts(sideEffect);
30
+ }
31
+ }
32
+ catch (error) {
33
+ console.error('Ethereum transaction simulation failed.', error);
34
+ }
35
+ }
36
+ return balanceChanges;
37
+ };
38
+ const getTxFeeDetails = (asset, transaction) => {
39
+ const maxFeePerGasBn = transaction.maxFeePerGas
40
+ ? hexToBN(transaction.maxFeePerGas)
41
+ : undefined;
42
+ const gasPriceBn = hexToBN(transaction.gasPrice);
43
+ const gasBn = hexToBN(transaction.gas);
44
+ return {
45
+ txFee: asset.currency.baseUnit(gasBn.mul(maxFeePerGasBn || gasPriceBn).toString()),
46
+ txFeeDetails: {
47
+ gasLimit: gasBn.toNumber(),
48
+ maxFeePerGas: maxFeePerGasBn?.toNumber(),
49
+ gasPrice: gasPriceBn.toNumber(),
50
+ },
51
+ };
52
+ };
53
+ export const simulateTransaction = async (asset, transaction) => {
54
+ const assetName = asset.name;
55
+ const shouldSimulate = SIMULATION_SUPPORTED_ASSET_NAMES.includes(assetName);
56
+ const balanceChanges = await computeBalanceChanges(asset, shouldSimulate, transaction);
57
+ const { txFee, txFeeDetails } = getTxFeeDetails(asset, transaction);
58
+ const displayInfo = getEthereumDisplayInfo(balanceChanges);
59
+ return {
60
+ assetName,
61
+ advancedDetails: [],
62
+ balanceChanges,
63
+ displayInfo,
64
+ txFee,
65
+ txFeeDetails,
66
+ };
67
+ };
@@ -1,7 +1,3 @@
1
- export interface EVMConstants {
2
- assetName: string;
3
- shouldSimulate: boolean;
4
- }
5
1
  export interface CurrencyParams {
6
2
  amount: string;
7
3
  symbol: string;
@@ -2,12 +2,6 @@ import BN from 'bn.js';
2
2
  import type { CurrencyParams, EthBalanceChange, EthBalanceChanges } from './types.js';
3
3
  import type { EthTransaction } from '@exodus/web3-ethereum-utils';
4
4
  export declare const hexToBN: (hexValue?: string) => BN;
5
- export declare const supportedNetworkEvms: Map<string, {
6
- chainId: string;
7
- network: string;
8
- assetName: string;
9
- shouldSimulate: boolean;
10
- }>;
11
5
  export declare const isEthTransferTx: (transaction: EthTransaction) => boolean;
12
6
  export declare function getEthereumDisplayInfo(balanceChanges: EthBalanceChanges): {
13
7
  title: string;
@@ -1,13 +1,6 @@
1
1
  import { UnitType } from '@exodus/currency';
2
2
  import BN from 'bn.js';
3
- import { CHAIN_IDS, ENABLED_EVMS } from './constant.js';
4
3
  export const hexToBN = (hexValue) => new BN((hexValue || '').slice(2), 'hex');
5
- const getEvmNetwork = (chainId) => `evm:${chainId}`;
6
- export const supportedNetworkEvms = new Map(ENABLED_EVMS.map((constant) => {
7
- const chainId = '0x' + CHAIN_IDS[constant.assetName].toString(16);
8
- const network = getEvmNetwork(chainId);
9
- return [network, { ...constant, chainId, network }];
10
- }));
11
4
  export const isEthTransferTx = (transaction) => {
12
5
  return (['0x', null, undefined].includes(transaction.data) &&
13
6
  [undefined, '0x5208'].includes(transaction.gas));
@@ -0,0 +1,2 @@
1
+ import type { WalletIcon } from '@wallet-standard/base';
2
+ export declare const icon: WalletIcon;
@@ -0,0 +1,2 @@
1
+ import { EXODUS_ICON } from '@exodus/web3-constants';
2
+ export const icon = EXODUS_ICON;
@@ -0,0 +1,17 @@
1
+ import type { Wallet } from '@wallet-standard/base';
2
+ import type { EthereumProvider } from '../provider/provider.js';
3
+ export declare type EthereumProviderFeature = {
4
+ 'ethereum:provider': {
5
+ provider: EthereumProvider;
6
+ };
7
+ };
8
+ export declare class ExodusEthereumWallet implements Wallet {
9
+ #private;
10
+ get version(): "1.0.0";
11
+ get name(): "Exodus";
12
+ get icon(): `data:image/svg+xml;base64,${string}` | `data:image/webp;base64,${string}` | `data:image/png;base64,${string}` | `data:image/gif;base64,${string}`;
13
+ get chains(): never[];
14
+ get features(): EthereumProviderFeature;
15
+ get accounts(): never[];
16
+ constructor(ethereumProvider: EthereumProvider);
17
+ }
@@ -0,0 +1,35 @@
1
+ import { icon } from './icon.js';
2
+ export class ExodusEthereumWallet {
3
+ #version = '1.0.0';
4
+ #name = 'Exodus';
5
+ #icon = icon;
6
+ #provider = null;
7
+ get version() {
8
+ return this.#version;
9
+ }
10
+ get name() {
11
+ return this.#name;
12
+ }
13
+ get icon() {
14
+ return this.#icon;
15
+ }
16
+ get chains() {
17
+ return [];
18
+ }
19
+ get features() {
20
+ return {
21
+ 'ethereum:provider': {
22
+ provider: this.#provider,
23
+ },
24
+ };
25
+ }
26
+ get accounts() {
27
+ return [];
28
+ }
29
+ constructor(ethereumProvider) {
30
+ if (!ethereumProvider) {
31
+ throw new Error('Ethereum Provider is required!');
32
+ }
33
+ this.#provider = ethereumProvider;
34
+ }
35
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exodus/web3-ethereum",
3
3
  "description": "Apps connectivity library for EVM-compatible chains.",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "module": "lib/index.js",
@@ -12,7 +12,7 @@
12
12
  "./provider": "./lib/provider/index.js",
13
13
  "./rpc": "./lib/rpc-handlers/index.js",
14
14
  "./simulation": "./lib/simulation/index.js",
15
- "./utils": "./lib/rpc-handlers/index.js"
15
+ "./wallet-standard": "./lib/wallet-standard/index.js"
16
16
  },
17
17
  "react-native": "./lib/index.js",
18
18
  "files": [
@@ -40,10 +40,11 @@
40
40
  "devDependencies": {
41
41
  "@exodus/assets": "^8.0.72",
42
42
  "@exodus/schemasafe": "^1.0.0-rc.7",
43
- "@exodus/web3-types": "^1.6.0"
43
+ "@exodus/web3-types": "^1.6.0",
44
+ "@wallet-standard/base": "^1.0.1"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "@exodus/assets": "^8.0.72"
47
48
  },
48
- "gitHead": "c220026347ce27cfc25bacc083d61b1aae5c876b"
49
+ "gitHead": "75254d697e3ffd2d95759e30425c30c7fb7fa654"
49
50
  }
@@ -1,11 +0,0 @@
1
- import type { WalletStandardAccountParams } from '../../types.js';
2
- export declare class ExodusEthereumWalletAccount {
3
- #private;
4
- get address(): string;
5
- get publicKey(): string | undefined;
6
- get chains(): string[] | undefined;
7
- get features(): string[];
8
- get label(): string | undefined;
9
- get icon(): string | undefined;
10
- constructor({ address, publicKey, label, icon, chains, }: WalletStandardAccountParams);
11
- }
@@ -1,36 +0,0 @@
1
- // This file is copied with modification from @wallet-standard/util
2
- const features = ['ethereum:request'];
3
- export class ExodusEthereumWalletAccount {
4
- #address;
5
- #publicKey;
6
- #chains;
7
- #features;
8
- #label;
9
- #icon;
10
- get address() {
11
- return this.#address;
12
- }
13
- get publicKey() {
14
- return this.#publicKey?.slice();
15
- }
16
- get chains() {
17
- return this.#chains?.slice();
18
- }
19
- get features() {
20
- return this.#features?.slice();
21
- }
22
- get label() {
23
- return this.#label;
24
- }
25
- get icon() {
26
- return this.#icon;
27
- }
28
- constructor({ address, publicKey, label, icon, chains, }) {
29
- this.#address = address;
30
- this.#publicKey = publicKey;
31
- this.#chains = chains;
32
- this.#features = features;
33
- this.#label = label;
34
- this.#icon = icon;
35
- }
36
- }
@@ -1,9 +0,0 @@
1
- import type { ChainId } from '../../types.js';
2
- /** Ethereum Mainnet, e.g. https://ethereum.publicnode.com */
3
- export declare const ETHEREUM_MAINNET = "ethereum:1";
4
- /** Array of Ethereum chains supported by Exodus */
5
- export declare const ETHEREUM_CHAINS: string[];
6
- /**
7
- * Converts a hexadecimal chain ID to a [human-readable format](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md)
8
- */
9
- export declare function convertChainIdToCanonicalBlockchainIdentifier(chainId: ChainId): string;
@@ -1,11 +0,0 @@
1
- /** Ethereum Mainnet, e.g. https://ethereum.publicnode.com */
2
- export const ETHEREUM_MAINNET = 'ethereum:1';
3
- /** Array of Ethereum chains supported by Exodus */
4
- export const ETHEREUM_CHAINS = [ETHEREUM_MAINNET];
5
- /**
6
- * Converts a hexadecimal chain ID to a [human-readable format](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md)
7
- */
8
- export function convertChainIdToCanonicalBlockchainIdentifier(chainId) {
9
- chainId = chainId.replace('0x', '');
10
- return `ethereum:${chainId}`;
11
- }
@@ -1,37 +0,0 @@
1
- import { ExodusEthereumWalletAccount } from './account.js';
2
- import type { ChainId, ExodusProvider, UnknownFunction } from '../../types.js';
3
- import type { EthereumProvider } from '../provider.js';
4
- export declare class ExodusEthereumWallet {
5
- #private;
6
- get version(): string;
7
- get name(): string;
8
- get icon(): string;
9
- get chains(): string[];
10
- get features(): {
11
- 'standard:connect': {
12
- version: string;
13
- connect: ({ silent }?: {
14
- silent: boolean;
15
- }) => Promise<{
16
- accounts: ExodusEthereumWalletAccount[];
17
- }>;
18
- };
19
- 'standard:disconnect': {
20
- version: string;
21
- disconnect: () => Promise<void>;
22
- };
23
- 'standard:events': {
24
- version: string;
25
- on: (event: string, listener: UnknownFunction) => () => void;
26
- };
27
- 'ethereum:provider': {
28
- version: string;
29
- provider: EthereumProvider | null;
30
- };
31
- 'exodus:': {
32
- exodus: ExodusProvider | null;
33
- };
34
- };
35
- get accounts(): ExodusEthereumWalletAccount[];
36
- constructor(exodusProvider: ExodusProvider, supportedChainIds: ChainId[]);
37
- }
@@ -1,123 +0,0 @@
1
- import { EXODUS_ICON } from '@exodus/web3-constants';
2
- import { ExodusEthereumWalletAccount } from './account.js';
3
- import { convertChainIdToCanonicalBlockchainIdentifier } from './chains.js';
4
- export class ExodusEthereumWallet {
5
- #exodus = null;
6
- #provider = null;
7
- #listeners = {};
8
- #version = '1.0.0';
9
- #name = 'Exodus';
10
- #icon = EXODUS_ICON;
11
- #account = null;
12
- #chains;
13
- get version() {
14
- return this.#version;
15
- }
16
- get name() {
17
- return this.#name;
18
- }
19
- get icon() {
20
- return this.#icon;
21
- }
22
- get chains() {
23
- return this.#chains?.slice() ?? [];
24
- }
25
- get features() {
26
- return {
27
- 'standard:connect': {
28
- version: '1.0.0',
29
- connect: this.#connect,
30
- },
31
- 'standard:disconnect': {
32
- version: '1.0.0',
33
- disconnect: this.#disconnect,
34
- },
35
- 'standard:events': {
36
- version: '1.0.0',
37
- on: this.#on,
38
- },
39
- 'ethereum:provider': {
40
- version: '1.0.0',
41
- provider: this.#provider,
42
- },
43
- 'exodus:': {
44
- exodus: this.#exodus,
45
- },
46
- };
47
- }
48
- get accounts() {
49
- return this.#account ? [this.#account] : [];
50
- }
51
- constructor(exodusProvider, supportedChainIds) {
52
- if (!exodusProvider) {
53
- throw new Error('Exodus Provider is required!');
54
- }
55
- if (!exodusProvider.ethereum) {
56
- throw new Error('Exodus Provider must include Ethereum Provider!');
57
- }
58
- if (!supportedChainIds?.length) {
59
- throw new Error('At least one supported chain must be provided!');
60
- }
61
- this.#exodus = exodusProvider;
62
- this.#provider = exodusProvider.ethereum;
63
- this.#chains = supportedChainIds.map(convertChainIdToCanonicalBlockchainIdentifier);
64
- this.#provider.on('accountsChanged', this.#reconnected, this);
65
- this.#connected();
66
- }
67
- #on = (event, listener) => {
68
- this.#listeners[event]?.push(listener) ||
69
- (this.#listeners[event] = [listener]);
70
- return () => this.#off(event, listener);
71
- };
72
- #emit = (event, ...args) => {
73
- // eslint-disable-next-line no-unused-expressions,prefer-spread
74
- this.#listeners[event]?.forEach((listener) => listener.apply(null, args));
75
- };
76
- #off = (event, listener) => {
77
- this.#listeners[event] = this.#listeners[event]?.filter((existingListener) => listener !== existingListener);
78
- };
79
- #connected = async () => {
80
- const address = await this.#getAddress();
81
- if (address) {
82
- const account = this.#account;
83
- if (!account || account.address !== address) {
84
- this.#account = new ExodusEthereumWalletAccount({ address });
85
- this.#emit('change', { accounts: this.accounts });
86
- }
87
- }
88
- };
89
- #disconnected = () => {
90
- if (this.#account) {
91
- this.#account = null;
92
- this.#emit('change', { accounts: this.accounts });
93
- }
94
- };
95
- #reconnected = async () => {
96
- const address = await this.#getAddress();
97
- if (address) {
98
- this.#connected();
99
- }
100
- else {
101
- this.#disconnected();
102
- }
103
- };
104
- #connect = async ({ silent } = { silent: false }) => {
105
- if (!silent) {
106
- await this.#requestAddress();
107
- }
108
- await this.#connected();
109
- return { accounts: this.accounts };
110
- };
111
- #disconnect = async () => {
112
- this.#disconnected();
113
- };
114
- #requestAddress = () => {
115
- return this.#provider.request({ method: 'eth_requestAccounts' });
116
- };
117
- #getAddress = async () => {
118
- const [address] = (await this.#provider.request({
119
- method: 'eth_accounts',
120
- }));
121
- return address;
122
- };
123
- }
package/lib/types.d.ts DELETED
@@ -1,13 +0,0 @@
1
- import type { EthereumProvider } from './provider/provider.js';
2
- export interface WalletStandardAccountParams {
3
- address: string;
4
- chains?: ChainId[];
5
- publicKey?: string;
6
- label?: string;
7
- icon?: string;
8
- }
9
- export interface ExodusProvider {
10
- ethereum: EthereumProvider;
11
- }
12
- export declare type ChainId = string;
13
- export declare type UnknownFunction = (...args: unknown[]) => unknown;
package/lib/types.js DELETED
@@ -1 +0,0 @@
1
- export {};