Merge pull request #61 from PhillipLangMartinez/release/26-08-22

Release/26 08 22 - bug fixes
This commit is contained in:
AlphaX-Projects 2022-08-27 16:27:36 +02:00 committed by GitHub
commit ce6ee040f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 744 additions and 233 deletions

View File

@ -30,6 +30,7 @@ html {
--nav-icon-color: #080808; --nav-icon-color: #080808;
--nav-border-color: #eeeeee; --nav-border-color: #eeeeee;
--nav-border-selected-color: #03a9f4; --nav-border-selected-color: #03a9f4;
--error: #d50000;
--background: url("/img/qortal_background_light_.jpg"); --background: url("/img/qortal_background_light_.jpg");
} }
@ -65,5 +66,6 @@ html[theme="dark"] {
--nav-icon-color: #008fd5; --nav-icon-color: #008fd5;
--nav-border-color: #0b305e; --nav-border-color: #0b305e;
--nav-border-selected-color: #76c8f5; --nav-border-selected-color: #76c8f5;
--error: #d50000;
--background: url("/img/qortal_background_dark_.jpg"); --background: url("/img/qortal_background_dark_.jpg");
} }

View File

@ -174,7 +174,7 @@
"mchange33":"Introduction", "mchange33":"Introduction",
"mchange34":"In Qortal, in order to become a minter and begin earning QORT rewards with your increase in Minter Level, you must first become sponsored. A sponsor in Qortal is any other minter of level 5 or higher, or a Qortal Founder. You will obtain a sponsorship key from the sponsor, and use that key to get to level 1. Once you have reached level 1, you will be able to create your own minting key and start earning rewards for helping secure the Qortal Blockchain.", "mchange34":"In Qortal, in order to become a minter and begin earning QORT rewards with your increase in Minter Level, you must first become sponsored. A sponsor in Qortal is any other minter of level 5 or higher, or a Qortal Founder. You will obtain a sponsorship key from the sponsor, and use that key to get to level 1. Once you have reached level 1, you will be able to create your own minting key and start earning rewards for helping secure the Qortal Blockchain.",
"mchange35":"Sponsorship", "mchange35":"Sponsorship",
"mchange36":"Your sponsor will issue you a Sponsorship Key which you will use to add to your node, and begin minting (for no rewards until reaching level 1.) Once you reach level 1, you create/assign your own Minting Key and begin earning rewards. You have XXXX blocks remaining in your sponsorship period.", "mchange36":"Your sponsor will issue you a Sponsorship Key which you will use to add to your node, and begin minting (for no rewards until reaching level 1.) Once you reach level 1, you create/assign your own Minting Key and begin earning rewards.",
"mchange37":"Simply reach out to a minter in Qortal who is high enough level to issue a sponsorship key, obtain that key, then come back here and input the key to begin your minting journey !", "mchange37":"Simply reach out to a minter in Qortal who is high enough level to issue a sponsorship key, obtain that key, then come back here and input the key to begin your minting journey !",
"mchange38":"in" "mchange38":"in"
}, },

View File

@ -2,27 +2,193 @@ import { LitElement, html, css } from 'lit';
import { connect } from 'pwa-helpers'; import { connect } from 'pwa-helpers';
import { store } from '../store.js'; import { store } from '../store.js';
import { translate, get } from 'lit-translate'; import { translate, get } from 'lit-translate';
import {asyncReplace} from 'lit/directives/async-replace.js';
import '../functional-components/my-button.js'; import '../functional-components/my-button.js';
import { routes } from '../plugins/routes.js'; import { routes } from '../plugins/routes.js';
import "@material/mwc-button"
import '@material/mwc-dialog'
async function* countDown(count, callback) {
while (count > 0) {
yield count--;
await new Promise((r) => setTimeout(r, 1000));
if(count === 0){
callback()
}
}
}
class StartMinting extends connect(store)(LitElement) { class StartMinting extends connect(store)(LitElement) {
static get properties() { static get properties() {
return { return {
addressInfo: { type: Object }, addressInfo: { type: Object },
mintingAccountData: { type: Array }, mintingAccountData: { type: Array },
errorMsg: { type: String }, errorMsg: { type: String },
openDialogRewardShare : {type: Boolean},
status: {type: Number},
timer: {type: Number},
privateRewardShareKey: {type: String}
}; };
} }
static get styles() { static get styles() {
return [ return [
css` css`
.dialogCustom {
position: fixed;
z-index: 10000;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
top: 0px;
bottom: 0px;
left: 0px;
width: 100vw;
}
.dialogCustomInner {
width: 300px;
min-height: 400px;
background-color: var(--white);
box-shadow: var(--mdc-dialog-box-shadow, 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12));
padding: 20px 24px;
border-radius: 4px;
}
.dialogCustomInner ul {
padding-left: 0px
}
.dialogCustomInner li {
margin-bottom: 10px;
}
.start-minting-wrapper { .start-minting-wrapper {
position: absolute; position: absolute;
left: 50%; left: 50%;
transform: translateX(calc(-50% - 10px)); transform: translateX(calc(-50% - 10px));
z-index: 10;
} }
.dialog-header h1 {
font-size: 18px;
}
.row {
display: flex;
width: 100%;
align-items: center;
}
.modalFooter {
width: 100%;
display: flex;
justify-content: flex-end;
}
.hide {
visibility: hidden
}
.inactiveText {
opacity: .60
}
.column {
display: flex;
flex-direction: column;
width: 100%;
}
.smallLoading,
.smallLoading:after {
border-radius: 50%;
width: 2px;
height: 2px;
}
.smallLoading {
border-width: 0.6em;
border-style: solid;
border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2)
rgba(3, 169, 244, 0.2) rgb(3, 169, 244);
font-size: 10px;
position: relative;
text-indent: -9999em;
transform: translateZ(0px);
animation: 1.1s linear 0s infinite normal none running loadingAnimation;
}
@-webkit-keyframes loadingAnimation {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loadingAnimation {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.word-break {
word-break:break-all;
}
.dialog-container {
width: 300px;
min-height: 300px;
max-height: 75vh;
padding: 5px;
display: flex;
align-items: flex-start;
flex-direction: column;
}
.between {
justify-content: space-between;
}
.no-width {
width: auto
}
.between p {
margin: 0;
padding: 0;
}
.marginLoader {
margin-left: 10px;
}
.marginRight {
margin-right: 10px;
}
.warning{
display: flex;
flex-grow: 1
}
.message-error {
color: var(--error);
}
`, `,
]; ];
} }
@ -32,6 +198,9 @@ class StartMinting extends connect(store)(LitElement) {
this.addressInfo = {}; this.addressInfo = {};
this.mintingAccountData = []; this.mintingAccountData = [];
this.errorMsg = ''; this.errorMsg = '';
this.openDialogRewardShare = false;
this.status = 0;
this.privateRewardShareKey = "";
} }
render() { render() {
@ -40,6 +209,10 @@ class StartMinting extends connect(store)(LitElement) {
firstUpdated() { firstUpdated() {
this.getMintingAcccounts(); this.getMintingAcccounts();
this.shadowRoot.querySelector('mdc-dialog--open').setAttribute('style', 'width: 100vw')
} }
async getMintingAcccounts() { async getMintingAcccounts() {
@ -60,6 +233,118 @@ class StartMinting extends connect(store)(LitElement) {
} }
} }
async changeStatus(value){
const myNode =
store.getState().app.nodeConfig.knownNodes[
store.getState().app.nodeConfig.node
];
const nodeUrl =
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
this.status = value
const publicAddress =
window.parent.reduxStore.getState().app?.selectedAddress
?.base58PublicKey;
// Check to see if a sponsorship key on a newly-level 1 minter exists. If it does, remove it.
const findMintingAccountFromOtherUser = this.mintingAccountData.find(
(ma) => !ma.publicKey.includes(publicAddress)
);
const removeMintingAccount = async (publicKey) => {
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
return await fetch(url, {
method: 'DELETE',
body: publicKey,
});
};
const addMintingAccount = async (sponsorshipKeyValue) => {
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
return await fetch(url, {
method: 'POST',
body: sponsorshipKeyValue,
});
};
try {
if (
findMintingAccountFromOtherUser &&
findMintingAccountFromOtherUser?.publicKey[0]
) {
await removeMintingAccount(
findMintingAccountFromOtherUser?.publicKey[0]
);
}
} catch (error) {
this.errorMsg = 'Failed to remove key';
return;
}
try {
await addMintingAccount(this.privateRewardShareKey);
routes.showSnackBar({
data: translate('becomeMinterPage.bchange19'),
});
this.status = 5;
this.getMintingAcccounts();
} catch (error) {
this.errorMsg = 'Failed to add minting key';
return;
}
}
async confirmRelationship(){
const myNode =
store.getState().app.nodeConfig.knownNodes[
store.getState().app.nodeConfig.node
];
const nodeUrl =
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
let interval = null
let stop = false
this.status = 2
const getAnswer = async () => {
const rewardShares = async (minterAddr) => {
const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}`;
const res = await fetch(url);
const data = await res.json();
return data;
};
if (!stop) {
stop= true;
try {
const address =
window.parent.reduxStore.getState().app?.selectedAddress?.address;
const myRewardShareArray = await rewardShares(address);
if(myRewardShareArray.length > 0){
clearInterval(interval)
this.status = 3
this.timer = countDown(180, ()=> this.changeStatus(4));
}
} catch (error) {
}
stop = false
}
};
interval = setInterval(getAnswer, 5000);
}
renderStartMintingButton() { renderStartMintingButton() {
const myNode = const myNode =
store.getState().app.nodeConfig.knownNodes[ store.getState().app.nodeConfig.knownNodes[
@ -70,12 +355,7 @@ class StartMinting extends connect(store)(LitElement) {
const mintingAccountData = this.mintingAccountData; const mintingAccountData = this.mintingAccountData;
const addressInfo = this.addressInfo; const addressInfo = this.addressInfo;
const rewardShares = async (minterAddr) => {
const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}`;
const res = await fetch(url);
const data = await res.json();
return data;
};
const address = const address =
window.parent.reduxStore.getState().app?.selectedAddress?.address; window.parent.reduxStore.getState().app?.selectedAddress?.address;
const nonce = const nonce =
@ -89,17 +369,10 @@ class StartMinting extends connect(store)(LitElement) {
); );
const isMinterButKeyMintingKeyNotAssigned = const isMinterButKeyMintingKeyNotAssigned =
addressInfo?.error !== 124 && addressInfo?.error !== 124 &&
addressInfo?.level === 1 && addressInfo?.level >= 1 &&
!findMintingAccount; !findMintingAccount;
const removeMintingAccount = async (publicKey) => {
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
return await fetch(url, {
method: 'DELETE',
body: publicKey,
});
};
const makeTransactionRequest = async (lastRef) => { const makeTransactionRequest = async (lastRef) => {
let mylastRef = lastRef; let mylastRef = lastRef;
@ -128,35 +401,33 @@ class StartMinting extends connect(store)(LitElement) {
}; };
const getTxnRequestResponse = (txnResponse) => { const getTxnRequestResponse = (txnResponse) => {
let err6string = get('rewardsharepage.rchange21');
if(txnResponse?.extraData?.rewardSharePrivateKey && (txnResponse?.data?.message.includes('multiple') || txnResponse?.data?.message.includes('SELF_SHARE_EXISTS'))){
return err6string
}
if (txnResponse.success === false && txnResponse.message) { if (txnResponse.success === false && txnResponse.message) {
throw new Error(txnResponse); throw(txnResponse);
} else if ( } else if (
txnResponse.success === true && txnResponse.success === true &&
!txnResponse.data.error !txnResponse.data.error
) { ) {
let err6string = get('rewardsharepage.rchange21');
return err6string; return err6string;
} else { } else {
throw new Error(txnResponse); throw(txnResponse);
} }
}; };
const createSponsorshipKey = async () => { const createSponsorshipKey = async () => {
this.status= 1
let lastRef = await getLastRef(); let lastRef = await getLastRef();
let myTransaction = await makeTransactionRequest(lastRef); let myTransaction = await makeTransactionRequest(lastRef);
getTxnRequestResponse(myTransaction); getTxnRequestResponse(myTransaction);
return myTransaction.data; return myTransaction?.extraData?.rewardSharePrivateKey
};
const addMintingAccount = async (sponsorshipKeyValue) => {
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
return await fetch(url, {
method: 'POST',
body: sponsorshipKeyValue,
});
}; };
const getLastRef = async () => { const getLastRef = async () => {
const url = `${nodeUrl}/addresses/lastreference/${address}`; const url = `${nodeUrl}/addresses/lastreference/${address}`;
@ -167,64 +438,23 @@ class StartMinting extends connect(store)(LitElement) {
return data; return data;
}; };
const startMinting = async () => { const startMinting = async () => {
this.openDialogRewardShare = true
this.errorMsg = ''; this.errorMsg = '';
let rewardSharesList;
try { try {
rewardSharesList = await rewardShares(address);
this.privateRewardShareKey = await createSponsorshipKey();
this.confirmRelationship(publicAddress)
} catch (error) { } catch (error) {
this.errorMsg = 'Cannot fetch reward shares'; console.log({error})
return; this.errorMsg = error?.data?.message || 'Cannot create sponsorship key';
}
// check to see if self-share exists
const findRewardShareData = rewardSharesList.find(
(rs) =>
rs?.mintingAccount === address && rs?.recipient === address
);
let sponsorshipKeyValue = null;
try {
if (!findRewardShareData) {
// if no self-share exits, create one.
sponsorshipKeyValue = await createSponsorshipKey();
} else {
sponsorshipKeyValue =
findRewardShareData.rewardSharePublicKey;
}
} catch (error) {
this.errorMsg = 'Cannot create sponsorship key';
return; return;
} }
// Check to see if a sponsorship key on a newly-level 1 minter exists. If it does, remove it.
const findMintingAccountFromOtherUser = mintingAccountData.find(
(ma) => !ma.publicKey.includes(publicAddress)
);
try {
if (
findMintingAccountFromOtherUser &&
findMintingAccountFromOtherUser?.publicKey[0]
) {
await removeMintingAccount(
findMintingAccountFromOtherUser?.publicKey[0]
);
}
} catch (error) {
this.errorMsg = 'Failed to remove key';
return;
}
try {
await addMintingAccount(sponsorshipKeyValue);
routes.showSnackBar({
data: translate('becomeMinterPage.bchange19'),
});
this.getMintingAcccounts();
} catch (error) {
this.errorMsg = 'Failed to add minting key';
return;
}
}; };
return html` return html`
@ -246,6 +476,93 @@ class StartMinting extends connect(store)(LitElement) {
}} }}
></my-button> ></my-button>
</div> </div>
<!-- Dialog for tracking the progress of starting minting -->
${this.openDialogRewardShare ? html`
<div class="dialogCustom">
<div class="dialogCustomInner">
<div class="dialog-header" >
<div class="row">
<h1>In progress </h1> <div class=${`smallLoading marginLoader ${this.status > 3 && 'hide'}`}></div>
</div>
<hr />
</div>
<div class="dialog-container">
<ul>
<li class="row between">1. Creating relationship <div class=${`smallLoading marginLoader ${this.status !== 1 && 'hide'}`}></div></li>
<li class=${`row between ${this.status < 2 && 'inactiveText' }`}>
<p>
2. Awaiting confirmation on blockchain
</p>
<div class=${`smallLoading marginLoader ${this.status !== 2 && 'hide'}`}></div>
</li>
<li class=${`row between ${this.status < 3 && 'inactiveText' }`}>
<p>
3. Finishing up relationship
</p>
<div class="row no-width">
<div class=${`smallLoading marginLoader marginRight ${this.status !== 3 && 'hide'}`} ></div> ${asyncReplace(this.timer)}
</div>
</li>
<li class=${`row between ${this.status < 4 && 'inactiveText' }`}>
<p>
4. Adding minting key to node
</p>
<div class=${`smallLoading marginLoader ${this.status !== 4 && 'hide'}`}></div>
</li>
<li class=${`row between ${this.status < 5 && 'inactiveText' }`}>
<p>
5. Complete
</p>
</li>
</ul>
<div class="warning column">
<p>
Warning: do not close the Qortal UI until completion!
</p>
<p class="message-error">${this.errorMsg}</p>
</div>
</div>
<div class="modalFooter">
<mwc-button
slot="primaryAction"
@click=${()=>{
this.openDialogRewardShare = false
this.errorMsg = ''
}}
class="red"
>
${translate("general.close")}
</mwc-button>
</div>
</div>
<!-- </mwc-dialog> -->
</div>
` : ""}
` `
: ''} : ''}
`; `;

View File

@ -141,15 +141,21 @@ export const routes = {
req.data.params req.data.params
); );
if (!req.disableModal) { if (!req.disableModal && !req.data.disableModal) {
await requestTransactionDialog.requestTransaction(tx); await requestTransactionDialog.requestTransaction(tx);
} }
const res = await processTransaction(tx.signedBytes); const res = await processTransaction(tx.signedBytes);
let extraData = {}
if(req.data.type === 38 && tx && tx._rewardShareKeyPair && tx._rewardShareKeyPair.secretKey){
extraData.rewardSharePrivateKey = Base58.encode(tx._rewardShareKeyPair.secretKey)
}
response = { response = {
success: true, success: true,
data: res, data: res,
extraData
}; };
} catch (e) { } catch (e) {
console.error(e); console.error(e);

View File

@ -147,9 +147,9 @@ class BecomeMinter extends LitElement {
} }
render() { render() {
console.log({ mintingAccountData: this.mintingAccountData });
const findMintingAccount = this.mintingAccountData?.find( const findMintingAccount = this.mintingAccountData?.find(
(ma) => !!ma.publicKey (ma) => ma.publicKey === window.parent.reduxStore.getState().app?.selectedAddress
?.base58PublicKey
); );
const isAlreadySponsored = const isAlreadySponsored =

View File

@ -37,8 +37,8 @@ export const pageStyles = css`
.message { .message-error {
color: var(--gray); color: var(--error);
} }
@ -62,6 +62,15 @@ export const pageStyles = css`
.row { .row {
display: flex; display: flex;
width: 100%; width: 100%;
align-items: center;
}
.hide {
visibility: hidden
}
.inactiveText {
opacity: .60
} }
.column { .column {
display: flex; display: flex;
@ -156,6 +165,30 @@ export const pageStyles = css`
z-index: 9; z-index: 9;
position: fixed; position: fixed;
} }
.marginLoader {
margin-left: 10px;
}
.marginRight {
margin-right: 10px;
}
.smallLoading,
.smallLoading:after {
border-radius: 50%;
width: 2px;
height: 2px;
}
.smallLoading {
border-width: 0.6em;
border-style: solid;
border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2)
rgba(3, 169, 244, 0.2) rgb(3, 169, 244);
font-size: 10px;
position: relative;
text-indent: -9999em;
transform: translateZ(0px);
animation: 1.1s linear 0s infinite normal none running loadingAnimation;
}
.loading, .loading,
.loading:after { .loading:after {
@ -201,9 +234,9 @@ export const pageStyles = css`
.tableGrid { .tableGrid {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax( grid-template-columns: minmax(0, 3fr) minmax(0, 1fr) minmax(
0, 0,
1fr 2fr
) minmax(0, 1fr); ) minmax(0, 1fr);
align-items: center; align-items: center;
gap: 5px; gap: 5px;
@ -214,6 +247,16 @@ export const pageStyles = css`
} }
.header {
align-self: flex-start;
}
.header p {
word-break: break-word ;
}
.grid-item { .grid-item {
text-align: center; text-align: center;
@ -267,7 +310,9 @@ export const pageStyles = css`
} }
.word-break {
word-break:break-all;
}
.dialog-container { .dialog-container {
width: 300px; width: 300px;
min-height: 300px; min-height: 300px;
@ -331,6 +376,7 @@ export const pageStyles = css`
text-decoration: none; text-decoration: none;
margin: 0px; margin: 0px;
margin-right: 10px; margin-right: 10px;
word-break: break-word;
} }
.grid-item { .grid-item {
@ -356,4 +402,37 @@ export const pageStyles = css`
grid-column: 1 / -1; grid-column: 1 / -1;
} }
} }
.between {
justify-content: space-between;
}
.no-width {
width: auto
}
.between p {
margin: 0;
padding: 0;
}
#showDialogRewardShareCreationStatus .dialog-container {
width: 300px;
min-height: 250px;
max-height: 75vh;
padding: 5px;
display: flex;
align-items: flex-start;
flex-direction: column;
}
.warning{
display: flex;
flex-grow: 1
}
#showDialogRewardShareCreationStatus li {
margin-bottom: 15px;
}
` `

View File

@ -13,14 +13,27 @@ import "@polymer/paper-spinner/paper-spinner-lite.js"
import "@material/mwc-button" import "@material/mwc-button"
import "@material/mwc-textfield" import "@material/mwc-textfield"
import "@vaadin/button" import "@vaadin/button"
import "@material/mwc-button"
import "@polymer/paper-spinner/paper-spinner-lite.js" import "@polymer/paper-spinner/paper-spinner-lite.js"
import '@material/mwc-dialog' import '@material/mwc-dialog'
import {asyncReplace} from 'lit/directives/async-replace.js';
import { pageStyles } from "./sponsorship-list-css.src.js" import { pageStyles } from "./sponsorship-list-css.src.js"
const parentEpml = new Epml({ type: "WINDOW", source: window.parent }) const parentEpml = new Epml({ type: "WINDOW", source: window.parent })
async function* countDown(count, callback) {
while (count > 0) {
yield count--;
await new Promise((r) => setTimeout(r, 1000));
if(count === 0){
callback()
}
}
}
class SponsorshipList extends LitElement { class SponsorshipList extends LitElement {
static get properties() { static get properties() {
return { return {
@ -32,11 +45,14 @@ class SponsorshipList extends LitElement {
mintingAccountData: { type: Array }, mintingAccountData: { type: Array },
sponsorships: { type: Array }, sponsorships: { type: Array },
removeRewardShareLoading: { type: Array }, removeRewardShareLoading: { type: Array },
createSponsorshipMessage: { type: String }, errorMessage: { type: String },
isLoadingCreateSponsorship: { type: Array }, isLoadingCreateSponsorship: { type: Array },
publicKeyValue: { type: String }, publicKeyValue: { type: String },
error: { type: Boolean }, isOpenModal: {type: Boolean},
isOpenModal: {type: Boolean} status: {type: Number},
privateRewardShareKey: {type: String},
timer: {type: Number},
openDialogRewardShare: {type: Boolean}
} }
} }
@ -54,11 +70,14 @@ class SponsorshipList extends LitElement {
this.mintingAccountData = null this.mintingAccountData = null
this.sponsorships = [] this.sponsorships = []
this.removeRewardShareLoading = false this.removeRewardShareLoading = false
this.error = false
this.createSponsorshipMessage = "" this.errorMessage = ""
this.isLoadingCreateSponsorship = false this.isLoadingCreateSponsorship = false
this.publicKeyValue = "" this.publicKeyValue = ""
this.isOpenModal = false this.isOpenModal = false
this.status = 0
this.privateRewardShareKey = ""
this.openDialogRewardShare = false
} }
inputHandler(e) { inputHandler(e) {
@ -108,9 +127,27 @@ class SponsorshipList extends LitElement {
return nodeInfo return nodeInfo
} }
async saveToClipboard(text) {
try {
await navigator.clipboard.writeText(text)
parentEpml.request('showSnackBar', this.onSuccessMessage)
} catch (err) {
parentEpml.request('showSnackBar', this.onErrorMessage)
console.error('Copy to clipboard error:', err)
}
}
changeStatus(value){
this.status = value
this.saveToClipboard(translate(
"walletpage.wchange4"
))
}
async atMount() { async atMount() {
this.changeLanguage() this.changeLanguage()
this.addressInfo = this.addressInfo =
window.parent.reduxStore.getState().app.accountInfo.addressInfo window.parent.reduxStore.getState().app.accountInfo.addressInfo
this.isPageLoading = true this.isPageLoading = true
@ -119,6 +156,8 @@ class SponsorshipList extends LitElement {
const address = const address =
window.parent.reduxStore.getState().app?.selectedAddress window.parent.reduxStore.getState().app?.selectedAddress
?.address ?.address
let rewardShares = await this.getRewardShareRelationship( let rewardShares = await this.getRewardShareRelationship(
address address
) )
@ -130,7 +169,6 @@ class SponsorshipList extends LitElement {
type: "api", type: "api",
url: `/addresses/${rs.recipient}`, url: `/addresses/${rs.recipient}`,
}) })
let blocksRemaining = this._levelUpBlocks(addressInfo) let blocksRemaining = this._levelUpBlocks(addressInfo)
blocksRemaining = +blocksRemaining > 0 ? +blocksRemaining : 0 blocksRemaining = +blocksRemaining > 0 ? +blocksRemaining : 0
return { return {
@ -152,6 +190,7 @@ class SponsorshipList extends LitElement {
if(openModal){ if(openModal){
this.shadowRoot.querySelector('#showDialog').show() this.shadowRoot.querySelector('#showDialog').show()
} }
} catch (error) { } catch (error) {
@ -250,18 +289,23 @@ class SponsorshipList extends LitElement {
removeReceiver() removeReceiver()
} }
async createRewardShare(e) { async createRewardShare(publicKeyValue) {
this.error = false this.openDialogRewardShare = true
this.createSponsorshipMessage = "" if(!publicKeyValue){
const recipientPublicKey = this.publicKeyValue this.errorMessage = "unable to pull public key from the chain, account has no outgoing transactions"
return
}
this.privateRewardShareKey = ""
this.errorMessage = ""
const recipientPublicKey = publicKeyValue
const percentageShare = 0 const percentageShare = 0
const selectedAddress = const selectedAddress =
window.parent.reduxStore.getState().app?.selectedAddress window.parent.reduxStore.getState().app?.selectedAddress
// Check for valid... // Check for valid...
this.isLoadingCreateSponsorship = true this.isLoadingCreateSponsorship = true
let recipientAddress =
window.parent.base58PublicKeyToAddress(recipientPublicKey)
// Get Last Ref // Get Last Ref
const getLastRef = async () => { const getLastRef = async () => {
@ -281,96 +325,39 @@ class SponsorshipList extends LitElement {
return myAccountDetails return myAccountDetails
} }
// Get Reward Relationship if it already exists
const getRewardShareRelationship = async (minterAddr) => {
let isRewardShareExisting = false
let myRewardShareArray = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/rewardshares?minters=${minterAddr}&recipients=${recipientAddress}`,
})
isRewardShareExisting =
myRewardShareArray.length !== 0 ? true : false
return isRewardShareExisting
}
// Validate Reward Share by Level // Validate Reward Share by Level
const validateReceiver = async () => { const validateReceiver = async () => {
let accountDetails = await getAccountDetails() let accountDetails
let lastRef = await getLastRef() try {
let isExisting = await getRewardShareRelationship( accountDetails = await getAccountDetails()
selectedAddress.address } catch (error) {
) this.errorMessage = "Couldn't fetch account details"
// Check for creating self share at different levels (also adding check for flags...)
if (accountDetails.flags === 1) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
this.error = true
this.createSponsorshipMessage = `Cannot Create Multiple Reward Shares!`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else if (accountDetails.address === recipientAddress) {
if (accountDetails.level >= 1 && accountDetails.level <= 4) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err1string = get("rewardsharepage.rchange18")
this.error = true
this.createSponsorshipMessage = `${err1string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else if (accountDetails.level >= 5) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err2string = get("rewardsharepage.rchange19")
this.error = true
this.createSponsorshipMessage = `${err2string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else {
let err3string = get("rewardsharepage.rchange20")
this.error = true
this.createSponsorshipMessage = `${err3string} ${accountDetails.level}`
}
} else {
//Check for creating reward shares
if (accountDetails.level >= 5) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err4string = get("rewardsharepage.rchange18")
this.error = true
this.createSponsorshipMessage = `${err4string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else {
this.error = true
let err5string = get("rewardsharepage.rchange20")
this.createSponsorshipMessage = `${err5string} ${accountDetails.level}`
}
} }
let lastRef = await getLastRef()
if (accountDetails.level >= 5) {
this.status = 1
this.errorMessage = ""
try {
const myTransaction = await makeTransactionRequest(lastRef)
getTxnRequestResponse(myTransaction)
} catch (error) {
this.errorMessage = error
}
} else {
let err5string = get("rewardsharepage.rchange20")
this.errorMessage = `${err5string} ${accountDetails.level}`
}
} }
// Make Transaction Request // Make Transaction Request
@ -392,35 +379,86 @@ class SponsorshipList extends LitElement {
rewarddialog3: rewarddialog3, rewarddialog3: rewarddialog3,
rewarddialog4: rewarddialog4, rewarddialog4: rewarddialog4,
}, },
disableModal: true
}) })
return myTxnrequest return myTxnrequest
} }
const getTxnRequestResponse = (txnResponse) => { const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) {
this.error = true if(txnResponse?.extraData?.rewardSharePrivateKey && (txnResponse?.data?.message.includes('multiple') || txnResponse?.data?.message.includes('SELF_SHARE_EXISTS')) ){
this.createSponsorshipMessage = txnResponse.message
throw new Error(txnResponse) this.privateRewardShareKey = txnResponse?.extraData?.rewardSharePrivateKey
this.confirmRelationship(publicKeyValue)
} else if (txnResponse.success === false && txnResponse?.message) {
this.errorMessage = txnResponse?.message
this.isLoadingCreateSponsorship = false
throw(txnResponse?.message)
} else if ( } else if (
txnResponse.success === true && txnResponse.success === true &&
!txnResponse.data.error !txnResponse.data.error
) { ) {
let err6string = get("rewardsharepage.rchange21")
this.createSponsorshipMessage = err6string
this.error = false this.privateRewardShareKey = txnResponse?.extraData?.rewardSharePrivateKey
this.confirmRelationship(publicKeyValue)
} else { } else {
this.error = true
this.createSponsorshipMessage = txnResponse.data.message this.errorMessage = txnResponse?.data?.message || txnResponse?.message
throw new Error(txnResponse) this.isLoadingCreateSponsorship = false
throw(txnResponse?.data?.message || txnResponse?.message)
} }
} }
validateReceiver() validateReceiver()
this.isLoadingCreateSponsorship = false
} }
render() {
async confirmRelationship(recipientPublicKey){
this.status = 2
let interval = null
let stop = false
const getAnswer = async () => {
if (!stop) {
stop= true;
try {
const recipientAddress =
window.parent.base58PublicKeyToAddress(recipientPublicKey)
const minterAddress = window.parent.reduxStore.getState().app?.selectedAddress.address
const myRewardShareArray = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/rewardshares?minters=${minterAddress}&recipients=${recipientAddress}`,
})
if(myRewardShareArray.length > 0){
clearInterval(interval)
this.status = 3
this.timer = countDown(180, ()=> this.changeStatus(4));
}
} catch (error) {
console.error(error)
}
stop = false
}
};
interval = setInterval(getAnswer, 5000);
}
render() {
return html` return html`
${ ${
this.isPageLoading this.isPageLoading
@ -452,17 +490,17 @@ class SponsorshipList extends LitElement {
<p>${translate("sponsorshipspage.schange1")}</p> <p>${translate("sponsorshipspage.schange1")}</p>
</div> </div>
<div class="tableGrid table-header"> <div class="tableGrid table-header">
<div class="grid-item"> <div class="grid-item header">
<p>${translate("sponsorshipspage.schange2")}</p> <p>${translate("sponsorshipspage.schange2")}</p>
</div> </div>
<div class="grid-item"> <div class="grid-item header">
<p>${translate("walletprofile.blocksminted")}</p> <p>${translate("walletprofile.blocksminted")}</p>
</div> </div>
<div class="grid-item"> <div class="grid-item header">
<p>${translate("becomeMinterPage.bchange17")}</p> <p>${translate("becomeMinterPage.bchange17")}</p>
</div> </div>
<div class="grid-item"> <div class="grid-item header">
</div> </div>
</div> </div>
@ -472,33 +510,29 @@ class SponsorshipList extends LitElement {
(sponsorship) => html` (sponsorship) => html`
<ul class="tableGrid"> <ul class="tableGrid">
<li class="grid-item"> <li class="grid-item">
<p class="grid-item-text">
Account Address
</p>
${sponsorship.address} ${sponsorship.address}
</li> </li>
<li class="grid-item"> <li class="grid-item">
<p class="grid-item-text">
Blocks Minted
</p>
${+sponsorship.blocksMinted + ${+sponsorship.blocksMinted +
+sponsorship.blocksMintedAdjustment} +sponsorship.blocksMintedAdjustment}
</li> </li>
<li class="grid-item"> <li class="grid-item">
<p class="grid-item-text">
Copy Sponsorship Key
</p>
<button-icon-copy <mwc-button @click=${()=> {
title="${translate(
"becomeMinterPage.bchange17"
)}" this.createRewardShare(sponsorship?.publicKey)
onSuccessMessage="${translate( } }>copy</mwc-button>
"walletpage.wchange4"
)}"
onErrorMessage="${translate(
"walletpage.wchange39"
)}"
textToCopy=${sponsorship.rewardSharePublicKey}
buttonSize="28px"
iconSize="16px"
color="var(--copybutton)"
offsetLeft="4px"
></button-icon-copy>
</li> </li>
<li class="grid-item grid-item-button"> <li class="grid-item grid-item-button">
<mwc-button <mwc-button
@ -540,7 +574,7 @@ class SponsorshipList extends LitElement {
</div> </div>
` `
: ''} : ''}
<p class="message">${this.createSponsorshipMessage}</p> <p class="message-error">${this.errorMessage}</p>
<div class="form-wrapper"> <div class="form-wrapper">
<div class="sponsor-minter-wrapper"> <div class="sponsor-minter-wrapper">
<p class="sponsor-minter-text">${translate("sponsorshipspage.schange5")}</p> <p class="sponsor-minter-text">${translate("sponsorshipspage.schange5")}</p>
@ -559,17 +593,11 @@ class SponsorshipList extends LitElement {
<div class="form-item form-item--button"> <div class="form-item form-item--button">
<vaadin-button <vaadin-button
?disabled="${this.isLoadingCreateSponsorship || !this.publicKeyValue}" ?disabled="${this.isLoadingCreateSponsorship || !this.publicKeyValue}"
@click="${this.createRewardShare}" @click="${()=> this.createRewardShare(this.publicKeyValue)}"
> >
${ ${translate(
this.isLoadingCreateSponsorship === false
? html`${translate(
"puzzlepage.pchange15" "puzzlepage.pchange15"
)}` )}
: html`<paper-spinner-lite
active
></paper-spinner-lite>`
}
</vaadin-button> </vaadin-button>
</div> </div>
</div> </div>
@ -598,6 +626,85 @@ class SponsorshipList extends LitElement {
${translate("general.close")} ${translate("general.close")}
</mwc-button> </mwc-button>
</mwc-dialog>
<mwc-dialog escapeKeyAction="" scrimClickAction="" id="showDialogRewardShareCreationStatus" ?hideActions=${this.errorMessage ? false : this.status < 4 ? true : false} ?open=${this.openDialogRewardShare}>
<div class="dialog-header" >
<div class="row">
<h1>In progress </h1> <div class=${`smallLoading marginLoader ${this.status > 3 && 'hide'}`}></div>
</div>
<hr />
</div>
<div class="dialog-container">
<ul>
<li class="row between">1. Creating relationship <div class=${`smallLoading marginLoader ${this.status !== 1 && 'hide'}`}></div></li>
<li class=${`row between ${this.status < 2 && 'inactiveText' }`}>
<p>
2. Awaiting confirmation on blockchain
</p>
<div class=${`smallLoading marginLoader ${this.status !== 2 && 'hide'}`}></div>
</li>
<li class=${`row between ${this.status < 3 && 'inactiveText' }`}>
<p>
3. Finishing up
</p>
<div class="row no-width">
<div class=${`smallLoading marginLoader marginRight ${this.status !== 3 && 'hide'}`} ></div> ${asyncReplace(this.timer)}
</div>
</li>
<li class=${`row between ${this.status < 4 && 'inactiveText' }`}>
<p>
4. Complete
</p>
</li>
${this.privateRewardShareKey && this.status === 4 ? html`
<li class=${`column word-break ${this.status < 4 && 'inactiveText' }`}>
<p>Copy the key below and share it with your sponsored person.</p>
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
<span style="color: #000;">${this.privateRewardShareKey}</span>
</div>
</li>
` : ''}
</ul>
<div class="warning column">
<p>
Warning: do not close the Qortal UI until completion!
</p>
<p class="message-error">${this.errorMessage}</p>
</div>
</div>
<mwc-button
slot="primaryAction"
@click=${()=>{
this.openDialogRewardShare = false
this.errorMessage = ''
this.isLoadingCreateSponsorship = false
this.privateRewardShareKey = ""
this.atMount()
}}
class="red"
>
${translate("general.close")}
</mwc-button>
</mwc-dialog> </mwc-dialog>
</div> </div>
` `