@rango-dev/provider-phantom 0.0.0-experimental-936229e8-20251208
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/CHANGELOG.md +285 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/legacy/index.d.ts +15 -0
- package/dist/legacy/index.d.ts.map +1 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +2 -0
- package/dist/mod.js.map +7 -0
- package/dist/namespaces/evm.d.ts +4 -0
- package/dist/namespaces/evm.d.ts.map +1 -0
- package/dist/namespaces/solana.d.ts +4 -0
- package/dist/namespaces/solana.d.ts.map +1 -0
- package/dist/namespaces/sui.d.ts +4 -0
- package/dist/namespaces/sui.d.ts.map +1 -0
- package/dist/namespaces/utxo.d.ts +4 -0
- package/dist/namespaces/utxo.d.ts.map +1 -0
- package/dist/provider-phantom.build.json +1 -0
- package/dist/provider.d.ts +3 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/signer.d.ts +4 -0
- package/dist/signer.d.ts.map +1 -0
- package/dist/signers/utxoSigner.d.ts +12 -0
- package/dist/signers/utxoSigner.d.ts.map +1 -0
- package/dist/utils.d.ts +11 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +37 -0
- package/readme.md +25 -0
- package/src/constants.ts +86 -0
- package/src/legacy/index.ts +175 -0
- package/src/mod.ts +12 -0
- package/src/namespaces/evm.ts +62 -0
- package/src/namespaces/solana.ts +80 -0
- package/src/namespaces/sui.ts +51 -0
- package/src/namespaces/utxo.ts +171 -0
- package/src/provider.ts +27 -0
- package/src/signer.ts +43 -0
- package/src/signers/utxoSigner.ts +92 -0
- package/src/utils.ts +98 -0
package/src/provider.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ProviderBuilder } from '@rango-dev/wallets-core';
|
|
2
|
+
|
|
3
|
+
import { metadata, WALLET_ID } from './constants.js';
|
|
4
|
+
import { evm } from './namespaces/evm.js';
|
|
5
|
+
import { solana } from './namespaces/solana.js';
|
|
6
|
+
import { sui } from './namespaces/sui.js';
|
|
7
|
+
import { utxo } from './namespaces/utxo.js';
|
|
8
|
+
import { phantom as phantomInstance } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const buildProvider = () =>
|
|
11
|
+
new ProviderBuilder(WALLET_ID)
|
|
12
|
+
.init(function (context) {
|
|
13
|
+
const [, setState] = context.state();
|
|
14
|
+
|
|
15
|
+
if (phantomInstance()) {
|
|
16
|
+
setState('installed', true);
|
|
17
|
+
console.debug('[phantom] instance detected.', context);
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
.config('metadata', metadata)
|
|
21
|
+
.add('solana', solana)
|
|
22
|
+
.add('evm', evm)
|
|
23
|
+
.add('utxo', utxo)
|
|
24
|
+
.add('sui', sui)
|
|
25
|
+
.build();
|
|
26
|
+
|
|
27
|
+
export { buildProvider };
|
package/src/signer.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Provider } from './utils.js';
|
|
2
|
+
import type { SignerFactory } from 'rango-types';
|
|
3
|
+
|
|
4
|
+
import { LegacyNetworks as Networks } from '@rango-dev/wallets-core/legacy';
|
|
5
|
+
import { getInstance as getSuiInstance } from '@rango-dev/wallets-core/namespaces/sui';
|
|
6
|
+
import {
|
|
7
|
+
dynamicImportWithRefinedError,
|
|
8
|
+
getNetworkInstance,
|
|
9
|
+
} from '@rango-dev/wallets-shared';
|
|
10
|
+
import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';
|
|
11
|
+
|
|
12
|
+
import { WALLET_NAME_IN_WALLET_STANDARD } from './constants.js';
|
|
13
|
+
|
|
14
|
+
export default async function getSigners(
|
|
15
|
+
provider: Provider
|
|
16
|
+
): Promise<SignerFactory> {
|
|
17
|
+
const solProvider = getNetworkInstance(provider, Networks.SOLANA);
|
|
18
|
+
const evmProvider = getNetworkInstance(provider, Networks.ETHEREUM);
|
|
19
|
+
const bitcoinInstance = getNetworkInstance(provider, Networks.BTC);
|
|
20
|
+
|
|
21
|
+
const suiProvider = getSuiInstance(WALLET_NAME_IN_WALLET_STANDARD);
|
|
22
|
+
|
|
23
|
+
const { DefaultEvmSigner } = await dynamicImportWithRefinedError(
|
|
24
|
+
async () => await import('@rango-dev/signer-evm')
|
|
25
|
+
);
|
|
26
|
+
const { DefaultSolanaSigner } = await dynamicImportWithRefinedError(
|
|
27
|
+
async () => await import('@rango-dev/signer-solana')
|
|
28
|
+
);
|
|
29
|
+
const { BTCSigner } = await dynamicImportWithRefinedError(
|
|
30
|
+
async () => await import('./signers/utxoSigner.js')
|
|
31
|
+
);
|
|
32
|
+
const { DefaultSuiSigner } = await dynamicImportWithRefinedError(
|
|
33
|
+
async () => await import('@rango-dev/signer-sui')
|
|
34
|
+
);
|
|
35
|
+
const signers = new DefaultSignerFactory();
|
|
36
|
+
signers.registerSigner(TxType.SOLANA, new DefaultSolanaSigner(solProvider));
|
|
37
|
+
signers.registerSigner(TxType.EVM, new DefaultEvmSigner(evmProvider));
|
|
38
|
+
signers.registerSigner(TxType.TRANSFER, new BTCSigner(bitcoinInstance));
|
|
39
|
+
if (!!suiProvider) {
|
|
40
|
+
signers.registerSigner(TxType.SUI, new DefaultSuiSigner(suiProvider));
|
|
41
|
+
}
|
|
42
|
+
return signers;
|
|
43
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { GenericSigner, Transfer } from 'rango-types';
|
|
2
|
+
|
|
3
|
+
import * as secp256k1 from '@bitcoinerlab/secp256k1';
|
|
4
|
+
import { Networks } from '@rango-dev/wallets-shared';
|
|
5
|
+
import * as bitcoin from 'bitcoinjs-lib';
|
|
6
|
+
import { SignerError } from 'rango-types';
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
type TransferExternalProvider = any;
|
|
10
|
+
|
|
11
|
+
const BTC_RPC_URL = 'https://go.getblock.io/f37bad28a991436483c0a3679a3acbee';
|
|
12
|
+
|
|
13
|
+
// TODO: use Uint8Array.fromBase64() static method and use this function as a polyfill after updating TypeScript DOM lib
|
|
14
|
+
function base64ToUint8Array(base64String: string) {
|
|
15
|
+
const binaryString = atob(base64String);
|
|
16
|
+
const length = binaryString.length;
|
|
17
|
+
const uint8Array = new Uint8Array(length);
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < length; i++) {
|
|
20
|
+
uint8Array[i] = binaryString.charCodeAt(i);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return uint8Array;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class BTCSigner implements GenericSigner<Transfer> {
|
|
27
|
+
private provider: TransferExternalProvider;
|
|
28
|
+
constructor(provider: TransferExternalProvider) {
|
|
29
|
+
this.provider = provider;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async signMessage(): Promise<string> {
|
|
33
|
+
throw SignerError.UnimplementedError('signMessage');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async signAndSendTx(tx: Transfer): Promise<{ hash: string }> {
|
|
37
|
+
const { asset, psbt } = tx;
|
|
38
|
+
|
|
39
|
+
if (!psbt) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
'No PSBT found to sign. Ensure a valid PSBT is provided.'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (asset.blockchain !== Networks.BTC) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Signing ${asset.blockchain} transaction is not implemented by the signer.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
// Initialize ECC library
|
|
51
|
+
bitcoin.initEccLib(secp256k1);
|
|
52
|
+
|
|
53
|
+
const signedPSBTBytes = await this.provider.signPSBT(
|
|
54
|
+
base64ToUint8Array(psbt.unsignedPsbtBase64),
|
|
55
|
+
{
|
|
56
|
+
inputsToSign: psbt.inputsToSign,
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Finalize PSBT
|
|
61
|
+
const finalPsbt = bitcoin.Psbt.fromBuffer(Buffer.from(signedPSBTBytes));
|
|
62
|
+
finalPsbt.finalizeAllInputs();
|
|
63
|
+
|
|
64
|
+
const finalPsbtBaseHex = finalPsbt.extractTransaction().toHex();
|
|
65
|
+
|
|
66
|
+
// Broadcast PSBT to rpc node
|
|
67
|
+
const response = await fetch(BTC_RPC_URL, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
body: JSON.stringify({
|
|
70
|
+
method: 'sendrawtransaction',
|
|
71
|
+
params: [finalPsbtBaseHex],
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
// Handle network and fetch errors
|
|
77
|
+
const errorText = await response.text();
|
|
78
|
+
throw new Error(`Error broadcasting transaction: ${errorText}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const data = await response.json();
|
|
82
|
+
|
|
83
|
+
if (!data.result) {
|
|
84
|
+
// Handle Bitcoin specific errors
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Error broadcasting transaction. Error Code ${data.error.code}: ${data.error.message}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { hash: data.result };
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ProviderAPI as EvmProviderApi } from '@rango-dev/wallets-core/namespaces/evm';
|
|
2
|
+
import type { ProviderAPI as SolanaProviderApi } from '@rango-dev/wallets-core/namespaces/solana';
|
|
3
|
+
import type { ProviderAPI as SuiProviderApi } from '@rango-dev/wallets-core/namespaces/sui';
|
|
4
|
+
|
|
5
|
+
import { LegacyNetworks } from '@rango-dev/wallets-core/legacy';
|
|
6
|
+
|
|
7
|
+
export type Provider = Map<string, unknown>;
|
|
8
|
+
|
|
9
|
+
export function phantom(): Provider | null {
|
|
10
|
+
const { phantom } = window;
|
|
11
|
+
|
|
12
|
+
if (!phantom) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { solana, ethereum, bitcoin, sui } = phantom;
|
|
17
|
+
|
|
18
|
+
const instances: Provider = new Map();
|
|
19
|
+
|
|
20
|
+
if (ethereum && ethereum.isPhantom) {
|
|
21
|
+
instances.set(LegacyNetworks.ETHEREUM, ethereum);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (solana && solana.isPhantom) {
|
|
25
|
+
instances.set(LegacyNetworks.SOLANA, solana);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (bitcoin && bitcoin.isPhantom) {
|
|
29
|
+
instances.set(LegacyNetworks.BTC, bitcoin);
|
|
30
|
+
}
|
|
31
|
+
if (sui && sui.isPhantom) {
|
|
32
|
+
instances.set(LegacyNetworks.SUI, sui);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return instances;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getInstanceOrThrow(): Provider {
|
|
39
|
+
const instances = phantom();
|
|
40
|
+
|
|
41
|
+
if (!instances) {
|
|
42
|
+
throw new Error('Phantom is not injected. Please check your wallet.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return instances;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function evmPhantom(): EvmProviderApi {
|
|
49
|
+
const instances = phantom();
|
|
50
|
+
|
|
51
|
+
const evmInstance = instances?.get(LegacyNetworks.ETHEREUM);
|
|
52
|
+
|
|
53
|
+
if (!evmInstance) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
'Phantom not injected or EVM not enabled. Please check your wallet.'
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return evmInstance as EvmProviderApi;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function solanaPhantom(): SolanaProviderApi {
|
|
63
|
+
const instance = phantom();
|
|
64
|
+
const solanaInstance = instance?.get(LegacyNetworks.SOLANA);
|
|
65
|
+
|
|
66
|
+
if (!solanaInstance) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'Phantom not injected or Solana not enabled. Please check your wallet.'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return solanaInstance;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function bitcoinPhantom(): SolanaProviderApi {
|
|
76
|
+
const instance = phantom();
|
|
77
|
+
const bitcoinInstance = instance?.get(LegacyNetworks.BTC);
|
|
78
|
+
|
|
79
|
+
if (!bitcoinInstance) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
'Phantom not injected or Bitcoin not enabled. Please check your wallet.'
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return bitcoinInstance;
|
|
86
|
+
}
|
|
87
|
+
export function suiPhantom(): SuiProviderApi {
|
|
88
|
+
const instance = phantom();
|
|
89
|
+
const suiInstance = instance?.get(LegacyNetworks.SUI);
|
|
90
|
+
|
|
91
|
+
if (!suiInstance) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
'Phantom not injected or Sui not enabled. Please check your wallet.'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return suiInstance as SuiProviderApi;
|
|
98
|
+
}
|