Skip to content

Commit 13e9eef

Browse files
authored
Merge pull request #160 from secretkeylabs/mahmoud/eng-3760CC-transfer-runes-via-sats-connect
runes-transfer-via-sats-connect
2 parents 53e20e5 + 57115cb commit 13e9eef

File tree

5 files changed

+157
-32
lines changed

5 files changed

+157
-32
lines changed

example/package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/src/App.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { NetworkSelector } from './components/NetworkSelector';
2727
import { SendSip10 } from './components/stacks/SendSip10';
2828
import { SendStx } from './components/stacks/SendStx';
2929
import { SignTransaction } from './components/stacks/SignTransaction.tsx';
30+
import TransferRunes from './components/transferRunes/index.tsx';
3031
import { WalletType } from './components/wallet/WalletType';
3132
import { useLocalStorage } from './hooks';
3233
import { CollapseDesktop } from './layouts/CollapseDesktop';
@@ -178,11 +179,12 @@ const BitcoinMethods = () => {
178179
<SignMessage addresses={[...btcAddressInfo]} />
179180
<SendBtc network={network} />
180181
<SendInscription network={network} />
182+
<TransferRunes network={network} />
181183
<GetBtcBalance />
182-
<MintRunes network={network} addresses={[...btcAddressInfo]} />
183-
<EtchRunes network={network} addresses={[...btcAddressInfo]} />
184184
<GetRunesBalance />
185185
<GetInscriptions />
186+
<MintRunes network={network} addresses={[...btcAddressInfo]} />
187+
<EtchRunes network={network} addresses={[...btcAddressInfo]} />
186188
</>
187189
);
188190
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { useCallback, useMemo, useState } from 'react';
2+
import Wallet, { BitcoinNetworkType } from 'sats-connect';
3+
import { Button, Card, Input, Success } from '../../App.styles';
4+
5+
interface Props {
6+
network: BitcoinNetworkType;
7+
}
8+
9+
interface Recipient {
10+
address: string;
11+
runeName: string;
12+
amount: string;
13+
}
14+
15+
const TransferRunes = ({ network }: Props) => {
16+
const [recipients, setRecipients] = useState<Recipient[]>([
17+
{ address: '', runeName: '', amount: '' },
18+
]);
19+
const [txnId, setTxnId] = useState('');
20+
21+
const addRecipient = () => {
22+
setRecipients([...recipients, { address: '', runeName: '', amount: '' }]);
23+
};
24+
25+
const updateRecipient = (index: number, field: keyof Recipient, value: string) => {
26+
const updatedRecipients = [...recipients];
27+
updatedRecipients[index][field] = value;
28+
setRecipients(updatedRecipients);
29+
};
30+
31+
const removeRecipient = (index: number) => {
32+
if (recipients.length > 1) {
33+
const updatedRecipients = recipients.filter((_, i) => i !== index);
34+
setRecipients(updatedRecipients);
35+
}
36+
};
37+
38+
const onClick = useCallback(() => {
39+
(async () => {
40+
const response = await Wallet.request('runes_transfer', {
41+
recipients,
42+
});
43+
44+
if (response.status === 'error') {
45+
console.error(response.error);
46+
alert('Error sending Runes. See console for details.');
47+
return;
48+
}
49+
50+
setTxnId(response.result.txid);
51+
setRecipients([{ address: '', runeName: '', amount: '' }]);
52+
})().catch(console.error);
53+
}, [recipients]);
54+
55+
const explorerUrl = useMemo(
56+
() =>
57+
network === BitcoinNetworkType.Mainnet
58+
? `https://mempool.space/tx/${txnId}`
59+
: `https://mempool.space/testnet/tx/${txnId}`,
60+
[network, txnId]
61+
);
62+
63+
return (
64+
<Card>
65+
<h3>Send Runes</h3>
66+
{!txnId && (
67+
<>
68+
{recipients.map((recipient, index) => (
69+
<div key={index}>
70+
{index > 0 && <hr />}
71+
<h4>Recipient {index + 1}</h4>
72+
<div>
73+
<div>Rune Name</div>
74+
<Input
75+
type="text"
76+
value={recipient.runeName}
77+
onChange={(e) => updateRecipient(index, 'runeName', e.target.value)}
78+
/>
79+
</div>
80+
<div>
81+
<div>Amount</div>
82+
<Input
83+
type="text"
84+
value={recipient.amount}
85+
onChange={(e) => updateRecipient(index, 'amount', e.target.value)}
86+
/>
87+
</div>
88+
<div>
89+
<div>Address</div>
90+
<Input
91+
type="text"
92+
value={recipient.address}
93+
onChange={(e) => updateRecipient(index, 'address', e.target.value)}
94+
/>
95+
</div>
96+
</div>
97+
))}
98+
<div
99+
style={{
100+
display: 'flex',
101+
gap: 8,
102+
marginTop: 16,
103+
marginBottom: 16,
104+
}}
105+
>
106+
<Button onClick={addRecipient} className="secondary">
107+
Add Recipient
108+
</Button>
109+
{recipients.length > 1 && (
110+
<Button onClick={() => removeRecipient(recipients.length - 1)} className="secondary">
111+
Remove Recipient
112+
</Button>
113+
)}
114+
</div>
115+
<Button
116+
onClick={onClick}
117+
disabled={recipients.some((r) => !r.runeName || !r.amount || !r.address)}
118+
>
119+
Send
120+
</Button>
121+
</>
122+
)}
123+
{txnId && (
124+
<Success>
125+
Success! Click{' '}
126+
<a href={explorerUrl} target="_blank" rel="noreferrer">
127+
here
128+
</a>{' '}
129+
to see your transaction
130+
</Success>
131+
)}
132+
</Card>
133+
);
134+
};
135+
136+
export default TransferRunes;

package-lock.json

+14-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sats-connect",
3-
"version": "2.7.0",
3+
"version": "2.8.0",
44
"main": "dist/index.mjs",
55
"files": [
66
"dist"
@@ -24,7 +24,7 @@
2424
]
2525
},
2626
"dependencies": {
27-
"@sats-connect/core": "0.2.1",
27+
"@sats-connect/core": "0.2.2",
2828
"@sats-connect/make-default-provider-config": "0.0.5",
2929
"@sats-connect/ui": "0.0.6"
3030
},

0 commit comments

Comments
 (0)