Skip to content

Commit

Permalink
Merge pull request #46 from input-output-hk/DAC-289
Browse files Browse the repository at this point in the history
DAC-289 Transaction payment by the Customer
  • Loading branch information
amnambiar authored Feb 9, 2023
2 parents 3688178 + 6bcf960 commit aa9bb93
Show file tree
Hide file tree
Showing 18 changed files with 10,463 additions and 6,899 deletions.
24 changes: 24 additions & 0 deletions react-web/config-overrides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const webpack = require('webpack');

module.exports = function override(webpackConfig, env) {
const wasmExtensionRegExp = /\.wasm$/;
webpackConfig.resolve.extensions.push('.wasm');
webpackConfig.experiments = {
asyncWebAssembly: true,
//lazyCompilation: true,
syncWebAssembly: true,
topLevelAwait: true,
};
webpackConfig.module.rules.forEach((rule) => {
(rule.oneOf || []).forEach((oneOf) => {
if (oneOf.type === "asset/resource") {
oneOf.exclude.push(wasmExtensionRegExp);
}
});
});
webpackConfig.plugins.push(new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}));

return webpackConfig;
}
16,942 changes: 10,097 additions & 6,845 deletions react-web/package-lock.json

Large diffs are not rendered by default.

23 changes: 14 additions & 9 deletions react-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
"name": "react-web",
"version": "0.1.0",
"private": true,
"proxy": "https://testing.dapps.iog.io/",
"homepage": "https://input-output-hk.github.io/dapps-certification/",
"proxy": "http://excuse.ro:9672/",
"homepage": "http://localhost:3000/",
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@emurgo/cardano-serialization-lib-browser": "^11.2.1",
"@hookform/resolvers": "^2.9.7",
"@mui/icons-material": "5.10.14",
"@mui/material": "5.10.14",
Expand All @@ -20,6 +21,7 @@
"@types/react-dom": "^18.0.6",
"@types/react-table": "^7.7.12",
"axios": "^0.27.2",
"buffer": "^6.0.3",
"dayjs": "^1.11.7",
"html-react-parser": "^3.0.4",
"node-sass": "^7.0.1",
Expand All @@ -33,16 +35,15 @@
"react-table": "^7.8.0",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4",
"yup": "^0.32.11",
"zod": "^3.17.10"
"yup": "^0.32.11"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"build:production": "REACT_APP_ENV=production yarn build",
"test": "react-scripts test --passWithNoTests",
"test:coverage": "react-scripts test --coverage --passWithNoTests",
"eject": "react-scripts eject"
"test": "react-app-rewired test --passWithNoTests",
"test:coverage": "react-app-rewired test --coverage --passWithNoTests",
"eject": "react-app-rewired eject"
},
"eslintConfig": {
"extends": [
Expand All @@ -61,5 +62,9 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"react-app-rewired": "^2.2.1",
"webpack-cli": "^5.0.1"
}
}
Binary file added react-web/public/images/back.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions react-web/src/app/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@
header button {
float: right;
margin: 10px;
}

section > svg.spinner {
top: 100px;
left: 50%;
}
4 changes: 3 additions & 1 deletion react-web/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const PageLayout = () => {
<Header />
{/* Load page content here */}
<section data-testid="contentWrapper" id="contentWrapper">
<Outlet />
<Suspense fallback={<Loader />}>
<Outlet />
</Suspense>
</section>
</>
);
Expand Down
41 changes: 30 additions & 11 deletions react-web/src/components/ConnectWallet/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, { useEffect, useState, useCallback } from "react";
import './ConnectWallet.scss';
import { Address } from "@emurgo/cardano-serialization-lib-browser";
import { useAppDispatch } from "store/store";
import { getProfileDetails } from "store/slices/auth.slice";

import Modal from "components/Modal/Modal";
import Button from "components/Button/Button";
import Loader from "components/Loader/Loader";

import { useAppDispatch } from "store/store";
import { getProfileDetails } from "store/slices/auth.slice";
import './ConnectWallet.scss';

const wallets: Array<string> = ['lace', 'nami', 'yoroi']

Expand All @@ -18,31 +21,46 @@ let CardanoNS = window.cardano;
const ConnectWallet = () => {
const dispatch = useAppDispatch();
const [wallet, setWallet] = useState(null)
const [address, setAddress] = useState(null)
const [walletName, setWalletName] = useState("")
const [address, setAddress] = useState("")
const [isOpen, setIsOpen] = useState(false)
const [walletLoading, setWalletLoading] = useState(false)

const openConnectWalletModal = useCallback(() => setIsOpen(true),[])

const onCloseModal = useCallback(() => setIsOpen(false),[])

const loadWallet = async (walletName: string) => {
try {
setWalletLoading(true)
const enabledWallet = await CardanoNS[walletName].enable();
setWallet(enabledWallet)
setWalletName(walletName)
if (enabledWallet) {
setAddress(await enabledWallet.getChangeAddress())
const response = await enabledWallet.getChangeAddress()
setAddress(Address.from_bytes(Buffer.from(response, "hex")).to_bech32())
}
} catch (err) {
// do nothing
console.log(err);
}
} catch (e) { handleError(e); }
}

const handleError = (err: any) => {
console.log(err)
}

useEffect(() => {
if (address) {
dispatch(getProfileDetails({"address": address, "wallet": wallet}))
(async () => {
try {
const response: any = await dispatch(getProfileDetails({"address": address, "wallet": wallet, "walletName": walletName})).catch(handleError)
setWalletLoading(false)
} catch(error) {
setWalletLoading(false)
handleError(error)
// dispatch(clearCache())
}
})()
}
}, [dispatch, address, wallet])
}, [dispatch, address, wallet, walletName])

return (
<>
Expand All @@ -69,6 +87,7 @@ const ConnectWallet = () => {
}
})
}
{ walletLoading ? <Loader /> : null}
</div>
</Modal>
</>
Expand Down
155 changes: 155 additions & 0 deletions react-web/src/components/CreateCertificate/CreateCertificate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { useState } from "react";
import { useAppSelector } from "store/store";

import Button from "components/Button/Button";
import Modal from "components/Modal/Modal";


import { Address,
Value,
BigNum,
LinearFee,
TransactionBuilderConfigBuilder,
TransactionUnspentOutputs,
TransactionUnspentOutput,
TransactionBuilder,
TransactionWitnessSet,
Transaction,
TransactionOutput,
CoinSelectionStrategyCIP2
} from '@emurgo/cardano-serialization-lib-browser';
import Toast from "components/Toast/Toast";
import { fetchData } from "api/api";

const CreateCertificate = () => {
const { uuid } = useAppSelector((state) => state.certification);
const { address, wallet } = useAppSelector((state) => state.auth);
const [ certifying, setCertifying ] = useState(false);
const [ certified, setCertified ] = useState(false);
const [ transactionId, setTransactionId ] = useState("")
const [ showError, setShowError ] = useState("");
const [ openModal, setOpenModal ] = useState(false);
const [ disableCertify, setDisableCertify ] = useState(false);

const onCloseModal = () => { setOpenModal(false) }

const handleError = (errorObj: any) => {
let errorMsg = ''
if (typeof errorObj === 'string') {
errorMsg = errorObj + ' Please try again.'
} else if (errorObj?.info) {
errorMsg = errorObj.info + ' Please try again.'
} else if (errorObj?.response?.message) {
errorMsg = errorObj?.response.message + ' Please try again.'
} else if (errorObj?.response?.data) {
errorMsg = errorObj.response.statusText + ' - ' + errorObj.response.data
}
setShowError(errorMsg.length > 50 ? 'Something wrong occurred. Please try again later.' : errorMsg);
const timeout = setTimeout(() => { clearTimeout(timeout); setShowError("") }, 5000)
setCertifying(false);
if (errorObj?.response?.status === 403) {
setDisableCertify(true)
}
}

const triggerSubmitCertificate = async (txnId: string) => {
const response: any = await fetchData.post('/run/' + uuid + '/certificate' + '?transactionid=' + txnId).catch(handleError)
try {
console.log('broadcasted tnx data ', response.data);
setTransactionId(response.data.transactionId)
setOpenModal(true)
setCertifying(false)
setCertified(true)
} catch(e) { }
}

const triggerGetCertificate = async () => {
setCertifying(true);
setShowError("")
try {
const walletAddressRes: any = await fetchData.get('/wallet-address').catch(handleError)
const applicationWallet_receiveAddr = walletAddressRes.data;
/** For mock */
// const applicationWallet_receiveAddr = 'addr_test1qz2rzeqq8n82gajfp35enq3mxhaynx6zhuql2c7yaljr25mfaznfszxu8275k6v7n05w5azzmxahfzdq564xuuyg73pqnqtrrc'
/** To be replaced with API */
const cert_fee_ada = 3
const cert_fee_lovelace = BigNum.from_str((cert_fee_ada * 1000000).toString())

const protocolParams: any = {
linearFee: {
minFeeA: "440",
minFeeB: "175381",
},
minUtxo: "34482",
poolDeposit: "500000000",
keyDeposit: "2000000",
maxValSize: 5000,
maxTxSize: 16384,
priceMem: 0.0577,
priceStep: 0.0000721,
// minFeeCoefficient: 44,
// minFeeConstant: 155_381,
coinsPerUtxoByte: "4310"
}

let linearFee = LinearFee.new(
BigNum.from_str(protocolParams.linearFee.minFeeA),
BigNum.from_str(protocolParams.linearFee.minFeeB)
);
let txnBuilderConfigBuilder = TransactionBuilderConfigBuilder.new()
.fee_algo(linearFee)
.coins_per_utxo_byte(BigNum.from_str(protocolParams.coinsPerUtxoByte))
.key_deposit(BigNum.from_str(protocolParams.keyDeposit))
.pool_deposit(BigNum.from_str(protocolParams.poolDeposit))
.max_value_size(protocolParams.maxValSize)
.max_tx_size(protocolParams.maxTxSize)

let txBuilder = TransactionBuilder.new(txnBuilderConfigBuilder.build())

wallet.getUtxos().then((utxos: any) =>{
let txnUnspentOutputs = TransactionUnspentOutputs.new()
utxos.forEach((utxo: any) => {
txnUnspentOutputs.add(TransactionUnspentOutput.from_hex(utxo))
})
txBuilder.add_output(TransactionOutput.new(Address.from_bech32(applicationWallet_receiveAddr), Value.new(cert_fee_lovelace) ))
txBuilder.add_inputs_from(txnUnspentOutputs, CoinSelectionStrategyCIP2.LargestFirst)
txBuilder.add_change_if_needed(Address.from_bech32(address))

const encodedTx = Buffer.from(txBuilder.build_tx().to_bytes()).toString("hex");
wallet.signTx(encodedTx).then((signed: string) =>{
const txVkeyWitnesses = TransactionWitnessSet.from_bytes(
Buffer.from(signed, "hex")
);
const txSigned = Transaction.new(txBuilder.build(), txVkeyWitnesses );
const encodedSignedTx = Buffer.from(txSigned.to_bytes()).toString("hex");
wallet.submitTx(encodedSignedTx).then((txnId: string) => {
console.log(' transaction id - ', txnId)
triggerSubmitCertificate(txnId)
}).catch(handleError)
}).catch(handleError)
}).catch(handleError)
} catch (e) {
handleError(e)
}
}

return (<>
{certified || disableCertify ? null : (<Button
displayStyle="gradient"
onClick={() => triggerGetCertificate()}
buttonLabel="Get Certificate"
showLoader={certifying}
/>)}
{transactionId ? (
<Modal open={openModal} title="Certification Successful" onCloseModal={onCloseModal}>
<span>
View your certification broadcasted on-chain&nbsp;
<a target="_blank" rel="noreferrer" href={`https://preprod.cardanoscan.io/transaction/${transactionId}`}>here</a>!
</span>
</Modal>
): null}
{showError ? <Toast message={showError} /> : null}
</>);
}

export default CreateCertificate;
Loading

0 comments on commit aa9bb93

Please sign in to comment.