diff --git a/src/components/cards/cip95BuildSignSubmitCard.js b/src/components/cards/cip95BuildSignSubmitCard.js new file mode 100644 index 0000000..2f4e556 --- /dev/null +++ b/src/components/cards/cip95BuildSignSubmitCard.js @@ -0,0 +1,103 @@ +import React from 'react' +import { + getAddressFromBech32, + getCslUtxos, + getLargestFirstMultiAsset, + getTransactionFromBytes, + getTransactionOutput, + getTransactionWitnessSetFromBytes, + getTxBuilder, + strToBigNum, + getSignedTransaction, +} from '../../utils/cslTools' +import {bytesToHex} from '../../utils/utils' + +const Cip95BuildSignSubmitCard = (props) => { + const {api, wasm, onWaiting, onError, getters, setters} = props + const {setCertBuilder, setVotingBuilder} = setters + const {certBuilder, votingBuilder, changeAddress, usedAddress, totalRefunds, hexUtxos} = getters + + const buildSignSubmit = () => { + onWaiting(true) + try { + // build Tx + const txBuilder = getTxBuilder(wasm) + // adding certs, votes to the tx + if (certBuilder) { + txBuilder.set_certs_builder(certBuilder) + setCertBuilder(null) + } + if (votingBuilder) { + txBuilder.set_voting_builder(votingBuilder) + setVotingBuilder(null) + } + // gov actions will be here in future + + // Set output and change addresses to those of our wallet + const shelleyOutputAddress = getAddressFromBech32(wasm, usedAddress) + const shelleyChangeAddress = getAddressFromBech32(wasm, changeAddress) + + // Add output of 1 ADA plus total needed for refunds + let outputValue = strToBigNum(wasm, '1000000') + if (totalRefunds.length > 0) { + outputValue = outputValue.checked_add(strToBigNum(wasm, totalRefunds)) + } + + txBuilder.add_output(getTransactionOutput(wasm, shelleyOutputAddress, outputValue)) + // Find the available UTxOs in the wallet and use them as Inputs for the transaction + const wasmUtxos = getCslUtxos(wasm, hexUtxos) + txBuilder.add_inputs_from(wasmUtxos, getLargestFirstMultiAsset(wasm)) + // Set change address, incase too much ADA provided for fee + txBuilder.add_change_if_needed(shelleyChangeAddress) + const wasmUnsignedTransaction = txBuilder.build_tx() + // sign Tx + const unsignedTxHex = bytesToHex(wasmUnsignedTransaction.to_bytes()) + + api + .signTx(unsignedTxHex) + .then((witnessHex) => { + const wasmUnsignedTransaction = getTransactionFromBytes(wasm, unsignedTxHex) + const wasmWitnessSet = getTransactionWitnessSetFromBytes(wasm, witnessHex) + const wasmSignedTransaction = getSignedTransaction(wasm, wasmUnsignedTransaction, wasmWitnessSet) + const signedTxHex = bytesToHex(wasmSignedTransaction.to_bytes()) + + // submit tx + api + .submitTx(signedTxHex) + .then((txId) => { + onWaiting(false) + console.log('The transaction is sent:', txId) + }) + .catch((e) => { + onWaiting(false) + console.log(e) + }) + }) + .catch((e) => { + onWaiting(false) + console.log(e) + }) + + onWaiting(false) + } catch (e) { + console.error(e) + onError() + onWaiting(false) + } + } + + return ( +
+
+ +
+
+ ) +} + +export default Cip95BuildSignSubmitCard diff --git a/src/components/cards/getAllInfoCard.js b/src/components/cards/getAllInfoCard.js index cc40d54..e46e123 100644 --- a/src/components/cards/getAllInfoCard.js +++ b/src/components/cards/getAllInfoCard.js @@ -7,18 +7,22 @@ import { getRegPubStakeKey, getRewardAddress, getUnregPubStakeKey, + getUsedAddress, + getUnusedAddress, getUTxOs, } from '../../utils/helpFunctions' -// we need onWaiting const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { const { setBalance, setAndMapUtxos, setChangeAddress, setRewardAddress, + setUsedAddress, + setUnusedAddress, setDRepIdBech32, setDRepIdHex, + setDRepIdInputValue, setRegPubStakeKey, setUnregPubStakeKey, } = setters @@ -28,7 +32,6 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { .then((adaValue) => { console.log('[dApp][GetAllInfoCard][getBalance]: ', adaValue) setBalance(adaValue) - onWaiting(false) }) .catch((e) => { console.error(e) @@ -40,7 +43,6 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { .then((utxos) => { console.log('[dApp][GetAllInfoCard][getUTxOs]: ', utxos) setAndMapUtxos(utxos) - onWaiting(false) }) .catch((e) => { console.error(e) @@ -52,7 +54,6 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { .then((bech32Addr) => { console.log('[dApp][GetAllInfoCard][getChangeAddress]: ', bech32Addr) setChangeAddress(bech32Addr) - onWaiting(false) }) .catch((e) => { console.error(e) @@ -64,7 +65,28 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { .then((bech32Addr) => { console.log('[dApp][GetAllInfoCard][getRewardAddress]: ', bech32Addr) setRewardAddress(bech32Addr) + }) + .catch((e) => { + console.error(e) + onWaiting(false) + onError() + }) + + getUsedAddress(api, wasm) + .then((bech32Addr) => { + console.log('[dApp][GetAllInfoCard][getUsedAddress]: ', bech32Addr) + setUsedAddress(bech32Addr) + }) + .catch((e) => { + console.error(e) onWaiting(false) + onError() + }) + + getUnusedAddress(api, wasm) + .then((bech32Addr) => { + console.log('[dApp][GetAllInfoCard][getUnusedAddress]: ', bech32Addr) + setUnusedAddress(bech32Addr) }) .catch((e) => { console.error(e) @@ -77,7 +99,7 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { console.log('[dApp][GetAllInfoCard][getPubDRepKey]: ', drepKey) setDRepIdBech32(drepKey.dRepIDBech32) setDRepIdHex(drepKey.dRepIDHex) - onWaiting(false) + setDRepIdInputValue(drepKey.dRepIDBech32) }) .catch((e) => { console.error(e) @@ -89,7 +111,6 @@ const GetAllInfoCard = ({api, wasm, onWaiting, onError, setters}) => { .then((stakeKeyHash) => { console.log('[dApp][GetAllInfoCard][getRegPubStakeKey]: ', stakeKeyHash) setRegPubStakeKey(stakeKeyHash) - onWaiting(false) }) .catch((e) => { console.error(e) diff --git a/src/components/cards/govActions/dRepRegistrationPanel.js b/src/components/cards/govActions/dRepRegistrationPanel.js new file mode 100644 index 0000000..0310722 --- /dev/null +++ b/src/components/cards/govActions/dRepRegistrationPanel.js @@ -0,0 +1,83 @@ +import React, {useState} from 'react' +import GovToolsPanel from '../govToolsPanel' +import InputWithLabel from '../../inputWithLabel' +import {getAnchor, getCertOfNewDRepReg, getDRepRegCert, getDRepRegWithAnchorCert} from '../../../utils/cslTools' +import {bytesToHex} from '../../../utils/utils' + +const DRepRegistrationPanel = (props) => { + const {wasm, onWaiting, onError, getters, setters, handleInputCreds} = props + + const {handleAddingCertInTx, setDRepIdInputValue} = setters + const {dRepIdInputValue, getCertBuilder} = getters + + const [depositAmount, setDepositAmount] = useState('2000000') + const [metadataURL, setMetadataURL] = useState('') + const [metadataHash, setMetadataHash] = useState('') + + const buildDRepRegistrationCert = () => { + onWaiting(true) + const certBuilder = getCertBuilder(wasm) + try { + const dRepCred = handleInputCreds(dRepIdInputValue) + let dRepRegCert = null + if (metadataURL.length > 0) { + const dataHash = + metadataHash.length > 0 + ? metadataHash + : bytesToHex(new TextEncoder().encode('{"testField": "_test__message_"}')) + const anchor = getAnchor(wasm, metadataURL, dataHash) + dRepRegCert = getDRepRegWithAnchorCert(wasm, dRepCred, depositAmount, anchor) + } else { + dRepRegCert = getDRepRegCert(wasm, dRepCred, depositAmount) + } + certBuilder.add(getCertOfNewDRepReg(wasm, dRepRegCert)) + handleAddingCertInTx(certBuilder) + onWaiting(false) + } catch (error) { + console.error(error) + onWaiting(false) + onError() + } + } + + const panelProps = { + buttonName: 'Build Cert', + certLabel: 'dRepRegistration', + clickFunction: buildDRepRegistrationCert, + } + + return ( + + { + setDRepIdInputValue(event.target.value) + }} + /> + { + setDepositAmount(event.target.value) + }} + /> + { + setMetadataURL(event.target.value) + }} + /> + { + setMetadataHash(event.target.value) + }} + /> + + ) +} + +export default DRepRegistrationPanel diff --git a/src/components/cards/govActions/dRepRetirementPanel.js b/src/components/cards/govActions/dRepRetirementPanel.js new file mode 100644 index 0000000..5e0332c --- /dev/null +++ b/src/components/cards/govActions/dRepRetirementPanel.js @@ -0,0 +1,55 @@ +import React, {useState} from 'react' +import GovToolsPanel from '../govToolsPanel' +import InputWithLabel from '../../inputWithLabel' +import {getCertOfNewDRepRetirement, getDRepRetirementCert} from '../../../utils/cslTools' + +const DRepRetirementPanel = (props) => { + const {wasm, onWaiting, onError, getters, setters, handleInputCreds} = props + + const {handleAddingCertInTx, setDRepIdInputValue} = setters + const {dRepIdInputValue, getCertBuilder} = getters + const [depositRefundAmount, setDepositRefundAmount] = useState('2000000') + + const buildDRepRetirementCert = () => { + onWaiting(true) + const certBuilder = getCertBuilder(wasm) + try { + const dRepCred = handleInputCreds(dRepIdInputValue) + const dRepRetirementCert = getDRepRetirementCert(wasm, dRepCred, depositRefundAmount) + certBuilder.add(getCertOfNewDRepRetirement(wasm, dRepRetirementCert)) + handleAddingCertInTx(certBuilder) + onWaiting(false) + } catch (error) { + console.error(error) + onWaiting(false) + onError() + } + } + + const panelProps = { + buttonName: 'Build Cert', + certLabel: 'dRepRetirement', + clickFunction: buildDRepRetirementCert, + } + + return ( + + { + setDRepIdInputValue(event.target.value) + }} + /> + { + setDepositRefundAmount(event.target.value) + }} + /> + + ) +} + +export default DRepRetirementPanel diff --git a/src/components/cards/govActions/dRepUpdatePanel.js b/src/components/cards/govActions/dRepUpdatePanel.js new file mode 100644 index 0000000..d120171 --- /dev/null +++ b/src/components/cards/govActions/dRepUpdatePanel.js @@ -0,0 +1,77 @@ +import React, {useState} from 'react' +import GovToolsPanel from '../govToolsPanel' +import InputWithLabel from '../../inputWithLabel' +import { + getAnchor, + getCertOfNewDRepUpdate, + getDRepUpdateCert, + getDRepUpdateWithAnchorCert, +} from '../../../utils/cslTools' +import {getRandomHex} from '../../../utils/helpFunctions' + +const DRepUpdatePanel = (props) => { + const {wasm, onWaiting, onError, getters, setters, handleInputCreds} = props + + const {handleAddingCertInTx, setDRepIdInputValue} = setters + const {dRepIdInputValue, getCertBuilder} = getters + + const [metadataURL, setMetadataURL] = useState('') + const [metadataHash, setMetadataHash] = useState('') + + const buildDRepUpdateCert = () => { + onWaiting(true) + const certBuilder = getCertBuilder(wasm) + try { + const dRepCred = handleInputCreds(dRepIdInputValue) + let dRepUpdateCert = null + if (metadataURL.length > 0) { + const dataHash = metadataHash.length > 0 ? metadataHash : getRandomHex(32) + const anchor = getAnchor(wasm, metadataURL, dataHash) + dRepUpdateCert = getDRepUpdateWithAnchorCert(wasm, dRepCred, anchor) + } else { + dRepUpdateCert = getDRepUpdateCert(wasm, dRepCred) + } + certBuilder.add(getCertOfNewDRepUpdate(wasm, dRepUpdateCert)) + handleAddingCertInTx(certBuilder) + onWaiting(false) + } catch (error) { + console.error(error) + onWaiting(false) + onError() + } + } + + const panelProps = { + buttonName: 'Build Cert', + certLabel: 'dRepUpdate', + clickFunction: buildDRepUpdateCert, + } + + return ( + + { + setDRepIdInputValue(event.target.value) + }} + /> + { + setMetadataURL(event.target.value) + }} + /> + { + setMetadataHash(event.target.value) + }} + /> + + ) +} + +export default DRepUpdatePanel diff --git a/src/components/cards/govActions/voteDelegationPanel.js b/src/components/cards/govActions/voteDelegationPanel.js new file mode 100644 index 0000000..597ff77 --- /dev/null +++ b/src/components/cards/govActions/voteDelegationPanel.js @@ -0,0 +1,91 @@ +import React, {useState} from 'react' +import InputWithLabel from '../../inputWithLabel' +import { + getCertOfNewVoteDelegation, + getDRepAbstain, + getDRepNewKeyHash, + getDRepNoConfidence, + getVoteDelegCert, +} from '../../../utils/cslTools' +import GovToolsPanel from '../govToolsPanel' + +const VoteDelegationPanel = (props) => { + const {wasm, onWaiting, onError, getters, setters, handleInputCreds} = props + const {dRepIdBech32, dRepIdInputValue, regPubStakeKey, unregPubStakeKey, getCertBuilder} = getters + const {handleAddingCertInTx, setDRepIdInputValue} = setters + + const [stake, setStake] = useState('') + + const suitableStake = regPubStakeKey.length > 0 ? regPubStakeKey : unregPubStakeKey + + const buildVoteDelegationCert = () => { + onWaiting(true) + + // build vote cert + const certBuilder = getCertBuilder(wasm) + try { + let targetDRep + if (dRepIdInputValue.toUpperCase() === 'ABSTAIN') { + targetDRep = getDRepAbstain(wasm) + } else if (dRepIdInputValue.toUpperCase() === 'NO CONFIDENCE') { + targetDRep = getDRepNoConfidence(wasm) + } else { + let tempTarget = dRepIdInputValue + if (dRepIdInputValue.length === 0) { + setDRepIdInputValue(dRepIdBech32) + tempTarget = dRepIdBech32 + } + const dRepKeyCred = handleInputCreds(tempTarget) + targetDRep = getDRepNewKeyHash(wasm, dRepKeyCred.to_keyhash()) + } + + let pubStake = stake + if (stake.length === 0) { + setStake(suitableStake) + pubStake = suitableStake + } + const stakeCred = handleInputCreds(pubStake) + if (stakeCred == null) { + return null + } + // Create cert object + const voteDelegationCert = getVoteDelegCert(wasm, stakeCred, targetDRep) + // add cert to certBuilder + certBuilder.add(getCertOfNewVoteDelegation(wasm, voteDelegationCert)) + // adding the cert to the certStorage + handleAddingCertInTx(certBuilder) + onWaiting(false) + } catch (error) { + console.error(error) + onWaiting(false) + onError() + } + } + + const panelProps = { + buttonName: 'Build Cert', + certLabel: 'voteDelegation', + clickFunction: buildVoteDelegationCert, + } + + return ( + + { + setDRepIdInputValue(event.target.value) + }} + /> + { + setStake(event.target.value) + }} + /> + + ) +} + +export default VoteDelegationPanel diff --git a/src/components/cards/govActions/votePanel.js b/src/components/cards/govActions/votePanel.js new file mode 100644 index 0000000..15dd096 --- /dev/null +++ b/src/components/cards/govActions/votePanel.js @@ -0,0 +1,117 @@ +import React, {useState} from 'react' +import InputWithLabel from '../../inputWithLabel' +import GovToolsPanel from '../govToolsPanel' +import { + getVoter, + getGovActionId, + getAnchor, + getVotingProcedure, + getVotingProcedureWithAnchor, +} from '../../../utils/cslTools' +import SelectWithLabel from '../../selectWithLabel' +import {getRandomHex} from '../../../utils/helpFunctions' + +const VotePanel = (props) => { + const {wasm, onWaiting, onError, getters, setters, handleInputCreds} = props + const {dRepIdInputValue, getVotingBuilder} = getters + const {handleAddingVotesInTx, setDRepIdInputValue} = setters + + const availableVotingChoices = [ + {label: 'NO', value: 0}, + {label: 'YES', value: 1}, + {label: 'ABSTAIN', value: 2}, + ] + + const [voteGovActionTxHashInHex, setVoteGovActionTxHashInHex] = useState('') + const [voteGovActionIndex, setVoteGovActionIndex] = useState('') + const [votingChoice, setVotingChoice] = useState(0) + const [metadataURL, setMetadataURL] = useState('') + const [metadataHash, setMetadataHash] = useState('') + + const handleVoteChoiceChange = (event) => { + setVotingChoice(event.target.value) + } + + const buildVote = () => { + onWaiting(true) + const votingBuilder = getVotingBuilder(wasm) + try { + // Getting voter + const dRepCreds = handleInputCreds(dRepIdInputValue) + const voter = getVoter(wasm, dRepCreds) + // What is being voted on + const govActionId = getGovActionId(wasm, voteGovActionTxHashInHex, voteGovActionIndex) + // Voting choice + let votingProcedure + + if (metadataURL.length > 0) { + const dataHash = metadataHash.length > 0 ? metadataHash : getRandomHex(32) + const anchor = getAnchor(wasm, metadataURL, dataHash) + votingProcedure = getVotingProcedureWithAnchor(wasm, votingChoice, anchor) + } else { + votingProcedure = getVotingProcedure(wasm, votingChoice) + } + // Add vote to vote builder + votingBuilder.add(voter, govActionId, votingProcedure) + handleAddingVotesInTx(votingBuilder) + onWaiting(false) + } catch (error) { + console.error(error) + onWaiting(false) + onError() + } + } + + const panelProps = { + buttonName: 'Build Vote', + certLabel: 'vote', + clickFunction: buildVote, + } + + return ( + + { + setDRepIdInputValue(event.target.value) + }} + /> + { + setVoteGovActionTxHashInHex(event.target.value) + }} + /> + { + setVoteGovActionIndex(event.target.value) + }} + /> + + { + setMetadataURL(event.target.value) + }} + /> + { + setMetadataHash(event.target.value) + }} + /> + + ) +} + +export default VotePanel diff --git a/src/components/cards/govToolsPanel.js b/src/components/cards/govToolsPanel.js index 3b2c0d4..8c14742 100644 --- a/src/components/cards/govToolsPanel.js +++ b/src/components/cards/govToolsPanel.js @@ -2,9 +2,9 @@ import React from 'react' import {ModalWindowContent} from '../ui-constants' const GovToolsPanel = (props) => { - const {certLabel, clickFunction, children} = props + const {buttonName, certLabel, clickFunction, children} = props const handleAction = () => { - console.log(`[dApp][GovToolsPanel][${certLabel}] Building the certificate is called`) + console.log(`[dApp][GovToolsPanel][${certLabel}] Building is called`) // action here clickFunction() } @@ -18,7 +18,7 @@ const GovToolsPanel = (props) => { className="w-full py-1 rounded-md text-xl text-white font-semibold bg-orange-700 hover:bg-orange-800 active:bg-orange-500" onClick={handleAction} > - Build Cert + {buttonName} diff --git a/src/components/cards/voteDelegationPanel.js b/src/components/cards/voteDelegationPanel.js deleted file mode 100644 index 24f487a..0000000 --- a/src/components/cards/voteDelegationPanel.js +++ /dev/null @@ -1,112 +0,0 @@ -import React, {useState} from 'react' -import InputWithLabel from '../inputWithLabel' -import { - getCertOfNewVoteDelegation, - getCslCredentialFromBech32, - getCslCredentialFromHex, - getDRepAbstain, - getDRepNewKeyHash, - getDRepNoConfidence, - getVoteDelegCert, -} from '../../utils/cslTools' -import GovToolsPanel from './govToolsPanel' - -const VoteDelegationPanel = ({api, wasm, onWaiting, onError, getters, setters}) => { - const [currentTarget, setTarget] = useState('') - const [currentStake, setStake] = useState('') - const {currentDRepIdBech32, currentRegPubStakeKey, currentUnregPubStakeKey, getCertBuilder} = getters - const {handleAddingCertInTx} = setters - - const suitableStake = currentRegPubStakeKey.length > 0 ? currentRegPubStakeKey : currentUnregPubStakeKey - - const handleInput = (input) => { - try { - return getCslCredentialFromHex(wasm, input) - } catch (err1) { - try { - return getCslCredentialFromBech32(wasm, input) - } catch (err2) { - onWaiting(false) - console.error( - `Error in parsing credential, not Hex or Bech32: ${JSON.stringify(err1)}, ${JSON.stringify(err2)}`, - ) - onError() - return null - } - } - } - - const buildVoteDelegationCert = () => { - onWaiting(true) - - // build vote cert - const certBuilder = getCertBuilder(wasm) - try { - let targetDRep - if (currentTarget.toUpperCase() === 'ABSTAIN') { - targetDRep = getDRepAbstain(wasm) - } else if (currentTarget.toUpperCase() === 'NO CONFIDENCE') { - targetDRep = getDRepNoConfidence(wasm) - } else { - let target = currentTarget - if (currentTarget.length === 0) { - setTarget(currentDRepIdBech32) - target = currentDRepIdBech32 - } else { - setTarget(currentTarget) - } - const dRepKeyCred = handleInput(target) - targetDRep = getDRepNewKeyHash(wasm, dRepKeyCred.to_keyhash()) - } - - let pubStake = currentStake - if (currentStake.length === 0) { - setStake(suitableStake) - pubStake = suitableStake - } else { - setStake(currentStake) - } - const stakeCred = handleInput(pubStake) - if (stakeCred == null) { - return null - } - // Create cert object - const voteDelegationCert = getVoteDelegCert(wasm, stakeCred, targetDRep) - // add cert to certBuilder - certBuilder.add(getCertOfNewVoteDelegation(wasm, voteDelegationCert)) - // adding the cert to the certStorage - handleAddingCertInTx(certBuilder) - onWaiting(false) - } catch (error) { - console.error(error) - onWaiting(false) - onError() - } - } - - const panelProps = { - certLabel: 'voteDelegation', - clickFunction: buildVoteDelegationCert, - } - - return ( - - { - setTarget(event.target.value) - }} - /> - 0 ? currentRegPubStakeKey : currentUnregPubStakeKey} - onChangeFunction={(event) => { - setStake(event.target.value) - }} - /> - - ) -} - -export default VoteDelegationPanel diff --git a/src/components/inputWithLabel.js b/src/components/inputWithLabel.js index 2b6258b..cf4d22e 100644 --- a/src/components/inputWithLabel.js +++ b/src/components/inputWithLabel.js @@ -1,6 +1,5 @@ import React from 'react' -import {CommonStyles} from './ui-constants' -import {ModalWindowContent} from './ui-constants' +import {CommonStyles, ModalWindowContent} from './ui-constants' const InputWithLabel = (props) => { const {inputName, inputValue, onChangeFunction} = props diff --git a/src/components/selectWithLabel.js b/src/components/selectWithLabel.js index e24ec41..42d45be 100644 --- a/src/components/selectWithLabel.js +++ b/src/components/selectWithLabel.js @@ -1,25 +1,23 @@ import React from 'react' +import {ModalWindowContent} from './ui-constants' const SelectWithLabel = (props) => { const {selectName, selectArray, onChangeFunction} = props const selectID = selectName.split(' ').join('') return ( -
-