-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a64689
commit bae43a7
Showing
15 changed files
with
656 additions
and
38 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { useConnection, useWallet } from "@solana/wallet-adapter-react"; | ||
import { PublicKey, Transaction, TransactionSignature } from "@solana/web3.js"; | ||
import axios from "axios"; | ||
import { PostError, PostResponse } from "pages/api/transaction"; | ||
import { FC, useCallback } from "react"; | ||
import { notify } from "../utils/notifications"; | ||
import { useNetworkConfiguration } from "../contexts/NetworkConfigurationProvider"; | ||
|
||
type SendTransactionRequestProps = { | ||
reference: PublicKey; | ||
}; | ||
|
||
export const SendTransactionRequest: FC<SendTransactionRequestProps> = ({ | ||
reference, | ||
}) => { | ||
const { connection } = useConnection(); | ||
const { publicKey, sendTransaction } = useWallet(); | ||
const { networkConfiguration } = useNetworkConfiguration(); | ||
|
||
const onClick = useCallback(async () => { | ||
if (!publicKey) { | ||
notify({ type: "error", message: `Wallet not connected!` }); | ||
console.error("Send Transaction: Wallet not connected!"); | ||
return; | ||
} | ||
|
||
let signature: TransactionSignature = ""; | ||
try { | ||
// Request the transaction from transaction request API | ||
const { data } = await axios.post( | ||
`/api/transaction?network=${networkConfiguration}&reference=${reference.toBase58()}`, | ||
{ | ||
account: publicKey, | ||
}, | ||
{ | ||
// Don't throw for 4xx responses, we handle them | ||
validateStatus: (s) => s < 500, | ||
} | ||
); | ||
|
||
const response = data as PostResponse | PostError; | ||
|
||
if ("error" in response) { | ||
console.error(`Failed to fetch transaction! ${response.error}`); | ||
notify({ | ||
type: "error", | ||
message: "Failed to fetch transaction!", | ||
description: response.error, | ||
}); | ||
return; | ||
} | ||
|
||
const message = response.message; | ||
notify({ | ||
type: "info", | ||
message: "Fetched transaction!", | ||
description: `message: ${message}`, | ||
}); | ||
|
||
// De-serialize the returned transaction | ||
const transaction = Transaction.from( | ||
Buffer.from(response.transaction, "base64") | ||
); | ||
|
||
// Debug: log current and expected signers of the transaction | ||
// The API can return a partially signed transaction | ||
console.log("Fetched transaction", transaction); | ||
const currentSigners = [ | ||
...new Set( | ||
transaction.signatures | ||
.filter((k) => k.signature !== null) | ||
.map((k) => k.publicKey.toBase58()) | ||
), | ||
]; | ||
const expectedSigners = [ | ||
...new Set( | ||
transaction.instructions.flatMap((i) => | ||
i.keys.filter((k) => k.isSigner).map((k) => k.pubkey.toBase58()) | ||
) | ||
), | ||
]; | ||
console.log({ | ||
currentSigners, | ||
expectedSigners, | ||
transaction: response.transaction, | ||
}); | ||
|
||
// Send the transaction | ||
await sendTransaction(transaction, connection); | ||
} catch (error: any) { | ||
notify({ | ||
type: "error", | ||
message: `Transaction failed!`, | ||
description: error?.message, | ||
txid: signature, | ||
}); | ||
console.error(`Transaction failed! ${error?.message}`, signature); | ||
return; | ||
} | ||
}, [publicKey, networkConfiguration, reference, sendTransaction, connection]); | ||
|
||
return ( | ||
<div> | ||
<button | ||
className="group w-60 m-2 btn animate-pulse disabled:animate-none bg-gradient-to-r from-[#9945FF] to-[#14F195] hover:from-pink-500 hover:to-yellow-500 ... " | ||
onClick={onClick} | ||
disabled={!publicKey} | ||
> | ||
<div className="hidden group-disabled:block ">Wallet not connected</div> | ||
<span className="block group-disabled:hidden">Send with wallet</span> | ||
</button> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { useConnection, useWallet } from "@solana/wallet-adapter-react"; | ||
import { | ||
Keypair, | ||
LAMPORTS_PER_SOL, | ||
PublicKey, | ||
SystemProgram, | ||
Transaction, | ||
TransactionSignature, | ||
} from "@solana/web3.js"; | ||
import { FC, useCallback } from "react"; | ||
import { notify } from "../utils/notifications"; | ||
|
||
type SendTransferRequestProps = { | ||
reference: PublicKey; | ||
}; | ||
|
||
export const SendTransferRequest: FC<SendTransferRequestProps> = ({ | ||
reference, | ||
}) => { | ||
const { connection } = useConnection(); | ||
const { publicKey, sendTransaction } = useWallet(); | ||
|
||
const onClick = useCallback(async () => { | ||
if (!publicKey) { | ||
notify({ type: "error", message: `Wallet not connected!` }); | ||
console.error("Send Transaction: Wallet not connected!"); | ||
return; | ||
} | ||
|
||
let signature: TransactionSignature = ""; | ||
try { | ||
const { blockhash, lastValidBlockHeight } = | ||
await connection.getLatestBlockhash(); | ||
|
||
// Transfer transaction | ||
const transaction = new Transaction({ | ||
feePayer: publicKey, | ||
blockhash, | ||
lastValidBlockHeight, | ||
}); | ||
|
||
const transferInstruction = SystemProgram.transfer({ | ||
fromPubkey: publicKey, | ||
toPubkey: Keypair.generate().publicKey, | ||
lamports: LAMPORTS_PER_SOL / 1000, | ||
}); | ||
|
||
// Add reference as a key to the instruction | ||
transferInstruction.keys.push({ | ||
pubkey: reference, | ||
isSigner: false, | ||
isWritable: false, | ||
}); | ||
|
||
transaction.add(transferInstruction); | ||
|
||
// Debug: log current and expected signers of the transaction | ||
console.log("Created transaction", transaction); | ||
const currentSigners = transaction.signatures | ||
.filter((k) => k.signature !== null) | ||
.map((k) => k.publicKey.toBase58()); | ||
const expectedSigners = transaction.instructions.flatMap((i) => | ||
i.keys.filter((k) => k.isSigner).map((k) => k.pubkey.toBase58()) | ||
); | ||
console.log({ currentSigners, expectedSigners }); | ||
|
||
// Send the transaction | ||
await sendTransaction(transaction, connection); | ||
} catch (error: any) { | ||
notify({ | ||
type: "error", | ||
message: `Transaction failed!`, | ||
description: error?.message, | ||
txid: signature, | ||
}); | ||
console.error(`Transaction failed! ${error?.message}`, signature); | ||
return; | ||
} | ||
}, [publicKey, connection, reference, sendTransaction]); | ||
|
||
return ( | ||
<div> | ||
<button | ||
className="group w-60 m-2 btn animate-pulse disabled:animate-none bg-gradient-to-r from-[#9945FF] to-[#14F195] hover:from-pink-500 hover:to-yellow-500 ... " | ||
onClick={onClick} | ||
disabled={!publicKey} | ||
> | ||
<div className="hidden group-disabled:block ">Wallet not connected</div> | ||
<span className="block group-disabled:hidden">Send with wallet</span> | ||
</button> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { createQR, encodeURL, TransactionRequestURLFields } from "@solana/pay"; | ||
import { PublicKey } from "@solana/web3.js"; | ||
import { useNetworkConfiguration } from "contexts/NetworkConfigurationProvider"; | ||
import { FC, useEffect, useRef } from "react"; | ||
|
||
type TransactionRequestQRProps = { | ||
reference: PublicKey; | ||
}; | ||
|
||
export const TransactionRequestQR: FC<TransactionRequestQRProps> = ({ | ||
reference, | ||
}) => { | ||
const qrRef = useRef<HTMLDivElement>(null); | ||
const { networkConfiguration } = useNetworkConfiguration(); | ||
|
||
useEffect(() => { | ||
// window.location is only available in the browser, so create the URL in here | ||
const { location } = window; | ||
const apiUrl = `${location.protocol}//${ | ||
location.host | ||
}/api/transaction?network=${networkConfiguration}&reference=${reference.toBase58()}`; | ||
const urlParams: TransactionRequestURLFields = { | ||
link: new URL(apiUrl), | ||
label: "My Store", | ||
}; | ||
const solanaUrl = encodeURL(urlParams); | ||
const qr = createQR(solanaUrl, 512, "transparent"); | ||
qr.update({ backgroundOptions: { round: 1000 } }); | ||
if (qrRef.current) { | ||
qrRef.current.innerHTML = ""; | ||
qr.append(qrRef.current); | ||
} | ||
}, [networkConfiguration, reference]); | ||
|
||
return ( | ||
<div className="rounded-2xl"> | ||
<div ref={qrRef} /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { createQR, encodeURL, TransferRequestURLFields } from "@solana/pay"; | ||
import { Keypair, PublicKey } from "@solana/web3.js"; | ||
import BigNumber from "bignumber.js"; | ||
import { FC, useEffect, useRef } from "react"; | ||
|
||
type TransferRequestQRProps = { | ||
reference: PublicKey; | ||
}; | ||
|
||
export const TransferRequestQR: FC<TransferRequestQRProps> = ({ | ||
reference, | ||
}) => { | ||
const qrRef = useRef<HTMLDivElement>(null); | ||
|
||
useEffect(() => { | ||
// Create a transfer request QR code | ||
const urlParams: TransferRequestURLFields = { | ||
recipient: Keypair.generate().publicKey, | ||
amount: new BigNumber(1 / 1000), // amount in SOL | ||
reference, | ||
label: "My Store", | ||
message: "Thankyou for your purchase!", | ||
}; | ||
const solanaUrl = encodeURL(urlParams); | ||
const qr = createQR(solanaUrl, 512, "transparent"); | ||
qr.update({ backgroundOptions: { round: 1000 } }); | ||
if (qrRef.current) { | ||
qrRef.current.innerHTML = ""; | ||
qr.append(qrRef.current); | ||
} | ||
}, [reference]); | ||
|
||
return ( | ||
<div className="rounded-2xl"> | ||
<div ref={qrRef} /> | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.