Skip to content

Instantly share code, notes, and snippets.

@joeljerushan
Created March 20, 2022 01:15
Show Gist options
  • Save joeljerushan/6b6947312c8c72467658aedf03b0487d to your computer and use it in GitHub Desktop.
Save joeljerushan/6b6947312c8c72467658aedf03b0487d to your computer and use it in GitHub Desktop.
Solana Pay Module for Siva App
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