Skip to content

Commit 59487b2

Browse files
ganchoradkovGancho Radkov
and
Gancho Radkov
authored
feat: bitcoin (#568)
* feat: implements bitcoin signet support in example dapp * feat: implements bitcoin signet in example wallet * fix: prettier * fix: adds tiny-secp256k1 to packages * chore: cleanup console logs * chore: cleanup * chore: rm console log * chore: dapp rework with btc specs * chore: parse addreses result * chore: sets bifrost wallet link * feat: lists all addresses on getaccountAddresses response * feat: implements new btc spec * feat: adds ordninals address handling * feat: sets addresses in session props * fix: types * refactor: cleanup * fix: build * feat: added btc mainnet * fix: explorer mainnet & testnet urls --------- Co-authored-by: Gancho Radkov <ganchoradkov@gmail.com>
1 parent ad24028 commit 59487b2

37 files changed

+1896
-48
lines changed

advanced/dapps/react-dapp-v2/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@kadena/types": "^0.6.0",
1919
"@multiversx/sdk-core": "12.18.0",
2020
"@multiversx/sdk-wallet": "4.2.0",
21+
"@noble/curves": "^1.6.0",
2122
"@polkadot/util-crypto": "^10.1.2",
2223
"@solana/web3.js": "^1.36.0",
2324
"@walletconnect/encoding": "^1.0.1",
@@ -26,6 +27,8 @@
2627
"@walletconnect/utils": "2.16.1",
2728
"@web3modal/standalone": "2.4.3",
2829
"axios": "^1.0.0",
30+
"bitcoinjs-lib": "^6.1.5",
31+
"bitcoinjs-message": "^2.2.0",
2932
"blockies-ts": "^1.0.0",
3033
"bs58": "^5.0.0",
3134
"cosmos-wallet": "^1.2.0",
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { NamespaceMetadata, ChainMetadata, ChainsMap } from "../helpers";
2+
3+
export const BIP122_MAINNET = "000000000019d6689c085ae165831e93";
4+
export const BIP122_TESTNET = "000000000933ea01ad0ee984209779ba";
5+
6+
export const BtcChainData: ChainsMap = {
7+
[BIP122_MAINNET]: {
8+
id: `bip122:${BIP122_MAINNET}`,
9+
name: "BTC Mainnet",
10+
rpc: [],
11+
slip44: 0,
12+
testnet: false,
13+
},
14+
[BIP122_TESTNET]: {
15+
id: `bip122:${BIP122_TESTNET}`,
16+
name: "BTC Testnet",
17+
rpc: [],
18+
slip44: 501,
19+
testnet: true,
20+
},
21+
};
22+
23+
export const BtcMetadata: NamespaceMetadata = {
24+
[BIP122_MAINNET]: {
25+
logo: "/assets/btc-testnet.png",
26+
rgb: "247, 147, 25",
27+
},
28+
[BIP122_TESTNET]: {
29+
logo: "/assets/btc-testnet.png",
30+
rgb: "247, 147, 25",
31+
},
32+
};
33+
34+
export function getChainMetadata(chainId: string): ChainMetadata {
35+
const reference = chainId.split(":")[1];
36+
const metadata = BtcMetadata[reference];
37+
if (typeof metadata === "undefined") {
38+
throw new Error(`No chain metadata found for chainId: ${chainId}`);
39+
}
40+
return metadata;
41+
}

advanced/dapps/react-dapp-v2/src/chains/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as multiversx from "./multiversx";
99
import * as tron from "./tron";
1010
import * as tezos from "./tezos";
1111
import * as kadena from "./kadena";
12+
import * as bip122 from "./bip122";
1213

1314
import { ChainMetadata, ChainRequestRender } from "../helpers";
1415

@@ -33,6 +34,8 @@ export function getChainMetadata(chainId: string): ChainMetadata {
3334
return tron.getChainMetadata(chainId);
3435
case "tezos":
3536
return tezos.getChainMetadata(chainId);
37+
case "bip122":
38+
return bip122.getChainMetadata(chainId);
3639
default:
3740
throw new Error(`No metadata handler for namespace ${namespace}`);
3841
}

advanced/dapps/react-dapp-v2/src/components/Asset.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { getChainMetadata } from "../chains";
1010
const xdaiLogo = getChainMetadata("eip155:100").logo;
1111
const maticLogo = getChainMetadata("eip155:137").logo;
1212
const kadenaLogo = getChainMetadata("kadena:testnet04").logo;
13+
const btcLogo = getChainMetadata(
14+
"bip122:000000000933ea01ad0ee984209779ba"
15+
).logo;
1316

1417
const SAsset = styled.div`
1518
width: 100%;
@@ -48,6 +51,8 @@ function getAssetIcon(asset: AssetData): JSX.Element {
4851
return <Icon src={maticLogo} />;
4952
case "kda":
5053
return <Icon src={kadenaLogo} />;
54+
case "btc":
55+
return <Icon src={btcLogo} />;
5156
default:
5257
return <Icon src={"/assets/eth20.svg"} />;
5358
}

advanced/dapps/react-dapp-v2/src/constants/default.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const DEFAULT_MAIN_CHAINS = [
1919
"tron:0x2b6653dc",
2020
"tezos:mainnet",
2121
"kadena:mainnet01",
22+
"bip122:000000000019d6689c085ae165831e93",
2223
];
2324

2425
export const DEFAULT_TEST_CHAINS = [
@@ -38,6 +39,7 @@ export const DEFAULT_TEST_CHAINS = [
3839
"tron:0xcd8690dc",
3940
"tezos:testnet",
4041
"kadena:testnet04",
42+
"bip122:000000000933ea01ad0ee984209779ba",
4143
];
4244

4345
export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS];
@@ -272,6 +274,18 @@ export enum DEFAULT_KADENA_METHODS {
272274
}
273275

274276
export enum DEFAULT_KADENA_EVENTS {}
277+
/**
278+
* BITCOIN
279+
*/
280+
export enum DEFAULT_BIP122_METHODS {
281+
BIP122_SEND_TRANSACTION = "sendTransfer",
282+
BIP122_GET_ACCOUNT_ADDRESSES = "getAccountAddresses",
283+
BIP122_SIGN_MESSAGE = "signMessage",
284+
BIP122_SIGN_PSBT = "signPsbt",
285+
}
286+
export enum DEFAULT_BIP122_EVENTS {
287+
BIP122_ADDRESS_CHANGED = "bip122_addressesChanged",
288+
}
275289

276290
export const REGIONALIZED_RELAYER_ENDPOINTS: RelayerType[] = [
277291
{

advanced/dapps/react-dapp-v2/src/contexts/ChainDataContext.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { CosmosChainData } from "../chains/cosmos";
1616
import { EIP155ChainData } from "../chains/eip155";
1717
import { TezosChainData } from "../chains/tezos";
1818
import { KadenaChainData } from "../chains/kadena";
19+
import { BtcChainData } from "../chains/bip122";
1920

2021
/**
2122
* Types
@@ -73,6 +74,9 @@ export function ChainDataContextProvider({
7374
case "kadena":
7475
chains = KadenaChainData;
7576
break;
77+
case "bip122":
78+
chains = BtcChainData;
79+
break;
7680
default:
7781
console.error("Unknown chain namespace: ", namespace);
7882
}

advanced/dapps/react-dapp-v2/src/contexts/ClientContext.tsx

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ interface IContext {
4949
setChains: any;
5050
setRelayerRegion: any;
5151
origin: string;
52+
setAccounts: any;
5253
}
5354

5455
/**
@@ -63,6 +64,16 @@ const web3Modal = new Web3Modal({
6364
projectId: DEFAULT_PROJECT_ID,
6465
themeMode: "light",
6566
walletConnectVersion: 2,
67+
mobileWallets: [
68+
{
69+
id: "bifrost",
70+
name: "Bifrost Wallet",
71+
links: {
72+
native: "bifrostwallet://",
73+
universal: "https://bifrostwallet.com",
74+
},
75+
},
76+
],
6677
});
6778

6879
/**
@@ -106,7 +117,6 @@ export function ClientContextProvider({
106117
const [namespace, reference, address] = account.split(":");
107118
const chainId = `${namespace}:${reference}`;
108119
const assets = await apiGetAccountBalance(address, chainId);
109-
110120
return { account, assets: [assets] };
111121
})
112122
);
@@ -123,6 +133,11 @@ export function ClientContextProvider({
123133
}
124134
};
125135

136+
useMemo(() => {
137+
if (!accounts.length) return;
138+
getAccountBalances(accounts);
139+
}, [accounts]);
140+
126141
const onSessionConnected = useCallback(
127142
async (_session: SessionTypes.Struct) => {
128143
const allNamespaceAccounts = Object.values(_session.namespaces)
@@ -147,26 +162,17 @@ export function ClientContextProvider({
147162
}
148163
console.log("connect, pairing topic is:", pairing?.topic);
149164
try {
150-
const requiredNamespaces = getRequiredNamespaces(chains);
151-
console.log(
152-
"requiredNamespaces config for connect:",
153-
requiredNamespaces
154-
);
155-
const optionalNamespaces = getOptionalNamespaces(chains);
156-
console.log(
157-
"optionalNamespaces config for connect:",
158-
optionalNamespaces
159-
);
165+
const namespacesToRequest = getRequiredNamespaces(chains);
160166
const { uri, approval } = await client.connect({
161167
pairingTopic: pairing?.topic,
162-
requiredNamespaces,
163-
optionalNamespaces,
168+
requiredNamespaces: {},
169+
optionalNamespaces: namespacesToRequest,
164170
});
165171

166172
// Open QRCode modal if a URI was returned (i.e. we're not connecting an existing pairing).
167173
if (uri) {
168174
// Create a flat array of all requested chains across namespaces.
169-
const standaloneChains = Object.values(requiredNamespaces)
175+
const standaloneChains = Object.values(namespacesToRequest)
170176
.map((namespace) => namespace.chains)
171177
.flat() as string[];
172178

@@ -375,6 +381,7 @@ export function ClientContextProvider({
375381
setChains,
376382
setRelayerRegion,
377383
origin,
384+
setAccounts,
378385
}),
379386
[
380387
pairings,
@@ -392,6 +399,7 @@ export function ClientContextProvider({
392399
setChains,
393400
setRelayerRegion,
394401
origin,
402+
setAccounts,
395403
]
396404
);
397405

0 commit comments

Comments
 (0)