Created
March 20, 2022 01:15
-
-
Save joeljerushan/6b6947312c8c72467658aedf03b0487d to your computer and use it in GitHub Desktop.
Solana Pay Module for Siva App
This file contains hidden or 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
import React, { Component } from 'react' | |
import { InputGroup, Button, FormControl, Row, Col, Modal } from 'react-bootstrap' | |
import { addDoc, collection, serverTimestamp } from "firebase/firestore"; | |
import { getAuth, onAuthStateChanged } from "firebase/auth"; | |
import { db } from '../../../../Firebase' | |
import { Cluster, clusterApiUrl, Connection, PublicKey, Keypair, LAMPORTS_PER_SOL, } from '@solana/web3.js'; | |
import { encodeURL, createQR, findTransactionSignature, validateTransactionSignature, } from '@solana/pay'; | |
import BigNumber from 'bignumber.js'; | |
const auth = getAuth(); | |
export default class Solana extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
amount: '', | |
showModal: false, | |
waiting: true, | |
reference: undefined, | |
uid: undefined, | |
} | |
} | |
componentDidMount(){ | |
let set = this | |
onAuthStateChanged(auth, (user) => { | |
if (user) { | |
console.log("user ", user.uid) | |
set.setState({ uid: user.uid, }) | |
} | |
}); | |
} | |
convertToNumber(value){ | |
let set = this | |
if(!isNaN(value) && Number(value) !== 0){ | |
set.setState({ amount: value }) | |
} else { | |
set.setState({ amount: '' }) | |
} | |
} | |
generateQRCode(){ | |
let set = this | |
let amount_value = Number(set.state.amount) | |
const recipient = new PublicKey('3pHDuJayFPNe1keCHbt73NGLxRxudJWfoi7LMkR5bTY5'); | |
const amount = new BigNumber(amount_value); | |
//const reference = new PublicKey('81H4W5XA9TnEjb8dRvgxxtxu2ZKKwAhcD3YCjLHgD6kW') | |
const reference = new Keypair().publicKey; | |
set.setState({ reference }) | |
const label = 'Siva Top Up'; | |
const message = 'Siva Top up to Account - #' + set.state.uid; | |
const memo = set.state.uid; | |
const url = encodeURL({ recipient, amount, reference, label, message, memo }); | |
const qrCode = createQR(url, 460,); | |
const element = document.getElementById('qr-code'); | |
qrCode.append(element); | |
setInterval(() => { | |
set.confirmPayment(); | |
}, 250); | |
} | |
async confirmPayment(){ | |
let set = this | |
let reference_state = set.state.reference | |
let amount_value = Number(set.state.amount) | |
const amount = new BigNumber(amount_value); | |
let paymentStatus = ''; | |
const connection = new Connection(clusterApiUrl('mainnet-beta'), 'confirmed'); | |
//const reference = new PublicKey('81H4W5XA9TnEjb8dRvgxxtxu2ZKKwAhcD3YCjLHgD6kW') | |
const recipient = new PublicKey('3pHDuJayFPNe1keCHbt73NGLxRxudJWfoi7LMkR5bTY5'); | |
paymentStatus = 'pending'; | |
const signatureInfo = await findTransactionSignature(connection, reference_state, undefined, 'confirmed'); | |
paymentStatus = 'confirmed'; | |
try { | |
await validateTransactionSignature(connection, signatureInfo.signature, recipient, amount, undefined, reference_state); | |
// Update payment status | |
paymentStatus = 'validated'; | |
console.log('✅ Payment validated'); | |
if(set.state.waiting === true){ | |
set.setState({ waiting: false, }) | |
set.savetoFirestore(amount_value, signatureInfo.signature) | |
} | |
} catch (error) { | |
//console.error('❌ Payment failed', error); | |
} | |
} | |
async savetoFirestore(solana_amount, signature){ | |
let set = this | |
let uid = set.state.uid | |
let doc_path = 'users/' + uid + '/solana_payments/' | |
await addDoc(collection(db, doc_path), { | |
uid: set.state.uid, | |
solana_amount, | |
recipient: '3pHDuJayFPNe1keCHbt73NGLxRxudJWfoi7LMkR5bTY5', | |
signature, | |
created: serverTimestamp(), | |
}).then(() => { | |
console.log("update success") | |
set.savetoFirestoreConvertSiviList(uid, signature, solana_amount) | |
}) | |
} | |
async savetoFirestoreConvertSiviList(uid, signature, solana_amount){ | |
let set = this | |
let doc_path = 'users_solana_payments/' | |
await addDoc(collection(db, doc_path), { | |
uid, | |
solana_amount, | |
signature, | |
sent: false, | |
created: serverTimestamp(), | |
}).then(() => { | |
console.log("update success") | |
window.location.reload() | |
}) | |
} | |
render() { | |
return ( | |
<div className='mt-3'> | |
<Row className="mt-4"> | |
<Col> | |
Amount you like to buy | |
<InputGroup className="mb-3"> | |
<InputGroup.Text id="sivi-amount">SOL</InputGroup.Text> | |
<FormControl | |
type="number" | |
placeholder="Type here" | |
value={ this.state.amount } | |
onChange={(input) => this.convertToNumber(input.target.value) } | |
aria-describedby="sivi-amount" | |
/> | |
</InputGroup> | |
{/* <span>$24 in USD</span> */} | |
</Col> | |
</Row> | |
{ | |
this.state.amount === undefined ? | |
<Button disabled={true} className='btn btn-primary px-5 siviButtonGradient'>Buy Solana</Button> | |
: | |
<Button onClick={()=> this.setState({ showModal: true, })} className='btn btn-primary px-5 siviButtonGradient'>Buy Solana</Button> | |
} | |
<Modal backdrop="static" keyboard={false} fullscreen={true} centered show={this.state.showModal} onHide={() => this.setState({ showModal: false, })} onShow={() => this.generateQRCode() }> | |
<Modal.Header closeButton={!this.state.waiting}> | |
<Modal.Title>Scan QR code using Phantom app and complete payment.</Modal.Title> | |
</Modal.Header> | |
<Modal.Body className="pe-0 pb-0"> | |
<Row> | |
<Col className="text-center mb-3"> | |
<small>Do not Close this popup untill you complete the payment.</small> | |
<div id="qr-code"></div> | |
<br/> | |
{ | |
this.state.waiting === true ? | |
<><small className="text-info">Waiting for payment.. </small></> | |
: | |
<>✅ Payment validated. Thank You</> | |
} | |
</Col> | |
</Row> | |
</Modal.Body> | |
</Modal> | |
</div> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment