@@ -19,11 +19,14 @@ | |||
</head> | |||
<body> | |||
<noscript>You need to enable JavaScript to run this app.</noscript> | |||
<div id="root" | |||
<span class="pay-button" | |||
data-fa2-contract="KT1BB1uMwVvJ1M3vVHXWALs1RWdgTp1rnXTR" | |||
data-swap-contract="KT1Ed11bNukFdYSc3qQFZ2HGYdF13XU6WZ4A" | |||
data-receiver="tz1hJncvXvL2VyctPE685GJPXDaRJ7dtiwjm" | |||
data-amount="32"></div> | |||
data-amount="0.1" | |||
data-redirect-success="http://freakaria.com"></span> | |||
<!-- | |||
This HTML file is a template. | |||
If you open it directly in the browser, you will see an empty page. |
@@ -1,5 +1,7 @@ | |||
import React, { useState, useEffect } from "react"; | |||
import { TezosToolkit } from "@taquito/taquito"; | |||
import "./App.css"; | |||
import ConnectButton from "./components/ConnectWallet"; | |||
import DisconnectButton from "./components/DisconnectWallet"; | |||
@@ -20,18 +22,22 @@ type AppProps = { | |||
swapContract: string, | |||
fa2Contract: string, | |||
receiver: string, | |||
amount: number | |||
amount: number, | |||
Tezos: TezosToolkit | |||
setTezos: any, | |||
redirectSuccess: string | |||
} | |||
const App = ({ | |||
swapContract, | |||
fa2Contract, | |||
receiver, | |||
amount | |||
amount, | |||
Tezos, | |||
setTezos, | |||
redirectSuccess | |||
}: AppProps) => { | |||
const [Tezos, setTezos] = useState<TezosToolkit>( | |||
new TezosToolkit("https://mainnet.api.tez.ie/") | |||
); | |||
const [contract, setContract] = useState<any>(undefined); | |||
const [publicToken, setPublicToken] = useState<string | null>(""); | |||
const [wallet, setWallet] = useState<any>(null); | |||
@@ -40,14 +46,7 @@ const App = ({ | |||
const [storage, setStorage] = useState<number>(0); | |||
const [copiedPublicToken, setCopiedPublicToken] = 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 qr = qrcode(0, "L"); | |||
@@ -56,45 +55,13 @@ const App = ({ | |||
return { __html: qr.createImgTag(4) }; | |||
}; | |||
if (publicToken && (!userAddress || isNaN(userBalance))) { | |||
return ( | |||
<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> | |||
); | |||
} else if (userAddress && !isNaN(userBalance)) { | |||
@@ -107,17 +74,18 @@ const App = ({ | |||
Tezos={Tezos} | |||
sender={userAddress} | |||
FA2address={fa2Contract} | |||
swapContract={swapContract} | |||
receiver={receiver} | |||
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> | |||
@@ -134,7 +102,7 @@ const App = ({ | |||
setUserAddress={setUserAddress} | |||
setUserBalance={setUserBalance} | |||
setStorage={setStorage} | |||
contractAddress={contractAddress} | |||
// contractAddress={contractAddress} | |||
setBeaconConnection={setBeaconConnection} | |||
wallet={wallet} | |||
/> |
@@ -1,15 +1,21 @@ | |||
import React, { Dispatch, SetStateAction, useState, useEffect } from "react"; | |||
import { TezosToolkit } from "@taquito/taquito"; | |||
import { BeaconWallet } from "@taquito/beacon-wallet"; | |||
import { bytes2Char } from '@taquito/utils'; | |||
import config from "./../config"; | |||
interface BuyButtonProps { | |||
Tezos: TezosToolkit, | |||
FA2address: string, | |||
swapContract: string, | |||
sender: string, | |||
receiver: string, | |||
amountUsd: number | |||
amountUsd: number, | |||
redirectSuccess: string | |||
} | |||
interface CoinGeckoPrice { | |||
@@ -20,32 +26,89 @@ interface CoinGeckoPrice { | |||
usd_market_cap: number; | |||
} | |||
enum ButtonState { | |||
CALCULATING_PRICE, | |||
READY_TO_PAY, | |||
AWAITING_CONFIRMATION | |||
} | |||
// interface TokenDetails { | |||
// | |||
// } | |||
const BuyButton = ({ | |||
Tezos, | |||
FA2address, | |||
swapContract, | |||
sender, | |||
receiver, | |||
amountUsd | |||
amountUsd, | |||
redirectSuccess | |||
}: BuyButtonProps ): JSX.Element => { | |||
const [tezUsd, setTezUsd] = useState<CoinGeckoPrice>(config.defaultTezPrice); | |||
const [tezPool, setTezPool] = useState<number>(0); | |||
const [tokenPool, setTokenPool] = 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(() => { | |||
getTezosPrice(); | |||
getPoolSizes(); | |||
}, []) | |||
}, [tokenDetails]) | |||
// calculate Price in Token | |||
useEffect(() => { | |||
if( tezUsd.usd > 0 && | |||
tezPool > 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> => { | |||
// https://www.coingecko.com/en/api#explore-api | |||
@@ -55,48 +118,78 @@ const BuyButton = ({ | |||
} | |||
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(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> => { | |||
makePayment(); | |||
makePayment().then( | |||
()=>window.location.href = redirectSuccess, | |||
()=>console.log("something went wrong") | |||
); | |||
} | |||
const makePayment = async (): Promise<void> => { | |||
const contract = await Tezos.wallet.at(FA2address); | |||
const transfer_params = [ | |||
{ | |||
from_: sender, | |||
txs: [{ | |||
to_: receiver, | |||
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> | |||
</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; |
@@ -16,7 +16,7 @@ type ButtonProps = { | |||
setUserAddress: Dispatch<SetStateAction<string>>; | |||
setUserBalance: Dispatch<SetStateAction<number>>; | |||
setStorage: Dispatch<SetStateAction<number>>; | |||
contractAddress: string; | |||
// contractAddress: string; | |||
setBeaconConnection: Dispatch<SetStateAction<boolean>>; | |||
setPublicToken: Dispatch<SetStateAction<string | null>>; | |||
wallet: BeaconWallet; | |||
@@ -29,7 +29,7 @@ const ConnectButton = ({ | |||
setUserAddress, | |||
setUserBalance, | |||
setStorage, | |||
contractAddress, | |||
// contractAddress, | |||
setBeaconConnection, | |||
setPublicToken, | |||
wallet | |||
@@ -42,10 +42,10 @@ const ConnectButton = ({ | |||
const balance = await Tezos.tz.getBalance(userAddress); | |||
setUserBalance(balance.toNumber()); | |||
// 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> => { |
@@ -8,7 +8,7 @@ interface ButtonProps { | |||
setUserAddress: Dispatch<SetStateAction<string>>; | |||
setUserBalance: Dispatch<SetStateAction<number>>; | |||
setWallet: Dispatch<SetStateAction<any>>; | |||
setTezos: Dispatch<SetStateAction<TezosToolkit>>; | |||
//setTezos: Dispatch<SetStateAction<TezosToolkit>>; | |||
setBeaconConnection: Dispatch<SetStateAction<boolean>>; | |||
} | |||
@@ -18,7 +18,7 @@ const DisconnectButton = ({ | |||
setUserAddress, | |||
setUserBalance, | |||
setWallet, | |||
setTezos, | |||
//setTezos, | |||
setBeaconConnection | |||
}: ButtonProps): JSX.Element => { | |||
const disconnectWallet = async (): Promise<void> => { | |||
@@ -26,8 +26,8 @@ const DisconnectButton = ({ | |||
setUserAddress(""); | |||
setUserBalance(0); | |||
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); | |||
setPublicToken(null); | |||
console.log("disconnecting wallet"); |
@@ -1,25 +1,65 @@ | |||
import React from "react"; | |||
import React, {useState} from "react"; | |||
import ReactDOM from "react-dom"; | |||
import App from "./App.tsx"; | |||
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 | |||
// unregister() to register() below. Note this comes with some pitfalls. | |||
// Learn more about service workers: https://bit.ly/CRA-PWA | |||
serviceWorker.unregister(); | |||
//serviceWorker.unregister(); |