From 24d6947d36668bf2b2fa08cbbb9899df60d1c2e5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 20 Jun 2021 16:35:16 +0200 Subject: [PATCH] Governance: Utulity function added --- .../Governance/Plugins/Pools/Superalgos.json | 6 +- .../Function-Libraries/MentorshipProgram.js | 274 ++++++++++++++++++ ...ReferralsProgram.js => ReferralProgram.js} | 57 +--- .../UI/Function-Libraries/TokenPower.js | 4 +- .../Governance/UI/Function-Libraries/Votes.js | 4 +- Projects/Governance/UI/Utilities/Pools.js | 58 ++++ Projects/ProjectsSchema.json | 13 +- 7 files changed, 357 insertions(+), 59 deletions(-) create mode 100644 Projects/Governance/UI/Function-Libraries/MentorshipProgram.js rename Projects/Governance/UI/Function-Libraries/{ReferralsProgram.js => ReferralProgram.js} (84%) create mode 100644 Projects/Governance/UI/Utilities/Pools.js diff --git a/Projects/Governance/Plugins/Pools/Superalgos.json b/Projects/Governance/Plugins/Pools/Superalgos.json index b6aa973c2..3f00e2e31 100644 --- a/Projects/Governance/Plugins/Pools/Superalgos.json +++ b/Projects/Governance/Plugins/Pools/Superalgos.json @@ -393,8 +393,8 @@ "pools": [ { "type": "Pool", - "name": "Usage", - "config": "{}", + "name": "Mentorship Program", + "config": "{\n \"codeName\": \"Mentorship-Program\"\n}", "project": "Governance", "poolClasses": [], "pools": [], @@ -612,7 +612,7 @@ "floatingObject": { "isPinned": false, "isFrozen": false, - "isCollapsed": true, + "isCollapsed": false, "angleToParent": 1, "distanceToParent": 3, "arrangementStyle": 0 diff --git a/Projects/Governance/UI/Function-Libraries/MentorshipProgram.js b/Projects/Governance/UI/Function-Libraries/MentorshipProgram.js new file mode 100644 index 000000000..90441a830 --- /dev/null +++ b/Projects/Governance/UI/Function-Libraries/MentorshipProgram.js @@ -0,0 +1,274 @@ +function newGovernanceFunctionLibraryMentorshipProgram() { + let thisObject = { + calculate: calculate + } + + return thisObject + + function calculate( + pools, + userProfiles + ) { + /* + Here we will store the total amount of tokens that is going to be distributed among all participants + of the Mentorship Program. This will come from a Pool that is configured wiht a codeName config property + with the value "Mentorship-Program" + */ + let mentorshipProgramPoolTokenReward + /* + In order to be able to calculate the share of the Mentorships Program Pool for each User Profile, + we need to accumulate all the Icomming Mentorship Power that each User Profile at their Mentorship Program + node has, because with that Incoming Power is that each Mentorship Program node gets a share of + the pool. + */ + let accumulatedIncomingMentorshipPower = 0 + + /* Scan Pools Until finding the Mentoship-Program Pool */ + for (let i = 0; i < pools.length; i++) { + let poolsNode = pools[i] + referralProgramPoolTokenReward = UI.projects.governance.utilities.pools.findPool(poolsNode, "Mentorship-Program") + } + if (mentorshipProgramPoolTokenReward === undefined || mentorshipProgramPoolTokenReward === 0) { return } + /* + We will first reset all the mentorship outgoingPower, and then distribute it. + */ + for (let i = 0; i < userProfiles.length; i++) { + let userProfile = userProfiles[i] + + if (userProfile.tokenSwitch === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram.payload === undefined) { continue } + + resetUserMentorships(userProfile.tokenSwitch.mentorshipProgram) + } + for (let i = 0; i < userProfiles.length; i++) { + let userProfile = userProfiles[i] + + if (userProfile.tokenSwitch === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram.payload === undefined) { continue } + + distributeMentorshipProgram(userProfile.tokenSwitch.mentorshipProgram) + } + for (let i = 0; i < userProfiles.length; i++) { + let userProfile = userProfiles[i] + + if (userProfile.tokenSwitch === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram === undefined) { continue } + if (userProfile.tokenSwitch.mentorshipProgram.payload === undefined) { continue } + + calculateMentorshipProgram(userProfile.tokenSwitch.mentorshipProgram) + } + + function resetUserMentorships(node) { + if (node === undefined) { return } + if (node.payload === undefined) { return } + node.payload.mentorships = { + count: 0, + outgoingPower: 0, + ownPower: 0, + incomingPower: 0, + awarded: { + tokens: 0, + percentage: 0 + } + } + /* + If the node is a User Profile, we will check if it has a User Referrer child defined. + */ + if ( + node.type === 'User Profile' && + node.tokenSwitch !== undefined && + node.tokenSwitch.mentorshipProgram !== undefined + ) { + resetUserMentorships(node.tokenSwitch.mentorshipProgram) + return + } + /* + If the node is a Mentorship Program, we will check if it has a User Referrer child defined. + */ + if ( + node.type === 'Mentorship Program' && + node.userReferrer !== undefined + ) { + resetUserMentorships(node.userReferrer) + return + } + /* + If there is a reference parent defined, this means that the mentorship outgoingPower is + transfered to it. + */ + if ( + node.type === 'User Referrer' && + node.payload.referenceParent !== undefined + ) { + resetUserMentorships(node.payload.referenceParent) + return + } + } + + function distributeMentorshipProgram(mentorshipProgram) { + if (mentorshipProgram === undefined || mentorshipProgram.payload === undefined) { return } + /* + Here we will convert Token Power into Mentorship Power. + As per system rules referringPower = tokensPower + */ + let referringPower = mentorshipProgram.payload.tokenPower + /* + We will also reseet the count of mentorships here. + */ + let count = 0 + /* + The Own Power is the power generated by the same User Profile tokens, not inherited from others. + */ + mentorshipProgram.payload.mentorships.ownPower = referringPower + + distributeMentorshipPower(mentorshipProgram, referringPower, count) + } + + function distributeMentorshipPower( + node, + referringPower, + count + ) { + + if (node === undefined) { return } + if (node.payload === undefined) { return } + + switch (node.type) { + case 'Mentorship Program': { + /* + This is the point where we increase to our local count of mentorships whatever it comes + at the count parameters. If we are processing the User Profile of this Mentorship Program + then we will add zero, otherwise, 1. + */ + node.payload.mentorships.count = node.payload.mentorships.count + count + /* + The outgoingPower of this node will be accumulating all the referringPower flowing + through it, no matter from where it comes. + */ + node.payload.mentorships.outgoingPower = node.payload.mentorships.outgoingPower + referringPower + /* + We need to adjust the balance that holds the accumulationt of all incomingPower of all Mentorship Program + nodes. To do this we will substratct the current incomingPower, bacause it is going to be recalculated + inmediatelly after this, and then we will add it again after the recalcualtion. + */ + accumulatedIncomingMentorshipPower = accumulatedIncomingMentorshipPower - node.payload.mentorships.incomingPower + /* + At any point in time, the incomingPower will be equal to the total of the outgoingPower minus + the ownPower. This is like this because the outgoingPower is the accumulation of all the + power flow that is leaving this node, which includes the ownPower. That means that if we + substract the ownPower, we will have the accumulation of all the incomingPower, which + means all the power coming from other User Profiles referencing this one. + */ + node.payload.mentorships.incomingPower = node.payload.mentorships.outgoingPower - node.payload.mentorships.ownPower + /* + Now that we have the incomingPower calculated again, we can add it again to the balance of all the incomingPower + of all Mentorship Program nodes. + */ + accumulatedIncomingMentorshipPower = accumulatedIncomingMentorshipPower + node.payload.mentorships.incomingPower + + if (node.userReferrer !== undefined) { + distributeMentorshipPower(node.userReferrer, referringPower, 0) + } + break + } + case 'User Referrer': { + drawUserReferrer(node) + if (node.payload.referenceParent !== undefined) { + distributeMentorshipPower(node.payload.referenceParent, referringPower / 10, 0) + } + break + } + case 'User Profile': { + if (node.tokenSwitch !== undefined) { + distributeMentorshipPower(node.tokenSwitch, referringPower, 0) + } + break + } + case 'Token Switch': { + if (node.mentorshipProgram !== undefined) { + distributeMentorshipPower(node.mentorshipProgram, referringPower, 1) + } + break + } + } + } + + function calculateMentorshipProgram(mentorshipProgram) { + /* + Here we will calculate which share of the Mentorship Program Pool this user will get in tokens. + To do that, we use the incomingPower, to se which proportion of the accumulatedIncomingMentorshipPower + represents. + */ + if (mentorshipProgram.payload === undefined) { return } + /* + If the accumulatedIncomingMentorshipPower is not grater the amount of tokens at the Mentorship Program Pool, then + this user will get the exact amount of tokens from the pool as incomingPower he has. + + If the accumulatedIncomingMentorshipPower is grater the amount of tokens at the Mentorship Program Pool, then + the amount ot tokens to be received is a proportional to the share of incomingPower in accumulatedIncomingMentorshipPower. + */ + let totalPowerRewardRatio = accumulatedIncomingMentorshipPower / mentorshipProgramPoolTokenReward + if (totalPowerRewardRatio < 1) { totalPowerRewardRatio = 1 } + + if (mentorshipProgram.tokensAwarded === undefined || mentorshipProgram.tokensAwarded.payload === undefined) { + mentorshipProgram.payload.uiObject.setErrorMessage("Tokens Awarded Node is needed in order for this Program to get Tokens from the Mentorship Program Pool.") + return + } + mentorshipProgram.payload.mentorships.awarded.tokens = mentorshipProgram.payload.mentorships.incomingPower * totalPowerRewardRatio + /* + As per the system rules, the Mentorship Program will not give tokens to users that do not ha their own Referrer set up, + unless it has a big amount of tokens (this last condition is for the edge case where a user it at the top of the + mentorship pyramid.) + */ + if ( + mentorshipProgram.payload.mentorships.ownPower < 1000000 && + (mentorshipProgram.userReferrer === undefined || mentorshipProgram.userReferrer.payload.referenceParent === undefined) + ) { + + mentorshipProgram.payload.uiObject.setErrorMessage("In order to be awarded " + mentorshipProgram.payload.mentorships.awarded.tokens + " SA Tokens from your mentorships, you need first to define yourself who your referrer is.") + mentorshipProgram.payload.mentorships.awarded.tokens = 0 + } + + drawMentorshipProgram(mentorshipProgram) + } + + function drawUserReferrer(node) { + if (node.payload !== undefined) { + const ownPowerText = new Intl.NumberFormat().format(node.payload.parentNode.payload.mentorships.ownPower) + const incomingPowerText = new Intl.NumberFormat().format(node.payload.parentNode.payload.mentorships.incomingPower) + const outgoingPowerText = new Intl.NumberFormat().format(node.payload.parentNode.payload.mentorships.outgoingPower) + + node.payload.uiObject.valueAngleOffset = 180 + node.payload.uiObject.valueAtAngle = true + + node.payload.uiObject.setValue(outgoingPowerText + ' ' + 'Referring Power') + + node.payload.uiObject.statusAngleOffset = 0 + node.payload.uiObject.statusAtAngle = false + + node.payload.uiObject.setStatus(ownPowerText + ' Own RP + ' + incomingPowerText + ' Incoming RP = ' + outgoingPowerText + ' ' + ' Outgoing RP') + } + } + + function drawMentorshipProgram(node) { + if (node.payload !== undefined) { + + node.payload.uiObject.statusAngleOffset = 0 + node.payload.uiObject.statusAtAngle = false + + node.payload.uiObject.setStatus("Referring Power = Token Power") + } + if (node.tokensAwarded !== undefined && node.tokensAwarded.payload !== undefined) { + + const tokensAwardedText = new Intl.NumberFormat().format(node.payload.mentorships.awarded.tokens) + + node.tokensAwarded.payload.uiObject.statusAngleOffset = 0 + node.tokensAwarded.payload.uiObject.statusAtAngle = false + + node.tokensAwarded.payload.uiObject.setValue(tokensAwardedText + ' SA Tokens') + } + } + } +} \ No newline at end of file diff --git a/Projects/Governance/UI/Function-Libraries/ReferralsProgram.js b/Projects/Governance/UI/Function-Libraries/ReferralProgram.js similarity index 84% rename from Projects/Governance/UI/Function-Libraries/ReferralsProgram.js rename to Projects/Governance/UI/Function-Libraries/ReferralProgram.js index ed0404952..703af10fa 100644 --- a/Projects/Governance/UI/Function-Libraries/ReferralsProgram.js +++ b/Projects/Governance/UI/Function-Libraries/ReferralProgram.js @@ -23,10 +23,10 @@ function newGovernanceFunctionLibraryReferralProgram() { */ let accumulatedIncomingReferralPower = 0 - /* Scan Pools Until finding the User-Referrlas Pool */ + /* Scan Pools Until finding the Referrla-Program Pool */ for (let i = 0; i < pools.length; i++) { let poolsNode = pools[i] - findPool(poolsNode) + referralProgramPoolTokenReward = UI.projects.governance.utilities.pools.findPool(poolsNode, "Referral-Program") } if (referralProgramPoolTokenReward === undefined || referralProgramPoolTokenReward === 0) { return } /* @@ -48,7 +48,7 @@ function newGovernanceFunctionLibraryReferralProgram() { if (userProfile.tokenSwitch.referralProgram === undefined) { continue } if (userProfile.tokenSwitch.referralProgram.payload === undefined) { continue } - distributeForReferralProgram(userProfile.tokenSwitch.referralProgram) + distributeReferralProgram(userProfile.tokenSwitch.referralProgram) } for (let i = 0; i < userProfiles.length; i++) { let userProfile = userProfiles[i] @@ -57,52 +57,7 @@ function newGovernanceFunctionLibraryReferralProgram() { if (userProfile.tokenSwitch.referralProgram === undefined) { continue } if (userProfile.tokenSwitch.referralProgram.payload === undefined) { continue } - calculateForReferralProgram(userProfile.tokenSwitch.referralProgram) - } - - function findPool(node) { - if (node === undefined) { return } - if (node.payload === undefined) { return } - - /* - When we reach certain node types, we will halt the distribution, because these are targets for - voting outgoingPower. - */ - if ( - node.type === 'Pool' - ) { - let codeName = UI.projects.foundations.utilities.nodeConfig.loadConfigProperty(node.payload, 'codeName') - if (codeName === "Referral-Program") { - referralProgramPoolTokenReward = node.payload.tokens - return - } - } - let schemaDocument = getSchemaDocument(node) - if (schemaDocument === undefined) { return } - - if (schemaDocument.childrenNodesProperties !== undefined) { - for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) { - let property = schemaDocument.childrenNodesProperties[i] - - switch (property.type) { - case 'node': { - let childNode = node[property.name] - findPool(childNode) - } - break - case 'array': { - let propertyArray = node[property.name] - if (propertyArray !== undefined) { - for (let m = 0; m < propertyArray.length; m++) { - let childNode = propertyArray[m] - findPool(childNode) - } - } - break - } - } - } - } + calculateReferralProgram(userProfile.tokenSwitch.referralProgram) } function resetUserReferrals(node) { @@ -152,7 +107,7 @@ function newGovernanceFunctionLibraryReferralProgram() { } } - function distributeForReferralProgram(referralProgram) { + function distributeReferralProgram(referralProgram) { if (referralProgram === undefined || referralProgram.payload === undefined) { return } /* Here we will convert Token Power into Referral Power. @@ -240,7 +195,7 @@ function newGovernanceFunctionLibraryReferralProgram() { } } - function calculateForReferralProgram(referralProgram) { + function calculateReferralProgram(referralProgram) { /* Here we will calculate which share of the Referral Program Pool this user will get in tokens. To do that, we use the incomingPower, to se which proportion of the accumulatedIncomingReferralPower diff --git a/Projects/Governance/UI/Function-Libraries/TokenPower.js b/Projects/Governance/UI/Function-Libraries/TokenPower.js index e2508f7dc..fc8e533eb 100644 --- a/Projects/Governance/UI/Function-Libraries/TokenPower.js +++ b/Projects/Governance/UI/Function-Libraries/TokenPower.js @@ -17,7 +17,7 @@ function newGovernanceFunctionLibraryTokenPower() { } for (let i = 0; i < userProfiles.length; i++) { let userProfile = userProfiles[i] - distributeForProfile(userProfile) + distributeProfile(userProfile) } function resetTokenPower(node) { @@ -67,7 +67,7 @@ function newGovernanceFunctionLibraryTokenPower() { } } - function distributeForProfile(userProfile) { + function distributeProfile(userProfile) { if (userProfile.payload === undefined) { return } let tokenPower if (userProfile.payload.blockchainTokens === undefined) { diff --git a/Projects/Governance/UI/Function-Libraries/Votes.js b/Projects/Governance/UI/Function-Libraries/Votes.js index 1137f4a50..7c4f6392d 100644 --- a/Projects/Governance/UI/Function-Libraries/Votes.js +++ b/Projects/Governance/UI/Function-Libraries/Votes.js @@ -57,7 +57,7 @@ function newGovernanceFunctionLibraryVotes() { userProfile.tokenSwitch.votingProgram.payload.votes = userProfile.tokenSwitch.votingProgram.payload.tokenPower - distributeForVotingProgram(userProfile.tokenSwitch.votingProgram) + distributeVotingProgram(userProfile.tokenSwitch.votingProgram) } function resetVotes(node) { @@ -126,7 +126,7 @@ function newGovernanceFunctionLibraryVotes() { } } - function distributeForVotingProgram(votingProgram) { + function distributeVotingProgram(votingProgram) { if (votingProgram.payload === undefined) { return } let votes = votingProgram.payload.votes distributeVotes(votingProgram, votes) diff --git a/Projects/Governance/UI/Utilities/Pools.js b/Projects/Governance/UI/Utilities/Pools.js new file mode 100644 index 000000000..f6c35a751 --- /dev/null +++ b/Projects/Governance/UI/Utilities/Pools.js @@ -0,0 +1,58 @@ +function newFoundationsUtilitiesPools() { + let thisObject = { + findPool: findPool + } + + return thisObject + + function findPool(node, codeNameToFind) { + + let tokens = undefined + findTokensAtPool(node, codeNameToFind) + + return tokens + + function findTokensAtPool(node, codeNameToFind) { + if (node === undefined) { return } + if (node.payload === undefined) { return } + /* + This function allows us to find a Pool within a Pool hierarchy that + has a give codeName config property. + */ + if ( + node.type === 'Pool' + ) { + let codeName = UI.projects.foundations.utilities.nodeConfig.loadConfigProperty(node.payload, 'codeName') + if (codeName === codeNameToFind) { + tokens = node.payload.tokens + } + } + let schemaDocument = getSchemaDocument(node) + if (schemaDocument === undefined) { return } + + if (schemaDocument.childrenNodesProperties !== undefined) { + for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) { + let property = schemaDocument.childrenNodesProperties[i] + + switch (property.type) { + case 'node': { + let childNode = node[property.name] + findTokensAtPool(childNode, codeNameToFind) + } + break + case 'array': { + let propertyArray = node[property.name] + if (propertyArray !== undefined) { + for (let m = 0; m < propertyArray.length; m++) { + let childNode = propertyArray[m] + findTokensAtPool(childNode, codeNameToFind) + } + } + break + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Projects/ProjectsSchema.json b/Projects/ProjectsSchema.json index b700dd7a6..8ce023757 100644 --- a/Projects/ProjectsSchema.json +++ b/Projects/ProjectsSchema.json @@ -1003,13 +1003,24 @@ "propertyName": "referralProgram", "functionName": "newGovernanceFunctionLibraryReferralProgram" }, + { + "name": "Mentorship Program", + "propertyName": "mentorshipProgram", + "functionName": "newGovernanceFunctionLibraryMentorshipProgram" + }, { "name": "Profile Constructor", "propertyName": "profileConstructor", "functionName": "newGovernanceFunctionLibraryProfileConstructor" } ], - "utilities": [], + "utilities": [ + { + "name": "Pools", + "propertyName": "pools", + "functionName": "newFoundationsUtilitiesPools" + } + ], "spaces": [ { "name": "User Profile Space",