</head> | </head> | ||||
<body> | <body> | ||||
<noscript>You need to enable JavaScript to run this app.</noscript> | <noscript>You need to enable JavaScript to run this app.</noscript> | ||||
<div id="root" | |||||
<span class="pay-button" | |||||
data-fa2-contract="KT1BB1uMwVvJ1M3vVHXWALs1RWdgTp1rnXTR" | data-fa2-contract="KT1BB1uMwVvJ1M3vVHXWALs1RWdgTp1rnXTR" | ||||
data-swap-contract="KT1Ed11bNukFdYSc3qQFZ2HGYdF13XU6WZ4A" | data-swap-contract="KT1Ed11bNukFdYSc3qQFZ2HGYdF13XU6WZ4A" | ||||
data-receiver="tz1hJncvXvL2VyctPE685GJPXDaRJ7dtiwjm" | data-receiver="tz1hJncvXvL2VyctPE685GJPXDaRJ7dtiwjm" | ||||
data-amount="32"></div> | |||||
data-amount="0.1" | |||||
data-redirect-success="http://freakaria.com"></span> | |||||
<!-- | <!-- | ||||
This HTML file is a template. | This HTML file is a template. | ||||
If you open it directly in the browser, you will see an empty page. | If you open it directly in the browser, you will see an empty page. |
import React, { useState, useEffect } from "react"; | import React, { useState, useEffect } from "react"; | ||||
import { TezosToolkit } from "@taquito/taquito"; | import { TezosToolkit } from "@taquito/taquito"; | ||||
import "./App.css"; | import "./App.css"; | ||||
import ConnectButton from "./components/ConnectWallet"; | import ConnectButton from "./components/ConnectWallet"; | ||||
import DisconnectButton from "./components/DisconnectWallet"; | import DisconnectButton from "./components/DisconnectWallet"; | ||||
swapContract: string, | swapContract: string, | ||||
fa2Contract: string, | fa2Contract: string, | ||||
receiver: string, | receiver: string, | ||||
amount: number | |||||
amount: number, | |||||
Tezos: TezosToolkit | |||||
setTezos: any, | |||||
redirectSuccess: string | |||||
} | } | ||||
const App = ({ | const App = ({ | ||||
swapContract, | swapContract, | ||||
fa2Contract, | fa2Contract, | ||||
receiver, | receiver, | ||||
amount | |||||
amount, | |||||
Tezos, | |||||
setTezos, | |||||
redirectSuccess | |||||
}: AppProps) => { | }: AppProps) => { | ||||
const [Tezos, setTezos] = useState<TezosToolkit>( | |||||
new TezosToolkit("https://mainnet.api.tez.ie/") | |||||
); | |||||
const [contract, setContract] = useState<any>(undefined); | const [contract, setContract] = useState<any>(undefined); | ||||
const [publicToken, setPublicToken] = useState<string | null>(""); | const [publicToken, setPublicToken] = useState<string | null>(""); | ||||
const [wallet, setWallet] = useState<any>(null); | const [wallet, setWallet] = useState<any>(null); | ||||
const [storage, setStorage] = useState<number>(0); | const [storage, setStorage] = useState<number>(0); | ||||
const [copiedPublicToken, setCopiedPublicToken] = useState<boolean>(false); | const [copiedPublicToken, setCopiedPublicToken] = useState<boolean>(false); | ||||
const [beaconConnection, setBeaconConnection] = useState<boolean>(false); | const [beaconConnection, setBeaconConnection] = useState<boolean>(false); | ||||
// Granadanet Increment/Decrement contract | |||||
const contractAddress: string = "KT1K3XVNzsmur7VRgY8CAHPUENaErzzEpe4e"; | |||||
// useEffect(() => { | |||||
// console.log(swapContract) | |||||
// }, [swapContract]) | |||||
const generateQrCode = (): { __html: string } => { | const generateQrCode = (): { __html: string } => { | ||||
const qr = qrcode(0, "L"); | const qr = qrcode(0, "L"); | ||||
return { __html: qr.createImgTag(4) }; | return { __html: qr.createImgTag(4) }; | ||||
}; | }; | ||||
if (publicToken && (!userAddress || isNaN(userBalance))) { | if (publicToken && (!userAddress || isNaN(userBalance))) { | ||||
return ( | return ( | ||||
<div className="main-box"> | <div className="main-box"> | ||||
<div id="dialog"> | |||||
<div id="content"> | |||||
<div | |||||
dangerouslySetInnerHTML={generateQrCode()} | |||||
className="text-align-center" | |||||
></div> | |||||
<p id="public-token"> | |||||
{copiedPublicToken ? ( | |||||
<span id="public-token-copy__copied"> | |||||
<i className="far fa-thumbs-up"></i> | |||||
</span> | |||||
) : ( | |||||
<span | |||||
id="public-token-copy" | |||||
onClick={() => { | |||||
if (publicToken) { | |||||
navigator.clipboard.writeText(publicToken); | |||||
setCopiedPublicToken(true); | |||||
setTimeout(() => setCopiedPublicToken(false), 2000); | |||||
} | |||||
}} | |||||
> | |||||
<i className="far fa-copy"></i> | |||||
</span> | |||||
)} | |||||
<span> | |||||
Public token: <span>{publicToken}</span> | |||||
</span> | |||||
</p> | |||||
<p className="text-align-center"> | |||||
Status: {beaconConnection ? "Connected" : "Disconnected"} | |||||
</p> | |||||
</div> | |||||
</div> | |||||
connecting | |||||
</div> | </div> | ||||
); | ); | ||||
} else if (userAddress && !isNaN(userBalance)) { | } else if (userAddress && !isNaN(userBalance)) { | ||||
Tezos={Tezos} | Tezos={Tezos} | ||||
sender={userAddress} | sender={userAddress} | ||||
FA2address={fa2Contract} | FA2address={fa2Contract} | ||||
swapContract={swapContract} | |||||
receiver={receiver} | receiver={receiver} | ||||
amountUsd={amount} | amountUsd={amount} | ||||
redirectSuccess={redirectSuccess} | |||||
/> | /> | ||||
<DisconnectButton | |||||
wallet={wallet} | |||||
setPublicToken={setPublicToken} | |||||
setUserAddress={setUserAddress} | |||||
setUserBalance={setUserBalance} | |||||
setWallet={setWallet} | |||||
setTezos={setTezos} | |||||
setBeaconConnection={setBeaconConnection} | |||||
<DisconnectButton | |||||
wallet={wallet} | |||||
setPublicToken={setPublicToken} | |||||
setUserAddress={setUserAddress} | |||||
setWallet={setWallet} | |||||
setBeaconConnection={setBeaconConnection} | |||||
setUserBalance={setUserBalance} | |||||
/> | /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
setUserAddress={setUserAddress} | setUserAddress={setUserAddress} | ||||
setUserBalance={setUserBalance} | setUserBalance={setUserBalance} | ||||
setStorage={setStorage} | setStorage={setStorage} | ||||
contractAddress={contractAddress} | |||||
// contractAddress={contractAddress} | |||||
setBeaconConnection={setBeaconConnection} | setBeaconConnection={setBeaconConnection} | ||||
wallet={wallet} | wallet={wallet} | ||||
/> | /> |
import React, { Dispatch, SetStateAction, useState, useEffect } from "react"; | import React, { Dispatch, SetStateAction, useState, useEffect } from "react"; | ||||
import { TezosToolkit } from "@taquito/taquito"; | import { TezosToolkit } from "@taquito/taquito"; | ||||
import { BeaconWallet } from "@taquito/beacon-wallet"; | import { BeaconWallet } from "@taquito/beacon-wallet"; | ||||
import { bytes2Char } from '@taquito/utils'; | |||||
import config from "./../config"; | import config from "./../config"; | ||||
interface BuyButtonProps { | interface BuyButtonProps { | ||||
Tezos: TezosToolkit, | Tezos: TezosToolkit, | ||||
FA2address: string, | FA2address: string, | ||||
swapContract: string, | |||||
sender: string, | sender: string, | ||||
receiver: string, | receiver: string, | ||||
amountUsd: number | |||||
amountUsd: number, | |||||
redirectSuccess: string | |||||
} | } | ||||
interface CoinGeckoPrice { | interface CoinGeckoPrice { | ||||
usd_market_cap: number; | usd_market_cap: number; | ||||
} | } | ||||
enum ButtonState { | |||||
CALCULATING_PRICE, | |||||
READY_TO_PAY, | |||||
AWAITING_CONFIRMATION | |||||
} | |||||
// interface TokenDetails { | |||||
// | |||||
// } | |||||
const BuyButton = ({ | const BuyButton = ({ | ||||
Tezos, | Tezos, | ||||
FA2address, | FA2address, | ||||
swapContract, | |||||
sender, | sender, | ||||
receiver, | receiver, | ||||
amountUsd | |||||
amountUsd, | |||||
redirectSuccess | |||||
}: BuyButtonProps ): JSX.Element => { | }: BuyButtonProps ): JSX.Element => { | ||||
const [tezUsd, setTezUsd] = useState<CoinGeckoPrice>(config.defaultTezPrice); | const [tezUsd, setTezUsd] = useState<CoinGeckoPrice>(config.defaultTezPrice); | ||||
const [tezPool, setTezPool] = useState<number>(0); | const [tezPool, setTezPool] = useState<number>(0); | ||||
const [tokenPool, setTokenPool] = useState<number>(0); | const [tokenPool, setTokenPool] = useState<number>(0); | ||||
const [fiat2Token, setFiat2Token] = useState<number>(0); | const [fiat2Token, setFiat2Token] = useState<number>(0); | ||||
const [tokenDetails, setTokenDetails] = useState<any>({ | |||||
symbol:"", | |||||
decimals:6 | |||||
}); | |||||
const [status, setStatus] = useState<ButtonState>(ButtonState.CALCULATING_PRICE); | |||||
const [opHash, setOpHash] = useState<string>(""); | |||||
const tezMultiplyer = 10 ** 6; | |||||
const [tokenMultiplyer, setTokenMultiplyer] = useState<number>(10 ** 6); | |||||
async function initTokenContract(coinContract:string) { | |||||
try { | |||||
const newContract = await Tezos.wallet.at(coinContract); | |||||
const newStorage: any = await newContract.storage(); | |||||
const metdata: any = await newStorage.assets.token_metadata.get(0); | |||||
console.log(metdata); | |||||
const tokenDetails = { | |||||
totalSupply: parseInt(newStorage.assets.total_supply), | |||||
name: bytes2Char(metdata['token_info'].get('name')), | |||||
symbol: bytes2Char(metdata['token_info'].get('symbol')), | |||||
description: bytes2Char(metdata['token_info'].get('description')), | |||||
thumbnailUri: bytes2Char(metdata['token_info'].get('thumbnailUri')), | |||||
decimals: parseInt(bytes2Char(metdata['token_info'].get('decimals'))), | |||||
shouldPreferSymbol: bytes2Char(metdata['token_info'].get('shouldPreferSymbol')) === 'true', | |||||
coinContractAddress: coinContract, | |||||
swapContract: swapContract, | |||||
} | |||||
setTokenMultiplyer(10 ** tokenDetails.decimals) | |||||
setTokenDetails(tokenDetails) | |||||
} catch (e) { | |||||
console.error(e) | |||||
} | |||||
} | |||||
useEffect(() => { | |||||
(async () => { | |||||
await initTokenContract(FA2address); | |||||
})(); | |||||
},[]) | |||||
useEffect(() => { | useEffect(() => { | ||||
getTezosPrice(); | getTezosPrice(); | ||||
getPoolSizes(); | getPoolSizes(); | ||||
}, []) | |||||
}, [tokenDetails]) | |||||
// calculate Price in Token | // calculate Price in Token | ||||
useEffect(() => { | useEffect(() => { | ||||
if( tezUsd.usd > 0 && | if( tezUsd.usd > 0 && | ||||
tezPool > 0 && | tezPool > 0 && | ||||
tokenPool > 0 ) { | tokenPool > 0 ) { | ||||
setFiat2Token( tokenPool / tezPool / tezUsd.usd) | |||||
setFiat2Token( tokenPool / tezPool / tezUsd.usd); | |||||
if (status<ButtonState.READY_TO_PAY) { | |||||
setStatus(ButtonState.READY_TO_PAY); | |||||
} | |||||
} else { | |||||
} | } | ||||
}, [tezUsd,tezPool,tokenPool]) | |||||
}) | |||||
const getTezosPrice = async (): Promise<void> => { | const getTezosPrice = async (): Promise<void> => { | ||||
// https://www.coingecko.com/en/api#explore-api | // https://www.coingecko.com/en/api#explore-api | ||||
} | } | ||||
const getPoolSizes = async (): Promise<void> => { | const getPoolSizes = async (): Promise<void> => { | ||||
fetch(`https://api.tzkt.io/v1/contracts/KT1F3BqwEAoa2koYX4Hz7zJ8xfGSxxAGVT8t/storage`) | |||||
fetch("https://api.tzkt.io/v1/contracts/"+tokenDetails.swapContract+"/storage") | |||||
.then(res => res.json()) | .then(res => res.json()) | ||||
.then(item => { | .then(item => { | ||||
setTezPool( parseFloat(item.storage.tez_pool) );// / tezMultiplyer; | |||||
setTokenPool( (item.storage.token_pool) );// / tokenMultiplyer; | |||||
if (item.code == 400) { } else { | |||||
setTezPool( parseFloat(item.storage.tez_pool) / tezMultiplyer); | |||||
setTokenPool( parseFloat(item.storage.token_pool) / tokenMultiplyer); | |||||
//console.log(tokenPool + " -- " + parseFloat(item.storage.token_pool)) | |||||
} | |||||
} | } | ||||
) | ) | ||||
} | } | ||||
const buyMethod = async (): Promise<void> => { | const buyMethod = async (): Promise<void> => { | ||||
makePayment(); | |||||
makePayment().then( | |||||
()=>window.location.href = redirectSuccess, | |||||
()=>console.log("something went wrong") | |||||
); | |||||
} | } | ||||
const makePayment = async (): Promise<void> => { | const makePayment = async (): Promise<void> => { | ||||
const contract = await Tezos.wallet.at(FA2address); | const contract = await Tezos.wallet.at(FA2address); | ||||
const transfer_params = [ | const transfer_params = [ | ||||
{ | { | ||||
from_: sender, | from_: sender, | ||||
txs: [{ | txs: [{ | ||||
to_: receiver, | to_: receiver, | ||||
token_id:0, | token_id:0, | ||||
amount: amountUsd * fiat2Token | |||||
amount: Math.round(amountUsd * fiat2Token * tokenMultiplyer) | |||||
}] | }] | ||||
} | } | ||||
]; | ]; | ||||
const op = await contract.methods.transfer(transfer_params).send(); | |||||
await op.confirmation(); | |||||
const op = await contract.methods.transfer(transfer_params).send() | |||||
.then((op)=>{ | |||||
setOpHash(op.opHash); | |||||
setStatus(ButtonState.AWAITING_CONFIRMATION); | |||||
op.confirmation(); | |||||
}); | |||||
} | } | ||||
return (<div><div className="sd">1 Us Dollar if worth{fiat2Token} Moneyheros</div> | |||||
<div className="buttons"> | |||||
<button | |||||
className="button" | |||||
onClick={buyMethod} | |||||
>Pay {amountUsd * fiat2Token} Moneyherocoins | |||||
return (<div className="freaPay"><div className="info"> | |||||
{status === ButtonState.CALCULATING_PRICE && <span>calculating price</span>} | |||||
{status === ButtonState.READY_TO_PAY && <span>{amountUsd} USD = {amountUsd * fiat2Token} {tokenDetails.symbol}</span>} | |||||
{status === ButtonState.AWAITING_CONFIRMATION && <span>waiting for confirmation of transaction hash {opHash}</span>} | |||||
</div> | |||||
{status === ButtonState.READY_TO_PAY && | |||||
<button | |||||
className="button pay-button" | |||||
onClick={buyMethod}>Pay | |||||
</button> | </button> | ||||
</div></div> | |||||
); | |||||
} | |||||
</div>); | |||||
// if (status == ButtonState.READY_TO_PAY) { | |||||
// return (<div className="freaPay"><div className="info">{amountUsd} USD = {amountUsd * fiat2Token} {tokenDetails.symbol}</div> | |||||
// <div className="buttons"> | |||||
// | |||||
// | |||||
// <button | |||||
// className="button pay-button" | |||||
// onClick={buyMethod} | |||||
// >Pay {amountUsd * fiat2Token} {tokenDetails.symbol} | |||||
// </button> | |||||
// </div></div> | |||||
// ); | |||||
// } else if (status == ButtonState.CALCULATING_PRICE) { | |||||
// return (<div> calculating price</div>); | |||||
// } else if (status == ButtonState.AWAITING_CONFIRMATION) { | |||||
// return (<div>waiting for confirmation</div>); | |||||
// } else return (<div>an error has occured...</div>); | |||||
}; | }; | ||||
export default BuyButton; | export default BuyButton; |
setUserAddress: Dispatch<SetStateAction<string>>; | setUserAddress: Dispatch<SetStateAction<string>>; | ||||
setUserBalance: Dispatch<SetStateAction<number>>; | setUserBalance: Dispatch<SetStateAction<number>>; | ||||
setStorage: Dispatch<SetStateAction<number>>; | setStorage: Dispatch<SetStateAction<number>>; | ||||
contractAddress: string; | |||||
// contractAddress: string; | |||||
setBeaconConnection: Dispatch<SetStateAction<boolean>>; | setBeaconConnection: Dispatch<SetStateAction<boolean>>; | ||||
setPublicToken: Dispatch<SetStateAction<string | null>>; | setPublicToken: Dispatch<SetStateAction<string | null>>; | ||||
wallet: BeaconWallet; | wallet: BeaconWallet; | ||||
setUserAddress, | setUserAddress, | ||||
setUserBalance, | setUserBalance, | ||||
setStorage, | setStorage, | ||||
contractAddress, | |||||
// contractAddress, | |||||
setBeaconConnection, | setBeaconConnection, | ||||
setPublicToken, | setPublicToken, | ||||
wallet | wallet | ||||
const balance = await Tezos.tz.getBalance(userAddress); | const balance = await Tezos.tz.getBalance(userAddress); | ||||
setUserBalance(balance.toNumber()); | setUserBalance(balance.toNumber()); | ||||
// creates contract instance | // creates contract instance | ||||
const contract = await Tezos.wallet.at(contractAddress); | |||||
const storage: any = await contract.storage(); | |||||
setContract(contract); | |||||
setStorage(storage.toNumber()); | |||||
//const contract = await Tezos.wallet.at(contractAddress); | |||||
//const storage: any = await contract.storage(); | |||||
//setContract(contract); | |||||
//setStorage(storage.toNumber()); | |||||
}; | }; | ||||
const connectWallet = async (): Promise<void> => { | const connectWallet = async (): Promise<void> => { |
setUserAddress: Dispatch<SetStateAction<string>>; | setUserAddress: Dispatch<SetStateAction<string>>; | ||||
setUserBalance: Dispatch<SetStateAction<number>>; | setUserBalance: Dispatch<SetStateAction<number>>; | ||||
setWallet: Dispatch<SetStateAction<any>>; | setWallet: Dispatch<SetStateAction<any>>; | ||||
setTezos: Dispatch<SetStateAction<TezosToolkit>>; | |||||
//setTezos: Dispatch<SetStateAction<TezosToolkit>>; | |||||
setBeaconConnection: Dispatch<SetStateAction<boolean>>; | setBeaconConnection: Dispatch<SetStateAction<boolean>>; | ||||
} | } | ||||
setUserAddress, | setUserAddress, | ||||
setUserBalance, | setUserBalance, | ||||
setWallet, | setWallet, | ||||
setTezos, | |||||
//setTezos, | |||||
setBeaconConnection | setBeaconConnection | ||||
}: ButtonProps): JSX.Element => { | }: ButtonProps): JSX.Element => { | ||||
const disconnectWallet = async (): Promise<void> => { | const disconnectWallet = async (): Promise<void> => { | ||||
setUserAddress(""); | setUserAddress(""); | ||||
setUserBalance(0); | setUserBalance(0); | ||||
setWallet(null); | setWallet(null); | ||||
const tezosTK = new TezosToolkit("https://api.tez.ie/rpc/granadanet"); | |||||
setTezos(tezosTK); | |||||
//const tezosTK = new TezosToolkit("https://api.tez.ie/rpc/granadanet"); | |||||
//setTezos(tezosTK); | |||||
setBeaconConnection(false); | setBeaconConnection(false); | ||||
setPublicToken(null); | setPublicToken(null); | ||||
console.log("disconnecting wallet"); | console.log("disconnecting wallet"); |
import React from "react"; | |||||
import React, {useState} from "react"; | |||||
import ReactDOM from "react-dom"; | import ReactDOM from "react-dom"; | ||||
import App from "./App.tsx"; | import App from "./App.tsx"; | ||||
import * as serviceWorker from "./serviceWorker"; | import * as serviceWorker from "./serviceWorker"; | ||||
const appNode = document.getElementById("root"); | |||||
if (appNode) { | |||||
ReactDOM.render( | |||||
<React.StrictMode> | |||||
<App | |||||
swapContract={appNode.dataset.swapContract} | |||||
fa2Contract={appNode.dataset.fa2Contract} | |||||
receiver={appNode.dataset.receiver} | |||||
amount={appNode.dataset.amount} | |||||
/> | |||||
</React.StrictMode>, | |||||
document.getElementById("root") | |||||
); | |||||
import { TezosToolkit } from "@taquito/taquito"; | |||||
import { BeaconWallet } from "@taquito/beacon-wallet"; | |||||
import { | |||||
NetworkType, | |||||
BeaconEvent, | |||||
defaultEventCallbacks | |||||
} from "@airgap/beacon-sdk"; | |||||
const appNodes = document.getElementsByClassName("pay-button"); | |||||
function setPublicToken(pubKey) { | |||||
console.log("successfully connected to "+pubKey); | |||||
} | |||||
if (appNodes) { | |||||
// const [Tezos, setTezos] = useState<TezosToolkit>( | |||||
// new TezosToolkit("https://mainnet.api.tez.ie/") | |||||
// ); | |||||
const Tezos = new TezosToolkit("https://mainnet.api.tez.ie/"); | |||||
// const wallet = new BeaconWallet({ | |||||
// name: "freaPay", | |||||
// preferredNetwork: NetworkType.MAINNET, | |||||
// disableDefaultEvents: true, // Disable all events / UI. This also disables the pairing alert. | |||||
// eventHandlers: { | |||||
// // To keep the pairing alert, we have to add the following default event handlers back | |||||
// [BeaconEvent.PAIR_INIT]: { | |||||
// handler: defaultEventCallbacks.PAIR_INIT | |||||
// }, | |||||
// [BeaconEvent.PAIR_SUCCESS]: { | |||||
// handler: data => setPublicToken(data.publicKey) | |||||
// } | |||||
// } | |||||
// }); | |||||
for (var i = 0; i<appNodes.length; i++) { | |||||
let appNode = appNodes[i]; | |||||
ReactDOM.render( | |||||
<React.StrictMode> | |||||
<App | |||||
swapContract={appNode.dataset.swapContract} | |||||
fa2Contract={appNode.dataset.fa2Contract} | |||||
receiver={appNode.dataset.receiver} | |||||
amount={appNode.dataset.amount} | |||||
redirectSuccess={appNode.dataset.redirectSuccess} | |||||
Tezos={Tezos} | |||||
/> | |||||
</React.StrictMode>, | |||||
appNode | |||||
//document.getElementsByClassName("c") | |||||
); | |||||
} | |||||
} | } | ||||
// If you want your app to work offline and load faster, you can change | // If you want your app to work offline and load faster, you can change | ||||
// unregister() to register() below. Note this comes with some pitfalls. | // unregister() to register() below. Note this comes with some pitfalls. | ||||
// Learn more about service workers: https://bit.ly/CRA-PWA | // Learn more about service workers: https://bit.ly/CRA-PWA | ||||
serviceWorker.unregister(); | |||||
//serviceWorker.unregister(); |