No files matched your search
@@ -0,0 +1,73 @@
|
||||
exports.newMultiProject = function () {
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize
|
||||
}
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize() {
|
||||
/*
|
||||
First thing is to load the project schema file.
|
||||
*/
|
||||
let PROJECTS_SCHEMA = require(global.env.PATH_TO_PROJECTS_REQUIRED + '/' + 'ProjectsSchema.json')
|
||||
|
||||
/*
|
||||
Here we will setup the CL object, with all the
|
||||
projects and modules that will have inside.
|
||||
*/
|
||||
global.CL = {
|
||||
projects: {}
|
||||
}
|
||||
for (let i = 0; i < PROJECTS_SCHEMA.length; i++) {
|
||||
let projectDefinition = PROJECTS_SCHEMA[i]
|
||||
global.CL.projects[projectDefinition.propertyName] = {}
|
||||
let projectInstance = global.CL.projects[projectDefinition.propertyName]
|
||||
|
||||
projectInstance.utilities = {}
|
||||
projectInstance.globals = {}
|
||||
projectInstance.functionLibraries = {}
|
||||
projectInstance.taskModules = {}
|
||||
projectInstance.processModules = {}
|
||||
projectInstance.botModules = {}
|
||||
|
||||
if (projectDefinition.CL === undefined) { continue }
|
||||
|
||||
/* Set up Utilities of this Project */
|
||||
if (projectDefinition.CL.utilities !== undefined) {
|
||||
for (let j = 0; j < projectDefinition.CL.utilities.length; j++) {
|
||||
let utilityDefinition = projectDefinition.CL.utilities[j]
|
||||
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Utilities' + '/' + utilityDefinition.fileName
|
||||
|
||||
let requiredObject = require(path)
|
||||
let requiredFunction = requiredObject[utilityDefinition.functionName]
|
||||
projectInstance.utilities[utilityDefinition.propertyName] = requiredFunction.call()
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up Globals of this Project */
|
||||
if (projectDefinition.CL.globals !== undefined) {
|
||||
for (let j = 0; j < projectDefinition.CL.globals.length; j++) {
|
||||
let globalDefinition = projectDefinition.CL.globals[j]
|
||||
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Globals' + '/' + globalDefinition.fileName
|
||||
|
||||
let requiredObject = require(path)
|
||||
let requiredFunction = requiredObject[globalDefinition.functionName]
|
||||
projectInstance.globals[globalDefinition.propertyName] = requiredFunction.call()
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up Function Libraries of this Project */
|
||||
if (projectDefinition.CL.functionLibraries !== undefined) {
|
||||
for (let j = 0; j < projectDefinition.CL.functionLibraries.length; j++) {
|
||||
let functionLibraryDefinition = projectDefinition.CL.functionLibraries[j]
|
||||
let path = global.env.PATH_TO_PROJECTS_REQUIRED + '/' + projectDefinition.name + '/' + 'CL' + '/' + 'Function-Libraries' + '/' + functionLibraryDefinition.fileName
|
||||
|
||||
let requiredObject = require(path)
|
||||
let requiredFunction = requiredObject[functionLibraryDefinition.functionName]
|
||||
projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = requiredFunction.call()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,12 +64,27 @@ let EVENT_SERVER = require('./eventServer.js')
|
||||
let TASK_MANAGER_SERVER = require('./taskManagerServer.js')
|
||||
let CCXT_SERVER = require('./ccxtServer.js')
|
||||
let WEB3_SERVER = require('./web3Server.js')
|
||||
let GITHUB_SERVER = require('./githubServer.js')
|
||||
|
||||
/* Network Interfaces */
|
||||
let WEB_SOCKETS_INTERFACE = require('./webSocketsServer.js')
|
||||
let HTTP_INTERFACE = require('./httpInterface.js')
|
||||
|
||||
try {
|
||||
/*
|
||||
Setting up the modules that will be available for the Servers Running inside this Client
|
||||
*/
|
||||
let MULTI_PROJECT = require('./MultiProject.js');
|
||||
let MULTI_PROJECT_MODULE = MULTI_PROJECT.newMultiProject()
|
||||
MULTI_PROJECT_MODULE.initialize()
|
||||
/*
|
||||
Setting up external dependencies.
|
||||
*/
|
||||
CL.nodeModules = {
|
||||
fs: require('fs'),
|
||||
nodeFetch: require('node-fetch')
|
||||
}
|
||||
|
||||
console.log('CLIENT SERVERS:')
|
||||
console.log('')
|
||||
|
||||
@@ -87,7 +102,7 @@ try {
|
||||
PROJECT_FILE_SERVER.initialize()
|
||||
PROJECT_FILE_SERVER.run()
|
||||
console.log('Project File Server ......................................... Started')
|
||||
|
||||
|
||||
PLUGIN_SERVER = PLUGIN_SERVER.newPluginServer()
|
||||
PLUGIN_SERVER.initialize()
|
||||
PLUGIN_SERVER.run()
|
||||
@@ -112,12 +127,17 @@ try {
|
||||
CCXT_SERVER.initialize()
|
||||
CCXT_SERVER.run()
|
||||
console.log('CCXT Server ................................................. Started')
|
||||
|
||||
|
||||
WEB3_SERVER = WEB3_SERVER.newWeb3Server()
|
||||
WEB3_SERVER.initialize()
|
||||
WEB3_SERVER.run()
|
||||
console.log('WEB3 Server ................................................. Started')
|
||||
|
||||
GITHUB_SERVER = GITHUB_SERVER.newGithubServer()
|
||||
GITHUB_SERVER.initialize()
|
||||
GITHUB_SERVER.run()
|
||||
console.log('Github Server ............................................... Started')
|
||||
|
||||
console.log('')
|
||||
console.log('CLIENT INTERFACES:')
|
||||
console.log('')
|
||||
@@ -127,7 +147,16 @@ try {
|
||||
WEB_SOCKETS_INTERFACE.run()
|
||||
console.log('Web Sockets Interface ....................................... Listening at port ' + global.env.WEB_SOCKETS_INTERFACE_PORT)
|
||||
|
||||
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface(WEB_SERVER, DATA_FILE_SERVER, PROJECT_FILE_SERVER, UI_FILE_SERVER, PLUGIN_SERVER, CCXT_SERVER, WEB3_SERVER)
|
||||
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface(
|
||||
WEB_SERVER,
|
||||
DATA_FILE_SERVER,
|
||||
PROJECT_FILE_SERVER,
|
||||
UI_FILE_SERVER,
|
||||
PLUGIN_SERVER,
|
||||
CCXT_SERVER,
|
||||
WEB3_SERVER,
|
||||
GITHUB_SERVER
|
||||
)
|
||||
HTTP_INTERFACE.initialize()
|
||||
HTTP_INTERFACE.run()
|
||||
console.log('Http Interface .............................................. Listening at port ' + global.env.HTTP_INTERFACE_PORT)
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
exports.newGithubServer = function newGithubServer() {
|
||||
|
||||
let thisObject = {
|
||||
getGithubStars: getGithubStars,
|
||||
getGithubWatchers: getGithubWatchers,
|
||||
getGithubForks: getGithubForks,
|
||||
mergePullRequests: mergePullRequests,
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
run: run
|
||||
}
|
||||
|
||||
const GITHUB_API_WAITING_TIME = 250
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function run() {
|
||||
|
||||
}
|
||||
|
||||
async function getGithubStars(repository, username, token) {
|
||||
return await getGithubUsernames('activity', 'listStargazersForRepo', repository, username, token)
|
||||
}
|
||||
|
||||
async function getGithubWatchers(repository, username, token) {
|
||||
return await getGithubUsernames('activity', 'listWatchersForRepo', repository, username, token)
|
||||
}
|
||||
|
||||
async function getGithubForks(repository, username, token) {
|
||||
return await getGithubUsernames('repos', 'listForks', repository, username, token)
|
||||
}
|
||||
|
||||
async function mergePullRequests(commitMessage, username, token) {
|
||||
return await mergeGithubPullRequests(commitMessage, username, token)
|
||||
}
|
||||
|
||||
async function getGithubUsernames(endpoint, method, repository, username, token) {
|
||||
try {
|
||||
|
||||
repository = unescape(repository)
|
||||
username = unescape(username)
|
||||
token = unescape(token)
|
||||
let error
|
||||
let githubListArray = []
|
||||
|
||||
return await getRepoInfo()
|
||||
|
||||
async function getRepoInfo() {
|
||||
await doGithub()
|
||||
if (error !== undefined) {
|
||||
|
||||
let docs = {
|
||||
project: 'Governance',
|
||||
category: 'Topic',
|
||||
type: 'Gov Error - Get Repository Information',
|
||||
anchor: undefined,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
return respondWithDocsObject(docs, error)
|
||||
}
|
||||
|
||||
return {
|
||||
result: global.DEFAULT_OK_RESPONSE.result,
|
||||
githubListArray: githubListArray
|
||||
}
|
||||
}
|
||||
|
||||
async function doGithub() {
|
||||
|
||||
const { Octokit } = require("@octokit/rest")
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
userAgent: 'Superalgos Beta 11'
|
||||
})
|
||||
await getList()
|
||||
|
||||
async function getList() {
|
||||
const repo = repository
|
||||
const owner = 'Superalgos'
|
||||
const per_page = 100 // Max
|
||||
let page = 0
|
||||
let lastPage = false
|
||||
|
||||
while (lastPage === false) {
|
||||
try {
|
||||
page++
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
let listResponse = await octokit[endpoint][method]({
|
||||
owner,
|
||||
repo,
|
||||
per_page,
|
||||
page
|
||||
});
|
||||
|
||||
if (listResponse.data.length < 100) {
|
||||
lastPage = true
|
||||
}
|
||||
|
||||
for (let i = 0; i < listResponse.data.length; i++) {
|
||||
let listItem = listResponse.data[i]
|
||||
let githubUsername
|
||||
switch (endpoint) {
|
||||
case 'activity': {
|
||||
githubUsername = listItem.login
|
||||
break
|
||||
}
|
||||
case 'repos': {
|
||||
githubUsername = listItem.owner.login
|
||||
break
|
||||
}
|
||||
}
|
||||
//console.log(listItem)
|
||||
|
||||
githubListArray.push(githubUsername)
|
||||
}
|
||||
console.log('[INFO] Github Server -> getRepoInfo -> doGithub -> getList -> ' + method + ' Page = ' + page)
|
||||
console.log('[INFO] Github Server -> getRepoInfo -> doGithub -> getList -> ' + method + ' Received = ' + listResponse.data.length)
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
|
||||
if (err.stack.indexOf('last page') >= 0) {
|
||||
return
|
||||
} else {
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->Method call produced an error.')
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->err.stack = ' + err.stack)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->repository = ' + repository)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->username = ' + username)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> doGithub -> getList ->token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
error = err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> Method call produced an error.')
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> repository = ' + repository)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> username = ' + username)
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] Github Server -> getRepoInfo -> token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
async function mergeGithubPullRequests(commitMessage, username, token) {
|
||||
try {
|
||||
commitMessage = unescape(commitMessage)
|
||||
username = unescape(username)
|
||||
token = unescape(token)
|
||||
const repository = 'Superalgos'
|
||||
|
||||
/* Unsavping # */
|
||||
for (let i = 0; i < 10; i++) {
|
||||
commitMessage = commitMessage.replace('_SLASH_', '/')
|
||||
commitMessage = commitMessage.replace('_HASHTAG_', '#')
|
||||
}
|
||||
|
||||
let error
|
||||
let githubPrListArray = []
|
||||
|
||||
return await processOpenPullRequests()
|
||||
|
||||
async function processOpenPullRequests() {
|
||||
await doGithub()
|
||||
if (error !== undefined) {
|
||||
|
||||
let docs = {
|
||||
project: 'Governance',
|
||||
category: 'Topic',
|
||||
type: 'Gov Error - Pull Requests Not Processed',
|
||||
anchor: undefined,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
return respondWithDocsObject(docs, error)
|
||||
}
|
||||
|
||||
return {
|
||||
result: global.DEFAULT_OK_RESPONSE.result
|
||||
}
|
||||
}
|
||||
|
||||
async function doGithub() {
|
||||
try {
|
||||
const repo = repository
|
||||
const owner = 'Superalgos'
|
||||
const { Octokit } = require("@octokit/rest")
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
userAgent: 'Superalgos Beta 11'
|
||||
})
|
||||
await getPrList()
|
||||
await mergePrs()
|
||||
|
||||
async function getPrList() {
|
||||
|
||||
const per_page = 100 // Max
|
||||
let page = 0
|
||||
let lastPage = false
|
||||
|
||||
while (lastPage === false) {
|
||||
try {
|
||||
page++
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
|
||||
let listResponse = await octokit.rest.pulls.list({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
state: 'open',
|
||||
head: 'develop',
|
||||
base: 'develop',
|
||||
sort: undefined,
|
||||
direction: undefined,
|
||||
per_page: per_page,
|
||||
page: page
|
||||
});
|
||||
|
||||
if (listResponse.data.length < 100) {
|
||||
lastPage = true
|
||||
}
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Receiving Page = ' + page)
|
||||
for (let i = 0; i < listResponse.data.length; i++) {
|
||||
let pullRequest = listResponse.data[i]
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Pull Request "' + pullRequest.title + '" found and added to the list to validate. ')
|
||||
githubPrListArray.push(pullRequest)
|
||||
}
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList -> Received = ' + listResponse.data.length)
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
|
||||
if (err.stack.indexOf('last page') >= 0) {
|
||||
return
|
||||
} else {
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->Method call produced an error.')
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->err.stack = ' + err.stack)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->repository = ' + repository)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->username = ' + username)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> getPrList ->token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
error = err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePrs() {
|
||||
/*
|
||||
In order to automatically merge a PRs we will run several validations first.
|
||||
We want to automate specifically the merging of Profile File changes at the
|
||||
Governance System done by the same Github user name that matches the profile
|
||||
changed. We will also not do the merge if there are more than one file at the
|
||||
PR.
|
||||
|
||||
We will go through the list of open PRs and run the validations at each one of them.
|
||||
*/
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Ready to Validate ' + githubPrListArray.length + ' pull requests. ')
|
||||
|
||||
for (let i = 0; i < githubPrListArray.length; i++) {
|
||||
let pullRequest = githubPrListArray[i]
|
||||
/*
|
||||
Lets get the files changed at this Pull Request.
|
||||
*/
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
let listResponse = await octokit.rest.pulls.listFiles({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number
|
||||
});
|
||||
let filesChanged = listResponse.data
|
||||
let fileContentUrl // URL to the only file at the PR
|
||||
let fileContent // File content of the only file at the PR
|
||||
let userProfile // User Profile Object
|
||||
let githubUsername // The Github user name of who is submitting the Pull Request
|
||||
let mergeResponse // The response received from the call to Gihub to merge the Pull Request
|
||||
|
||||
if (await validatePrHasMoreThanOneFile() === false) { continue }
|
||||
if (await validateFileNameEqualsGithubUsername() === false) { continue }
|
||||
if (await validateFileChangedIsUserProfile() === false) { continue }
|
||||
if (await validateMessageSignedIsGithubUsername() === false) { continue }
|
||||
if (await validateUserProfileNodeNameEqualsGithubUsername() === false) { continue }
|
||||
if (await validateUserProfileIdDoesNotBelongtoAnotherUserProfile() === false) { continue }
|
||||
|
||||
if (await mergePullRequest() === false) {
|
||||
console.log('[WARN] Github Server -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
|
||||
} else {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Merge Succed -> Pull Request "' + pullRequest.title + '" successfully merged. -> mergeResponse.message = ' + mergeResponse.data.message)
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request was automatically merged by the Superalgos Governance System because it was detected that the Github User " ' + githubUsername + '" who submitted it, modified its own User Profile Plugin File and nothning else but that file. All validations were successfull.'
|
||||
});
|
||||
}
|
||||
|
||||
async function validatePrHasMoreThanOneFile() {
|
||||
/*
|
||||
Validation #1: If the PR has more than one file, then we will not automatically
|
||||
merge it.
|
||||
*/
|
||||
if (filesChanged.length !== 1) {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #1 Failed -> Pull Request "' + pullRequest.title + '" not merged because it contains more than 1 file. -> fileCount = ' + filesChanged.length)
|
||||
/*
|
||||
We will close PRs that contains any User Profile file together with other files in the same Pull Request.
|
||||
This will avoid manual merges to include User Profile files.
|
||||
*/
|
||||
for (let j = 0; j < filesChanged.length; j++) {
|
||||
let pullRequestFile = filesChanged[j]
|
||||
let fileContentUrl = pullRequestFile.raw_url
|
||||
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') >= 0) {
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that a User Profile file... \n\n' + fileContentUrl + '\n\n...was submitted together with ' + (filesChanged.length - 1) + ' other file/s. User Profiles files as per the Governance System rules, must be the only file present at a Pull Request in order to pass all the validations and be automatically merged.'
|
||||
});
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
break
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function validateFileNameEqualsGithubUsername() {
|
||||
/*
|
||||
Validation #2: File Name must be the same to the Github Username of the PR owner.
|
||||
*/
|
||||
let pullRequestFile = filesChanged[0]
|
||||
fileContentUrl = pullRequestFile.raw_url
|
||||
|
||||
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') < 0) {
|
||||
/*
|
||||
If it is not a user profile then there is no need to auto merge.
|
||||
*/
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified at the Pull Request is not a User Profile file. -> fileContentUrl = ' + fileContentUrl)
|
||||
return false
|
||||
}
|
||||
|
||||
let splittedURL = fileContentUrl.split('/')
|
||||
let fileName = splittedURL[splittedURL.length - 1]
|
||||
let splittedFileName = fileName.split('.')
|
||||
fileName = splittedFileName[0]
|
||||
githubUsername = pullRequest.user.login
|
||||
|
||||
if (githubUsername !== fileName) {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the File Name. -> Github Username = ' + githubUsername + '-> fileName = ' + fileName)
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the name of the User Profile Plugin File.\n\n File Name = "' + fileName + '"'
|
||||
});
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function validateFileChangedIsUserProfile() {
|
||||
/*
|
||||
Validation #3: The file changed at the PR is a User Profile.
|
||||
*/
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
fileContent = await CL.projects.foundations.utilities.webAccess.fetchAPIDataFile(fileContentUrl)
|
||||
userProfile = JSON.parse(fileContent)
|
||||
|
||||
if (userProfile.type !== 'User Profile') {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #3 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified is not a User Profile. -> Type = ' + userProfile.type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function validateMessageSignedIsGithubUsername() {
|
||||
/*
|
||||
Validation #4: The message signed at the config is not the Github Username.
|
||||
*/
|
||||
let config = JSON.parse(userProfile.config)
|
||||
let messageSigned = config.signature.message
|
||||
if (messageSigned !== githubUsername) {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #4 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the Message Signed at the User Profile. -> Github Username = ' + githubUsername + '-> messageSigned = ' + messageSigned)
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the Message Signed at the User Profile.\n\n Message Signed = "' + messageSigned + '"'
|
||||
});
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function validateUserProfileNodeNameEqualsGithubUsername() {
|
||||
/*
|
||||
Validation #5: The name of the User Profile node is not the Github Username.
|
||||
*/
|
||||
if (userProfile.name !== githubUsername) {
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #5 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the User Profile node\'s name. -> Github Username = ' + githubUsername + '-> userProfile.name = ' + userProfile.name)
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the User Profile node\'s name.\n\n User Profile Name = "' + userProfile.name + '"'
|
||||
});
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function validateUserProfileIdDoesNotBelongtoAnotherUserProfile() {
|
||||
/*
|
||||
Validation #6: The id of the User Profile can not be the id of an already existing User Profile
|
||||
unless the existing one belongs to the same Github username.
|
||||
*/
|
||||
let userProfileIdMap = new Map()
|
||||
let pluginFileNames = await CL.projects.foundations.utilities.plugins.getPluginFileNames(
|
||||
'Governance',
|
||||
'User-Profiles'
|
||||
)
|
||||
for (let i = 0; i < pluginFileNames.length; i++) {
|
||||
let pluginFileName = pluginFileNames[i]
|
||||
|
||||
let pluginFileContent = await CL.projects.foundations.utilities.plugins.getPluginFileContent(
|
||||
'Governance',
|
||||
'User-Profiles',
|
||||
pluginFileName
|
||||
)
|
||||
|
||||
let otherUserProfile = JSON.parse(pluginFileContent)
|
||||
userProfileIdMap.set(otherUserProfile.id, otherUserProfile.name)
|
||||
}
|
||||
|
||||
let testUserProfile = userProfileIdMap.get(userProfile.id)
|
||||
if (testUserProfile === undefined) { return true }
|
||||
if (testUserProfile !== userProfile.name) {
|
||||
|
||||
console.log('[INFO] Github Server -> mergeGithubPullRequests -> Validation #6 Failed -> Pull Request "' + pullRequest.title + '" not merged because the User Profile Id already exists and belongs to another User Profile on record. -> Profile Id = ' + userProfile.id + '-> User Profile with the same Id = ' + testUserProfile)
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because the User Profile Id already exists and belongs to another User Profile on record. \n\nUser Profile Id = "' + userProfile.id + '" \n\n User Profile with the same Id = "' + testUserProfile + '"'
|
||||
});
|
||||
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePullRequest() {
|
||||
/*
|
||||
All validations passed, we will proceed an merge this Pull Request.
|
||||
*/
|
||||
await CL.projects.foundations.utilities.asyncFunctions.sleep(GITHUB_API_WAITING_TIME)
|
||||
mergeResponse = await octokit.rest.pulls.merge({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
commit_title: 'Changes in User Profile done by Profile Owner ' + githubUsername + ' automatically merged by Superalgos.'
|
||||
});
|
||||
return mergeResponse.data.merged
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> doGithub -> err.stack = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> Method call produced an error.')
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> repository = ' + repository)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> username = ' + username)
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] Github Server -> mergeGithubPullRequests -> token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
function respondWithDocsObject(docs, error) {
|
||||
|
||||
if (error.message !== undefined) {
|
||||
docs.placeholder.errorMessage = {
|
||||
style: 'Error',
|
||||
text: error.message
|
||||
}
|
||||
}
|
||||
if (error.stack !== undefined) {
|
||||
docs.placeholder.errorStack = {
|
||||
style: 'Javascript',
|
||||
text: error.stack
|
||||
}
|
||||
}
|
||||
if (error.code !== undefined) {
|
||||
docs.placeholder.errorCode = {
|
||||
style: 'Json',
|
||||
text: error.code
|
||||
}
|
||||
}
|
||||
|
||||
docs.placeholder.errorDetails = {
|
||||
style: 'Json',
|
||||
text: JSON.stringify(error, undefined, 4)
|
||||
}
|
||||
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
docs: docs
|
||||
}
|
||||
|
||||
return customResponse
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,13 @@
|
||||
exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVER, PROJECT_FILE_SERVER, UI_FILE_SERVER, PLUGIN_SERVER, CCXT_SERVER, WEB3_SERVER) {
|
||||
exports.newHttpInterface = function newHttpInterface(
|
||||
WEB_SERVER,
|
||||
DATA_FILE_SERVER,
|
||||
PROJECT_FILE_SERVER,
|
||||
UI_FILE_SERVER,
|
||||
PLUGIN_SERVER,
|
||||
CCXT_SERVER,
|
||||
WEB3_SERVER,
|
||||
GITHUB_SERVER
|
||||
) {
|
||||
|
||||
/*
|
||||
IMPORTANT: If you are reviewing the code of the project please note
|
||||
@@ -366,6 +375,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Save-Concept-Schema': {
|
||||
getBody(processRequest)
|
||||
|
||||
@@ -396,6 +406,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Save-Topic-Schema': {
|
||||
getBody(processRequest)
|
||||
|
||||
@@ -426,6 +437,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Save-Tutorial-Schema': {
|
||||
getBody(processRequest)
|
||||
|
||||
@@ -456,6 +468,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Save-Review-Schema': {
|
||||
getBody(processRequest)
|
||||
|
||||
@@ -486,6 +499,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Save-Book-Schema': {
|
||||
getBody(processRequest)
|
||||
|
||||
@@ -1019,138 +1033,80 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
break
|
||||
|
||||
case 'Gov': {
|
||||
switch (requestParameters[2]) { // switch by command
|
||||
case 'getGithubStars': {
|
||||
getGithubUsernames('activity', 'listStargazersForRepo')
|
||||
break
|
||||
}
|
||||
case 'getGithubWatchers': {
|
||||
getGithubUsernames('activity', 'listWatchersForRepo')
|
||||
break
|
||||
}
|
||||
case 'getGithubForks': {
|
||||
getGithubUsernames('repos', 'listForks')
|
||||
break
|
||||
}
|
||||
case 'PRs': {
|
||||
mergeGithubPullRequests()
|
||||
break
|
||||
}
|
||||
case 'Pay': {
|
||||
payToContributors()
|
||||
break
|
||||
}
|
||||
}
|
||||
case 'GOV': {
|
||||
/*
|
||||
This is the Governance endpoint at the Http Interface. All methods
|
||||
related to the Governance System are implemented here and routed
|
||||
to the backend Servers that can process them.
|
||||
*/
|
||||
getBody(processRequest)
|
||||
|
||||
function getGithubUsernames(endpoint, method) {
|
||||
async function processRequest(body) {
|
||||
try {
|
||||
const GITHUB_API_WAITING_TIME = 250
|
||||
const repository = unescape(requestParameters[3])
|
||||
const username = unescape(requestParameters[4])
|
||||
const token = unescape(requestParameters[5])
|
||||
let error
|
||||
let githubListArray = []
|
||||
let params = JSON.parse(body)
|
||||
|
||||
getRepoInfo()
|
||||
switch (params.method) {
|
||||
case 'getGithubStars': {
|
||||
|
||||
async function getRepoInfo() {
|
||||
await doGithub()
|
||||
if (error !== undefined) {
|
||||
let serverResponse = await GITHUB_SERVER.getGithubStars(
|
||||
params.repository,
|
||||
params.username,
|
||||
params.token
|
||||
)
|
||||
|
||||
let docs = {
|
||||
project: 'Governance',
|
||||
category: 'Topic',
|
||||
type: 'Gov Error - Get Repository Information',
|
||||
anchor: undefined,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
respondWithDocsObject(docs, error)
|
||||
respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||
return
|
||||
}
|
||||
case 'getGithubWatchers': {
|
||||
|
||||
respondWithContent(JSON.stringify(githubListArray), httpResponse)
|
||||
}
|
||||
let serverResponse = await GITHUB_SERVER.getGithubWatchers(
|
||||
params.repository,
|
||||
params.username,
|
||||
params.token
|
||||
)
|
||||
|
||||
async function doGithub() {
|
||||
respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||
return
|
||||
}
|
||||
case 'getGithubForks': {
|
||||
|
||||
const { Octokit } = require("@octokit/rest")
|
||||
let serverResponse = await GITHUB_SERVER.getGithubForks(
|
||||
params.repository,
|
||||
params.username,
|
||||
params.token
|
||||
)
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
userAgent: 'Superalgos Beta 11'
|
||||
})
|
||||
await getList()
|
||||
respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||
return
|
||||
}
|
||||
case 'mergePullRequests': {
|
||||
|
||||
async function getList() {
|
||||
const repo = repository
|
||||
const owner = 'Superalgos'
|
||||
const per_page = 100 // Max
|
||||
let page = 0
|
||||
let lastPage = false
|
||||
let serverResponse = await GITHUB_SERVER.mergePullRequests(
|
||||
params.commitMessage,
|
||||
params.username,
|
||||
params.token
|
||||
)
|
||||
|
||||
while (lastPage === false) {
|
||||
try {
|
||||
page++
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
let listResponse = await octokit[endpoint][method]({
|
||||
owner,
|
||||
repo,
|
||||
per_page,
|
||||
page
|
||||
});
|
||||
respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||
return
|
||||
}
|
||||
case 'payContributors': {
|
||||
|
||||
if (listResponse.data.length < 100) {
|
||||
lastPage = true
|
||||
}
|
||||
let serverResponse = await WEB3_SERVER.payContributors(
|
||||
params.signature
|
||||
)
|
||||
|
||||
for (let i = 0; i < listResponse.data.length; i++) {
|
||||
let listItem = listResponse.data[i]
|
||||
let githubUsername
|
||||
switch (endpoint) {
|
||||
case 'activity': {
|
||||
githubUsername = listItem.login
|
||||
break
|
||||
}
|
||||
case 'repos': {
|
||||
githubUsername = listItem.owner.login
|
||||
break
|
||||
}
|
||||
}
|
||||
//console.log(listItem)
|
||||
|
||||
githubListArray.push(githubUsername)
|
||||
}
|
||||
console.log('[INFO] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList -> ' + method + ' Page = ' + page)
|
||||
console.log('[INFO] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList -> ' + method + ' Received = ' + listResponse.data.length)
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
|
||||
if (err.stack.indexOf('last page') >= 0) {
|
||||
return
|
||||
} else {
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->repository = ' + repository)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->username = ' + username)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> doGithub -> getList ->token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
error = err
|
||||
}
|
||||
}
|
||||
}
|
||||
respondWithContent(JSON.stringify(serverResponse), httpResponse)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), httpResponse)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> repository = ' + repository)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> username = ' + username)
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] httpInterface -> Gov -> getRepoInfo -> token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
console.log('[ERROR] httpInterface -> GOV -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> GOV -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> GOV -> Params Received = ' + body)
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
@@ -1160,332 +1116,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
respondWithContent(JSON.stringify(error), httpResponse)
|
||||
}
|
||||
}
|
||||
|
||||
function respondWithDocsObject(docs, error) {
|
||||
|
||||
if (error.message !== undefined) {
|
||||
docs.placeholder.errorMessage = {
|
||||
style: 'Error',
|
||||
text: error.message
|
||||
}
|
||||
}
|
||||
if (error.stack !== undefined) {
|
||||
docs.placeholder.errorStack = {
|
||||
style: 'Javascript',
|
||||
text: error.stack
|
||||
}
|
||||
}
|
||||
if (error.code !== undefined) {
|
||||
docs.placeholder.errorCode = {
|
||||
style: 'Json',
|
||||
text: error.code
|
||||
}
|
||||
}
|
||||
|
||||
docs.placeholder.errorDetails = {
|
||||
style: 'Json',
|
||||
text: JSON.stringify(error, undefined, 4)
|
||||
}
|
||||
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
docs: docs
|
||||
}
|
||||
|
||||
respondWithContent(JSON.stringify(customResponse), httpResponse)
|
||||
|
||||
}
|
||||
|
||||
function mergeGithubPullRequests() {
|
||||
try {
|
||||
let commitMessage = unescape(requestParameters[3])
|
||||
|
||||
/* Unsavping # */
|
||||
for (let i = 0; i < 10; i++) {
|
||||
commitMessage = commitMessage.replace('_SLASH_', '/')
|
||||
commitMessage = commitMessage.replace('_HASHTAG_', '#')
|
||||
}
|
||||
|
||||
const GITHUB_API_WAITING_TIME = 250
|
||||
const repository = 'Superalgos'
|
||||
const username = unescape(requestParameters[4])
|
||||
const token = unescape(requestParameters[5])
|
||||
|
||||
let error
|
||||
let githubPrListArray = []
|
||||
|
||||
processOpenPullRequests()
|
||||
|
||||
async function processOpenPullRequests() {
|
||||
await doGithub()
|
||||
if (error !== undefined) {
|
||||
|
||||
let docs = {
|
||||
project: 'Governance',
|
||||
category: 'Topic',
|
||||
type: 'Gov Error - Merge Pull Requests',
|
||||
anchor: undefined,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
respondWithDocsObject(docs, error)
|
||||
return
|
||||
}
|
||||
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), httpResponse)
|
||||
}
|
||||
|
||||
async function doGithub() {
|
||||
try {
|
||||
const repo = repository
|
||||
const owner = 'Superalgos'
|
||||
const { Octokit } = require("@octokit/rest")
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
userAgent: 'Superalgos Beta 11'
|
||||
})
|
||||
await getPrList()
|
||||
await mergePrs()
|
||||
|
||||
async function getPrList() {
|
||||
|
||||
const per_page = 100 // Max
|
||||
let page = 0
|
||||
let lastPage = false
|
||||
|
||||
while (lastPage === false) {
|
||||
try {
|
||||
page++
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
let listResponse = await octokit.rest.pulls.list({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
state: 'open',
|
||||
head: 'develop',
|
||||
base: 'develop',
|
||||
sort: undefined,
|
||||
direction: undefined,
|
||||
per_page: per_page,
|
||||
page: page
|
||||
});
|
||||
|
||||
if (listResponse.data.length < 100) {
|
||||
lastPage = true
|
||||
}
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Receiving Page = ' + page)
|
||||
for (let i = 0; i < listResponse.data.length; i++) {
|
||||
let pullRequest = listResponse.data[i]
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Pull Request "' + pullRequest.title + '" found and added to the list to validate. ')
|
||||
githubPrListArray.push(pullRequest)
|
||||
}
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList -> Received = ' + listResponse.data.length)
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
|
||||
if (err.stack.indexOf('last page') >= 0) {
|
||||
return
|
||||
} else {
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->repository = ' + repository)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->username = ' + username)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> getPrList ->token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
error = err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePrs() {
|
||||
/*
|
||||
In order to automatically merge a PRs we will run several validations first.
|
||||
We want to automate specifically the merging of Profile File changes at the
|
||||
Governance System done by the same Github user name that matches the profile
|
||||
changed. We will also not do the merge if there are more than one file at the
|
||||
PR.
|
||||
|
||||
We will go through the list of open PRs and run the validations at each one of them.
|
||||
*/
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Ready to Validate ' + githubPrListArray.length + ' pull requests. ')
|
||||
|
||||
for (let i = 0; i < githubPrListArray.length; i++) {
|
||||
let pullRequest = githubPrListArray[i]
|
||||
/*
|
||||
Lets get the files changed at this Pull Request.
|
||||
*/
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
let listResponse = await octokit.rest.pulls.listFiles({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number
|
||||
});
|
||||
/*
|
||||
Validation #1: If the PR has more than one file, then we will not automatically
|
||||
merge it.
|
||||
*/
|
||||
if (listResponse.data.length !== 1) {
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #1 Failed -> Pull Request "' + pullRequest.title + '" not merged because it contains more than 1 file. -> fileCount = ' + listResponse.data.length)
|
||||
/*
|
||||
We will close PRs that contains any User Profile file together with other files in the same Pull Request.
|
||||
This will avoid manual merges to include User Profile files.
|
||||
*/
|
||||
for (j = 0; j < listResponse.data.length; j++) {
|
||||
let pullRequestFile = listResponse.data[j]
|
||||
let fileContentUrl = pullRequestFile.raw_url
|
||||
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') >= 0) {
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that a User Profile file... \n\n' + fileContentUrl + '\n\n...was submitted together with ' + (listResponse.data.length - 1) + ' other file/s. User Profiles files as per the Governance System rules, must be the only file present at a Pull Request in order to pass all the validations and be automatically merged.'
|
||||
});
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
break
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
let pullRequestFile = listResponse.data[0]
|
||||
/*
|
||||
Validation #2: File Name must be the same to the Github Username of the PR owner.
|
||||
*/
|
||||
let fileContentUrl = pullRequestFile.raw_url
|
||||
|
||||
if (fileContentUrl.indexOf('Governance/Plugins/User-Profiles') < 0) {
|
||||
/*
|
||||
If it is not a user profile then there is no need to auto merge.
|
||||
*/
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified at the Pull Request is not a User Profile file. -> fileContentUrl = ' + fileContentUrl)
|
||||
continue
|
||||
}
|
||||
|
||||
let splittedURL = fileContentUrl.split('/')
|
||||
let fileName = splittedURL[splittedURL.length - 1]
|
||||
let splittedFileName = fileName.split('.')
|
||||
fileName = splittedFileName[0]
|
||||
let githubUsername = pullRequest.user.login
|
||||
|
||||
if (githubUsername !== fileName) {
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #2 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the File Name. -> Github Username = ' + githubUsername + '-> fileName = ' + fileName)
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the name of the User Profile Plugin File.\n\n File Name = "' + fileName + '"'
|
||||
});
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
continue
|
||||
}
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
let fileContent = await fetchAPIDataFile(fileContentUrl)
|
||||
|
||||
let userProfile = JSON.parse(fileContent)
|
||||
/*
|
||||
Validation #3: The file changed at the PR is a User Profile.
|
||||
*/
|
||||
if (userProfile.type !== 'User Profile') {
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #3 Failed -> Pull Request "' + pullRequest.title + '" not merged because the file modified is not a User Profile. -> Type = ' + userProfile.type)
|
||||
continue
|
||||
}
|
||||
/*
|
||||
Validation #4: The message signed at the config is not the Github Username.
|
||||
*/
|
||||
let config = JSON.parse(userProfile.config)
|
||||
let messageSigned = config.signature.message
|
||||
if (messageSigned !== githubUsername) {
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Validation #4 Failed -> Pull Request "' + pullRequest.title + '" not merged because the Github Username is not equal to the Message Signed at the User Profile. -> Github Username = ' + githubUsername + '-> messageSigned = ' + messageSigned)
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request could not be automatically merged and was closed by the Superalgos Governance System because it was detected that the Github User "' + githubUsername + '" who submitted it, is not equal to the Message Signed at the User Profile.\n\n Message Signed = "' + messageSigned + '"'
|
||||
});
|
||||
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.pulls.update({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
state: 'closed'
|
||||
});
|
||||
continue
|
||||
}
|
||||
/*
|
||||
All validations passed, we will proceed an merge this Pull Request.
|
||||
*/
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
let mergeResponse = await octokit.rest.pulls.merge({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
pull_number: pullRequest.number,
|
||||
commit_title: 'Changes in User Profile done by Profile Owner ' + githubUsername + ' automatically merged by Superalgos.'
|
||||
});
|
||||
|
||||
if (mergeResponse.data.merged !== true) {
|
||||
console.log('[WARN] httpInterface -> Gov -> mergeGithubPullRequests -> Merge Failed -> Pull Request "' + pullRequest.title + '" not merged because Github could not merge it. -> mergeResponse.message = ' + mergeResponse.data.message)
|
||||
continue
|
||||
} else {
|
||||
console.log('[INFO] httpInterface -> Gov -> mergeGithubPullRequests -> Merge Succed -> Pull Request "' + pullRequest.title + '" successfully merged. -> mergeResponse.message = ' + mergeResponse.data.message)
|
||||
await sleep(GITHUB_API_WAITING_TIME)
|
||||
await octokit.rest.issues.createComment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: pullRequest.number,
|
||||
body: 'This Pull Request was automatically merged by the Superalgos Governance System because it was detected that the Github User " ' + githubUsername + '" who submitted it, modified its own User Profile Plugin File and nothning else but that file. All validations were successfull.'
|
||||
});
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> doGithub -> err.stack = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> repository = ' + repository)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> username = ' + username)
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> token starts with = ' + token.substring(0, 10) + '...')
|
||||
console.log('[ERROR] httpInterface -> Gov -> mergeGithubPullRequests -> token ends with = ' + '...' + token.substring(token.length - 10))
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
respondWithContent(JSON.stringify(error), httpResponse)
|
||||
}
|
||||
}
|
||||
|
||||
function payToContributors() {
|
||||
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'LegacyPlotter.js':
|
||||
{
|
||||
@@ -1701,30 +1333,70 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'PluginFileNames':
|
||||
{
|
||||
let project = unescape(requestParameters[2])
|
||||
let pluginType = unescape(requestParameters[3])
|
||||
processRequest()
|
||||
|
||||
const fs = require('fs')
|
||||
let folder = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType
|
||||
async function processRequest(body) {
|
||||
try {
|
||||
let project = unescape(requestParameters[2])
|
||||
let folder = unescape(requestParameters[3])
|
||||
|
||||
fs.readdir(folder, (err, files) => {
|
||||
if (files === undefined) {
|
||||
files = []
|
||||
let response = await CL.projects.foundations.utilities.plugins.getPluginFileNames(
|
||||
project,
|
||||
folder
|
||||
)
|
||||
|
||||
respondWithContent(JSON.stringify(response), httpResponse)
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> PluginFileNames -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> PluginFileNames -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> PluginFileNames -> Params Received = ' + body)
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
respondWithContent(JSON.stringify(error), httpResponse)
|
||||
}
|
||||
respondWithContent(JSON.stringify(files), httpResponse)
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
|
||||
case 'LoadPlugin':
|
||||
|
||||
{
|
||||
let project = unescape(requestParameters[2])
|
||||
let pluginType = unescape(requestParameters[3])
|
||||
let fileName = unescape(requestParameters[4])
|
||||
let filePath = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType + '/' + fileName
|
||||
respondWithFile(filePath, httpResponse)
|
||||
processRequest()
|
||||
|
||||
async function processRequest(body) {
|
||||
try {
|
||||
let project = unescape(requestParameters[2])
|
||||
let folder = unescape(requestParameters[3])
|
||||
let fileName = unescape(requestParameters[4])
|
||||
|
||||
let response = await CL.projects.foundations.utilities.plugins.getPluginFileContent(
|
||||
project,
|
||||
folder,
|
||||
fileName
|
||||
)
|
||||
|
||||
respondWithContent(response, httpResponse)
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> LoadPlugin -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> LoadPlugin -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> LoadPlugin -> Params Received = ' + body)
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
respondWithContent(JSON.stringify(error), httpResponse)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
|
||||
case 'SavePlugin':
|
||||
getBody(processRequest)
|
||||
@@ -2431,44 +2103,4 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
return files.reduce((a, f) => a.concat(f), []);
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchAPIDataFile(url) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
const fetch = require('node-fetch')
|
||||
/*
|
||||
This is how we call the API.
|
||||
*/
|
||||
fetch(url)
|
||||
.then((response) => {
|
||||
|
||||
if (response.status !== 200) {
|
||||
console.log('[ERROR] fetchAPIData -> then -> url =' + url)
|
||||
reject()
|
||||
return
|
||||
}
|
||||
getResponseBody()
|
||||
|
||||
function getResponseBody() {
|
||||
response.text().then(body => {
|
||||
resolve(body)
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('[ERROR] fetchAPIData -> url =' + url)
|
||||
reject()
|
||||
})
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
return promise
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ Node JS is an open-source server environment required to run Superalgos.
|
||||
|
||||
**A.** Go to the Node JS [download page](https://nodejs.org/en/download/).
|
||||
|
||||
**B.** Download your system’s installer. Select *LTS Recommended for Most Users* and click the big Windows or macOS Installer button. If you are on Linux, the installer is listed further down the page.
|
||||
**B.** Download your system's installer. Select *LTS Recommended for Most Users* and click the big Windows or macOS Installer button. If you are on Linux, the installer is listed further down the page.
|
||||
|
||||
**C.** Run the installer with the default configuration — just click Next until Node.JS is fully installed. That's it! You can continue with step 2 (Git Installation).
|
||||
|
||||
@@ -94,13 +94,13 @@ Before you begin, it is recommended that you set up Chrome/Safari as your defaul
|
||||
|
||||
**A.** Scroll the page all the way to the top. Find and click the **Fork** button to create your fork/copy of this repository. To fork Superalgos you need a Github account. If you don't have one, go ahead and create it.
|
||||
|
||||
**NOTE:** A Fork is required for your contributions to the project. The reason why Superalgos is free and open-source is that the project has set up a <a href="https://superalgos.org/community-business.shtml" target="_blank">Collective Business</a> in which all users may participate. The way to participate is to <a href="https://superalgos.org/community-contribute.shtml" target="_blank">contribute</a> to make Superalgos better. The project's <a href="https://superalgos.org/token-overview.shtml" target="_blank">token</a> is distributed among contributors.
|
||||
**NOTE:** A Fork is required for your contributions to the project. The reason why Superalgos is free and open-source is that the project has set up a <a href="https://superalgos.org/project-one-pager.shtml" target="_blank">Collective Business</a> in which all users may participate. The way to participate is to <a href="https://superalgos.org/community-contribute.shtml" target="_blank">contribute</a> to make Superalgos better. The project's <a href="https://superalgos.org/token-overview.shtml" target="_blank">token</a> is distributed among contributors.
|
||||
|
||||
## 2. Clone Your Fork
|
||||
|
||||
**A.** Once the fork is created, you will land on the page of your fork. Copy the URL from your browser's address bar.
|
||||
|
||||
**B.** In your computer/laptop/server, open a command prompt or terminal. Make sure you are in a directory where you have write permissions (on most systems the terminal will open in your user’s home directory, so you’re good). Clone the git repository using the command:
|
||||
**B.** In your computer/laptop/server, open a command prompt or terminal. Make sure you are in a directory where you have write permissions (on most systems the terminal will open in your user's home directory, so you're good). Clone the git repository using the command:
|
||||
|
||||
```
|
||||
git clone <URL of your Superalgos fork>
|
||||
@@ -116,9 +116,13 @@ This creates the `Superalgos` folder in the current directory, which contains th
|
||||
|
||||
## 3. Install Node Dependencies
|
||||
|
||||
**A.** After the Superalgos directory has been installed, the final step of installation is to set up the necessary node dependencies.
|
||||
After the Superalgos directory has been installed, the final step of installation is to set up the necessary node dependencies. In the same command prompt or terminal you just used, type the following:
|
||||
|
||||
**B.** In the same command prompt or terminal you just used, type the following command:
|
||||
```
|
||||
cd Superalgos
|
||||
```
|
||||
|
||||
That should take you inside the Superalgos folder created by the `git clone` command earlier. Now, run the following command:
|
||||
|
||||
```
|
||||
node setup
|
||||
@@ -233,7 +237,7 @@ We are testing the UI on Google Chrome and Safari on macOS only. It may work on
|
||||
|
||||
# Running Superalgos on a Headless Linux Server as a Daemon
|
||||
|
||||
If you’re running Superalgos on a headless linux server like a Raspberry Pi, you might want to run it as a daemon so it isn’t attached to your current login session. The easiest, most standard way to go about this is probably using `systemd`. Most linux distributions use it as default init system/service manager.
|
||||
If you're running Superalgos on a headless linux server like a Raspberry Pi, you might want to run it as a daemon so it isn't attached to your current login session. The easiest, most standard way to go about this is probably using `systemd`. Most linux distributions use it as default init system/service manager.
|
||||
|
||||
## Using `systemd`
|
||||
|
||||
@@ -252,7 +256,7 @@ ExecStart=/usr/bin/node run minMemo noBrowser
|
||||
WantedBy=multi-user.target
|
||||
|
||||
```
|
||||
There is no need to run Superalgos as root so we’re running it as a user. The `minMemo` option assumes you’re running on a small machine like a Raspberry Pi, while `noBrowser` makes sense for running daemonized.
|
||||
There is no need to run Superalgos as root so we're running it as a user. The `minMemo` option assumes you're running on a small machine like a Raspberry Pi, while `noBrowser` makes sense for running daemonized.
|
||||
|
||||
Now, as root (or using `sudo`), put the file `superalgos.service` you just created in `/etc/systemd/system/` and issue the command
|
||||
```
|
||||
@@ -290,7 +294,7 @@ Once the app finishes loading, an interactive tutorial takes you by the hand and
|
||||
|
||||

|
||||
|
||||
**NOTE:** The tutorial uses Binance or Binance US as the exchange of choice. If you don’t have an account with Binance or Binance US, you will still be able to follow 100% of the tutorial. When you get to the live trading section, keep going even if you don't intend to run the session. You may learn how to work with other exchanges later on.
|
||||
**NOTE:** The tutorial uses Binance or Binance US as the exchange of choice. If you don't have an account with Binance or Binance US, you will still be able to follow 100% of the tutorial. When you get to the live trading section, keep going even if you don't intend to run the session. You may learn how to work with other exchanges later on.
|
||||
|
||||
# Docker Deployments
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
exports.newFoundationsUtilitiesAsyncFunctions = function () {
|
||||
|
||||
let thisObject = {
|
||||
sleep: sleep
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
exports.newFoundationsUtilitiesPlugins = function () {
|
||||
|
||||
let thisObject = {
|
||||
getPluginFileNames: getPluginFileNames,
|
||||
getPluginFileContent: getPluginFileContent
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function getPluginFileNames(project, folder) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
let path = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + folder
|
||||
|
||||
CL.nodeModules.fs.readdir(path, (err, files) => {
|
||||
if (err) {
|
||||
reject()
|
||||
return
|
||||
}
|
||||
if (files === undefined) {
|
||||
files = []
|
||||
}
|
||||
resolve(files)
|
||||
})
|
||||
|
||||
}
|
||||
)
|
||||
return promise
|
||||
}
|
||||
|
||||
async function getPluginFileContent(project, folder, fileName) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
let path = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + folder + '/' + fileName
|
||||
|
||||
CL.nodeModules.fs.readFile(path, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (err) {
|
||||
reject()
|
||||
return
|
||||
}
|
||||
resolve(file.toString())
|
||||
}
|
||||
}
|
||||
)
|
||||
return promise
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
exports.newFoundationsUtilitiesWebAccess = function () {
|
||||
|
||||
let thisObject = {
|
||||
fetchAPIDataFile: fetchAPIDataFile
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function fetchAPIDataFile(url) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
const fetch = CL.nodeModules.nodeFetch
|
||||
/*
|
||||
This is how we call the API.
|
||||
*/
|
||||
fetch(url)
|
||||
.then((response) => {
|
||||
|
||||
if (response.status !== 200) {
|
||||
console.log('[ERROR] fetchAPIData -> then -> url =' + url)
|
||||
reject()
|
||||
return
|
||||
}
|
||||
getResponseBody()
|
||||
|
||||
function getResponseBody() {
|
||||
response.text().then(body => {
|
||||
resolve(body)
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('[ERROR] fetchAPIData -> url =' + url)
|
||||
reject()
|
||||
})
|
||||
}
|
||||
)
|
||||
return promise
|
||||
}
|
||||
}
|
||||
@@ -329,15 +329,22 @@ function newFoundationsFunctionLibraryUiObjectsFromNodes() {
|
||||
pathName = rawPath[i][0]
|
||||
pathType = rawPath[i][1]
|
||||
pathNode = UI.projects.foundations.spaces.designSpace.workspace.getHierarchyHeadsByCodeNameAndNodeType( pathName, pathType )
|
||||
|
||||
// If reference parent is workspace node grab node
|
||||
if (pathType === "Workspace") {
|
||||
pathNode = UI.projects.foundations.spaces.designSpace.workspace.workspaceNode
|
||||
}
|
||||
// If Hierarchy Head is not located within the workspace abort reconnection
|
||||
if (pathNode === undefined) {
|
||||
console.log("[WARN] Abort reconnection saved path head node not found in current workspace", node)
|
||||
return
|
||||
}
|
||||
continue
|
||||
} else { // Walk through children nodes and find the next node from saved path
|
||||
pathName = rawPath[i][0]
|
||||
pathType = rawPath[i][1]
|
||||
pathNode = getNextNodeFromPath(pathNode, pathName, pathType)
|
||||
|
||||
}
|
||||
}
|
||||
if (pathNode !== undefined ) {
|
||||
@@ -347,6 +354,7 @@ function newFoundationsFunctionLibraryUiObjectsFromNodes() {
|
||||
}
|
||||
|
||||
function getNextNodeFromPath(node, pathName, pathType) {
|
||||
console.log("pathNode", node)
|
||||
let schemaDocument = getSchemaDocument(node)
|
||||
let nextNode = undefined
|
||||
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
|
||||
|
||||
@@ -157,7 +157,10 @@ function newWorkspace() {
|
||||
let workspace = UI.projects.foundations.spaces.designSpace.workspace.workspaceNode
|
||||
|
||||
/* Validation if it is too early to save. */
|
||||
if (thisObject.isInitialized === false) { return }
|
||||
if (thisObject.isInitialized === false) {
|
||||
console.log('Workspace not saved because it has not been initialized. =')
|
||||
return
|
||||
}
|
||||
|
||||
/* Validation of 2 sessions opened at the same time. */
|
||||
let savedSessionTimestamp = window.localStorage.getItem('Session Timestamp')
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#cdd4d5;}.cls-3{fill:#e6eaea;}.cls-4{fill:#365558;}.cls-5{fill:#fd6a33;}.cls-6{fill:#e3493c;}.cls-7{fill:none;}.cls-8{fill:#0295aa;}.cls-9{fill:#4acfd9;}</style></defs><title>airdrop-program</title><g id="Layer_15" data-name="Layer 15"><path class="cls-1" d="M166.66,502.09A14,14,0,0,0,180,512h2.34A17.34,17.34,0,0,1,166.66,502.09Z"/><path class="cls-1" d="M182.38,376.58H180a14,14,0,0,0-13.38,9.9A17.35,17.35,0,0,1,182.38,376.58Z"/><path class="cls-2" d="M170.05,390.57V498a10,10,0,0,0,10,10h76V380.57H180A10,10,0,0,0,170.05,390.57Z"/><path class="cls-3" d="M332,508a10,10,0,0,0,10-10V390.57a10,10,0,0,0-10-10H256V508Z"/><path class="cls-1" d="M332,376.58h-3.33a17.17,17.17,0,0,1,17.32,17V495a17.18,17.18,0,0,1-17.32,17H332a14,14,0,0,0,14-14V390.57A14,14,0,0,0,332,376.58Z"/><path class="cls-4" d="M166.05,390.57a14.2,14.2,0,0,1,.61-4.09,16.66,16.66,0,0,0-1.6,7.08V495a16.66,16.66,0,0,0,1.6,7.08,14.08,14.08,0,0,1-.61-4.08Z"/><path class="cls-4" d="M180,508a10,10,0,0,1-10-10V390.57a10,10,0,0,1,10-10h76v-4H182.38a17.35,17.35,0,0,0-15.72,9.9,14.2,14.2,0,0,0-.61,4.09V498a14.08,14.08,0,0,0,.61,4.08A17.34,17.34,0,0,0,182.38,512H256v-4Z"/><path class="cls-4" d="M346,495V393.56a17.17,17.17,0,0,0-17.32-17H256v4h76a10,10,0,0,1,10,10V498a10,10,0,0,1-10,10H256v4h72.63A17.18,17.18,0,0,0,346,495Z"/><path class="cls-1" d="M256,399.13v96.26a48.13,48.13,0,0,0,0-96.26Z"/><path class="cls-3" d="M207.87,447.26A48.12,48.12,0,0,0,256,495.39V399.13A48.13,48.13,0,0,0,207.87,447.26Z"/><path class="cls-5" d="M266.32,449.52a30.19,30.19,0,0,1-3.87-9.4c.45-4-1-8.92-4.16-9.4a3.57,3.57,0,0,0-2.29.47v25.75a31.72,31.72,0,0,1,3.21.89c3.41,2.31,8.31,3.55,10.4,1.2S269.61,452.58,266.32,449.52Z"/><path class="cls-6" d="M251.45,438.24a29.62,29.62,0,0,1-6.69,8c-3.75,1.67-7.36,5.19-6.19,8s6.52,3.08,10.19,2a32.12,32.12,0,0,1,7.26.72V431.17C253.78,432.41,252,435.6,251.45,438.24Z"/><path class="cls-5" d="M262.82,414.38c5.19.2,7.24,10.3,6.4,17.95A101.36,101.36,0,0,0,276,451.08a7.72,7.72,0,0,0,3.29,3.16,40.75,40.75,0,0,1-3.5-20c3.3-8.76,1.83-20.59-3.12-23.35a11.49,11.49,0,0,0-15.19,4.61.76.76,0,0,0-.09.18A7.69,7.69,0,0,1,262.82,414.38Z"/><path class="cls-6" d="M233.46,436.11c-9.55,1.64-19.46,8.76-19.46,14.23a11.1,11.1,0,0,0,11.77,10.33h.15a7.56,7.56,0,0,1-3.61-4c-2.5-4,5.39-10.94,12.84-14.19,2.37-1,12.09-13,13.46-15a7.74,7.74,0,0,0,1.2-4.36A43.34,43.34,0,0,1,233.46,436.11Z"/><path class="cls-5" d="M282.81,465.52a2,2,0,0,0-.21-.3,7.16,7.16,0,0,1-1.61,5.11c-2.75,4-12.77.92-19.41-3.68q-2.76-.76-5.58-1.41v5.56c.22.15.45.28.68.43,6.28,7.17,17.61,12,22.56,9.08A10.48,10.48,0,0,0,282.81,465.52Z"/><path class="cls-6" d="M241.35,463a7.63,7.63,0,0,0-4.49,1.17A44,44,0,0,1,256,470.82v-5.57A112.68,112.68,0,0,0,241.35,463Z"/><path class="cls-7" d="M73.94,197.32l170.45,155L175.44,199.91C125.06,158.21,84.92,187.52,73.94,197.32Z"/><path class="cls-7" d="M336.66,199.69,267.61,352.34,437.77,197.59C383.41,155.17,341.58,194.68,336.66,199.69Z"/><path class="cls-8" d="M230.08,9.88C143.71,22.49,76.44,97.11,72.29,188.45c15.56-12,55-34.3,102.48.78C176.13,104.33,198.58,34.8,230.08,9.88Z"/><path class="cls-9" d="M337.22,188.67c15.34-12,54.87-34.67,102.52.37C435.85,97.43,368.48,22.51,281.92,9.88,313.35,34.75,335.77,104,337.22,188.67Z"/><path class="cls-9" d="M256,170.3h.94l.65,0,1.43,0,.81,0,1.31.05.88,0,1.25.07.94.06,1.22.08,1,.08,1.22.1,1,.1,1.22.12,1,.11,1.22.14,1,.13,1.23.17,1,.14,1.24.19,1.05.17,1.25.2,1.05.19,1.27.23,1.05.2,1.29.26,1.06.22,1.3.28L287,174l1.32.31,1.06.25,1.34.34,1.06.28,1.37.37,1,.29,1.39.4,1,.31,1.44.44,1,.32,1.51.49,1,.32,1.57.54.92.32,1.72.63.78.28c.7.26,1.39.53,2.09.81l.43.16,2.56,1,.1,0,2.44,1,.78.34,1.78.8,1,.45,1.59.74,1.07.52,1.52.74,1.12.57c.49.25,1,.49,1.48.75l1.17.61,1.44.76,1.2.66,1,.55C327.77,90.84,294.83,8,256,8h0Z"/><path class="cls-8" d="M184.72,188.82l.7-.39.71-.4,1.21-.66.73-.39c.36-.2.73-.39,1.1-.58l.92-.48,1.11-.56.73-.36,1.61-.78.76-.35c.51-.25,1-.49,1.58-.73l.79-.36,1.55-.68.73-.31,2-.84.76-.31,2-.8.64-.24,2-.75.72-.25c.78-.28,1.58-.56,2.4-.83l.72-.24,2.54-.82.37-.11,2.58-.77.65-.19,2.82-.76.63-.16c1-.26,2-.52,3.07-.76a140.84,140.84,0,0,1,32-3.67H256V8c-38.77,0-71.67,82.58-73.25,182l.35-.2.62-.37Z"/><path class="cls-4" d="M258,371.78l-.42.2Z"/><path class="cls-4" d="M257.3,372.07a3.17,3.17,0,0,1-.44.12A3.17,3.17,0,0,0,257.3,372.07Z"/><path class="cls-4" d="M256.66,372.23a3.68,3.68,0,0,1-.66.06A3.68,3.68,0,0,0,256.66,372.23Z"/><path class="cls-4" d="M253.88,371.68a4.19,4.19,0,0,1-.54-.4A4.19,4.19,0,0,0,253.88,371.68Z"/><path class="cls-4" d="M254.48,372a3.42,3.42,0,0,1-.43-.21A3.42,3.42,0,0,0,254.48,372Z"/><path class="cls-4" d="M255.14,372.19a3.17,3.17,0,0,1-.44-.12A3.17,3.17,0,0,0,255.14,372.19Z"/><path class="cls-4" d="M336.23,200.13l-.06.05a3.7,3.7,0,0,1-.46.42h0a3.07,3.07,0,0,1-.42.28l-.08,0L335,201l-.41.17-.18.06-.48.11-.12,0a4.29,4.29,0,0,1-.62,0h-.1a4.43,4.43,0,0,1-.51-.06l-.19,0a3.45,3.45,0,0,1-.43-.12l-.18-.07a5,5,0,0,1-.57-.28c-1-.62-2-Line truncated
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#365558;fill-rule:evenodd;}.cls-2{fill:#e6eaea;}.cls-3{fill:#fff;}</style></defs><title>github-program</title><path class="cls-1" d="M384,512H128A128,128,0,0,1,0,384V128A128,128,0,0,1,128,0H384A128,128,0,0,1,512,128V384A128,128,0,0,1,384,512"/><path class="cls-1" d="M240,144H384A72,72,0,0,0,391.36.37C388.91.23,386.49,0,384,0H128A128,128,0,0,0,0,128V384C0,251.45,107.45,144,240,144"/><path class="cls-1" d="M384,256A128,128,0,1,0,512,384V128A128,128,0,0,1,384,256"/><path class="cls-2" d="M94.22,185.82a176.16,176.16,0,0,0,91.51,231.72A16,16,0,0,0,208,402.81V376h-3.76a64,64,0,0,1-54.88-31.07l-1.25-2.07A14.11,14.11,0,0,0,136,336a8,8,0,0,1,0-16h0a32,32,0,0,1,25.59,12.79h0A48,48,0,0,0,200,352h8.67a48,48,0,0,1,13.39-25.94c1-1,2-1.95,3.11-2.85A1.82,1.82,0,0,0,224,320h0a80,80,0,0,1-63.91-128.12,77.29,77.29,0,0,1,.77-36.87l1.36-5.08a8,8,0,0,1,9.8-5.66l5.08,1.36a77.38,77.38,0,0,1,30.4,16.07A80.85,80.85,0,0,1,224,160h32V79.72A176.19,176.19,0,0,0,94.22,185.82Z"/><path class="cls-3" d="M325.93,94.3A175.57,175.57,0,0,0,256,79.72V160h32a81,81,0,0,1,16.51,1.7,77.32,77.32,0,0,1,30.4-16.07l5.08-1.36a8,8,0,0,1,9.79,5.66l1.36,5.08a77.12,77.12,0,0,1,.77,36.86A80,80,0,0,1,288,320h0a1.82,1.82,0,0,0-1.16,3.21c1.07.9,2.11,1.85,3.11,2.85A48,48,0,0,1,304,360s0,23.91.13,42.81a15.86,15.86,0,0,0,22.08,14.6,176.16,176.16,0,0,0-.28-323.11Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#365558;}.cls-2{fill:#f0353d;}.cls-3{fill:#fd6a33;}.cls-4{fill:#0295aa;}.cls-5{fill:#4acfd9;}.cls-6{fill:#e6eaea;}.cls-7{fill:#cdd4d5;}.cls-8{fill:#9baaab;}.cls-9{fill:#ff8c29;}.cls-10{fill:#fff;}</style></defs><title>influencer-program</title><g id="Layer_2" data-name="Layer 2"><polygon class="cls-1" points="408.9 342.47 408.9 243.3 342.9 243.3 342.9 258.31 393.89 258.31 393.89 342.47 408.9 342.47"/><rect class="cls-1" x="312.46" y="243.3" width="15.43" height="15.02"/><rect class="cls-1" x="312.46" y="180.22" width="15.75" height="15.02"/><polygon class="cls-1" points="382.01 122.49 349.13 180.22 343.22 180.22 343.22 195.24 357.86 195.24 395.06 129.92 382.01 122.49"/><rect class="cls-1" x="264.91" y="101.18" width="15.02" height="16.02"/><polygon class="cls-1" points="264.91 86.16 279.92 86.16 279.92 45.62 194.34 45.62 194.34 60.63 264.91 60.63 264.91 86.16"/><path class="cls-2" d="M126.54,15.12h-.07a28.51,28.51,0,0,0-20.29,8.48l-9.89,10L86,23.4a28.47,28.47,0,0,0-20.15-8.28h-.21A28.49,28.49,0,0,0,45.38,23.7a28.87,28.87,0,0,0,.31,40.72L68,86.91l69.59-69.59A28.62,28.62,0,0,0,126.54,15.12Z"/><path class="cls-3" d="M146.89,64.22a28.82,28.82,0,0,0-9.31-46.9L68,86.91l28.24,28.48Z"/><path class="cls-3" d="M157.4,12.86a44.43,44.43,0,0,0-8.65-6.71l-5.53,5.53a36.32,36.32,0,0,1,9,57.82L99.23,123l-3,3L62.68,92.22l-5.31,5.31,38.88,39.2L157.56,74.8a43.53,43.53,0,0,0,12.72-32h0A43.72,43.72,0,0,0,157.4,12.86Z"/><path class="cls-2" d="M40.41,69.76A36.27,36.27,0,0,1,91.28,18.05l5,4.9,4.61-4.65a36.22,36.22,0,0,1,42.37-6.62l5.53-5.53A43.46,43.46,0,0,0,126.54.1h-.11A43.41,43.41,0,0,0,96.19,12.36,43.39,43.39,0,0,0,65.85.1h-.32A43.45,43.45,0,0,0,34.68,13.17a43.89,43.89,0,0,0,.4,61.88L57.37,97.53l5.31-5.31Z"/><path class="cls-3" d="M146.8,23.5a28.82,28.82,0,0,1,.09,40.72L96.23,115.39,68,86.91l-5.31,5.31,33.56,33.84,3-3,53-53.54a36.33,36.33,0,0,0-9-57.82l-5.64,5.64A28.59,28.59,0,0,1,146.8,23.5Z"/><path class="cls-2" d="M100.85,18.3,96.24,23l-5-4.9A36.27,36.27,0,0,0,40.41,69.76L62.68,92.22,68,86.91,45.69,64.42a28.87,28.87,0,0,1-.31-40.72,28.49,28.49,0,0,1,20.26-8.58h.21A28.47,28.47,0,0,1,86,23.4L96.29,33.56l9.89-10a28.51,28.51,0,0,1,20.29-8.48h.07a28.62,28.62,0,0,1,11,2.2l5.64-5.64A36.22,36.22,0,0,0,100.85,18.3Z"/><polygon class="cls-4" points="415.03 86.55 435.05 66.53 440.36 71.84 486 26.2 346.49 70.95 407.91 104.29 407.91 104.29 420.34 91.86 415.03 86.55"/><polygon class="cls-5" points="486 26.2 486 26.2 440.36 71.84 445.67 77.15 425.65 97.17 420.34 91.86 407.91 104.29 441.25 165.71 486 26.2"/><rect class="cls-6" x="418.85" y="80.75" width="28.31" height="7.51" transform="translate(67.07 330.93) rotate(-45)"/><rect class="cls-7" x="413.54" y="75.44" width="28.31" height="7.51" transform="translate(69.27 325.62) rotate(-45)"/><polygon class="cls-5" points="497.61 14.59 497.61 14.59 443.04 184.73 402.38 109.83 402.37 109.83 396.84 115.36 396.84 115.36 444.82 203.75 509.21 2.99 497.61 14.59"/><polygon class="cls-4" points="327.47 69.16 497.61 14.59 509.21 2.99 509.21 2.98 308.45 67.38 396.84 115.36 402.37 109.83 327.47 69.16"/><polygon class="cls-4" points="402.37 109.83 407.91 104.29 407.91 104.29 346.49 70.95 486 26.2 497.61 14.59 327.47 69.16 402.37 109.83"/><polygon class="cls-5" points="486 26.2 441.25 165.71 407.91 104.29 402.37 109.83 402.38 109.83 443.04 184.73 497.61 14.59 497.61 14.59 486 26.2 486 26.2"/><rect class="cls-6" x="87.47" y="55.42" width="28.31" height="7.51" transform="translate(-12.08 89.19) rotate(-45)"/><rect class="cls-7" x="82.16" y="50.11" width="28.31" height="7.51" transform="translate(-9.88 83.88) rotate(-45)"/><path class="cls-4" d="M15.65,241.94v11.82A10.24,10.24,0,0,0,25.88,264H42V231.7H25.88A10.24,10.24,0,0,0,15.65,241.94Z"/><polygon class="cls-4" points="280.39 160.74 259.93 160.74 259.93 188.73 280.39 163.92 280.39 160.74"/><polygon class="cls-5" points="252.42 207.33 252.42 222.34 259.93 222.34 259.93 334.96 280.39 334.96 280.39 163.92 259.93 188.73 259.93 207.33 252.42 207.33"/><polygon class="cls-4" points="126.83 320.41 126.83 350.06 151.29 320.41 126.83 320.41"/><path class="cls-5" d="M182.78,443.77V320.41H151.29l-24.46,29.65v93.71Zm-34.9-102.9h15v15h-15Zm15,30V411h-15V370.9Z"/><polygon class="cls-5" points="244.91 207.33 244.91 206.93 163.68 305.39 197.79 305.39 217.74 305.39 244.91 326.94 244.91 222.34 252.41 222.34 252.41 207.33 244.91 207.33"/><path class="cls-4" d="M244.91,168.76l-27.17,21.55H85a28,28,0,0,0-28,28v59.14a28,28,0,0,0,28,28h78.66l81.23-98.46ZM150.07,286.65H82.65v-15h67.42Zm0-31H82.65v-15h67.42Zm0-31H82.65v-15h67.42Z"/><rect class="cls-5" x="250.37" y="214.83" height="7.51"/><polygon class="cls-4" points="154.8 486.07 175.27 458.79 134.34 458.79 154.8 486.07"/><rect class="cls-6" x="147.88" y="370.9" width="15.02" height="40.04"/><rect class="cls-6" x="147.88" y="340.87" width="15.02" height="15.02"/><rect class="cls-8" x="82.65" y="209.63" width="67.42" height="15.02"/><rect class="clLine truncated
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#faab18;}.cls-2{fill:none;}.cls-3{fill:#0295aa;}.cls-4{fill:#e6eaea;}.cls-5{fill:#f0353d;}.cls-6{fill:#ff8c29;}.cls-7{fill:#9baaab;}.cls-8{fill:#4acfd9;}.cls-9{fill:#fd6a33;}.cls-10{fill:#ffd1a9;}</style></defs><title>mentorship-program</title><path class="cls-1" d="M250.08,381a50.32,50.32,0,0,0,5.92.36h.29V381Z"/><path class="cls-2" d="M256,488.57l-27.22,20.76a13,13,0,0,1-7.87,2.67h35.21l0-23.31Z"/><path class="cls-3" d="M171.71,376.86a18.91,18.91,0,0,1-15.41-12.8,18.49,18.49,0,0,1,4.84-19.27,3.52,3.52,0,0,0-.6-5.57,19,19,0,0,1-6.14-6.15H132.89a7.67,7.67,0,0,1-7.72,7.62H88.08A13.88,13.88,0,0,1,74.33,329a28.16,28.16,0,0,0-23.86-23.51A13.79,13.79,0,0,1,38.64,292V86.76A13.79,13.79,0,0,1,50.47,73.22,28.16,28.16,0,0,0,74.33,49.71,13.87,13.87,0,0,1,88.07,38.06H256.73l0-30.45H20.6A12.8,12.8,0,0,0,7.73,20.3V358.45A12.8,12.8,0,0,0,20.6,371.13H134.81a7.67,7.67,0,0,1,7.73,7.61h31.87c0-.05,0-.1-.08-.14A3.54,3.54,0,0,0,171.71,376.86Z"/><path class="cls-4" d="M151.75,321.36a18.71,18.71,0,0,1,12.37-15.67,3.52,3.52,0,0,0,2.19-2.25,3.46,3.46,0,0,0-.43-3.08,18.46,18.46,0,0,1-.67-19.84A19.05,19.05,0,0,1,183,271.16a3.55,3.55,0,0,0,2.93-1.17,3.47,3.47,0,0,0,.88-3,18.54,18.54,0,0,1,7.58-18.39,19.19,19.19,0,0,1,20.1-1.43,3.59,3.59,0,0,0,3.16.1,3.53,3.53,0,0,0,2-2.38,18.84,18.84,0,0,1,14.53-13.76,19.13,19.13,0,0,1,18.95,6.75,3.58,3.58,0,0,0,2.84,1.36l.47,0,.07-51.88H99.41a7.61,7.61,0,1,1,0-15.22H256.56l0-22.27H99.41a7.61,7.61,0,1,1,0-15.22h157.2l0-28H153.06a7.61,7.61,0,1,1,0-15.22h103.6l0-38.1H89.4A43.63,43.63,0,0,1,54.08,88.07V290.68A43.63,43.63,0,0,1,89.4,325.46h35.77a7.66,7.66,0,0,1,7.72,7.61H154.4A18.47,18.47,0,0,1,151.75,321.36Z"/><path class="cls-5" d="M238.89,424.93a3.65,3.65,0,0,0-5.56-1.16,19.18,19.18,0,0,1-9.86,4.22v66.14l24.65-18.8a13,13,0,0,1,7.88-2.65h.17l.05-37.28H256A19,19,0,0,1,238.89,424.93Z"/><path class="cls-6" d="M211.21,378.74h-21a18.48,18.48,0,0,1-1.28,8.62,3.46,3.46,0,0,0,.67,3.71,3.57,3.57,0,0,0,3.68,1.05A19.16,19.16,0,0,1,209.65,395a18.63,18.63,0,0,1,6.09,7.33V382.68C214.17,381.44,212.65,380.12,211.21,378.74Z"/><path class="cls-6" d="M191.49,333.07H175.24a18.51,18.51,0,0,1-3.32,22.63,3.44,3.44,0,0,0-.92,3.66,3.52,3.52,0,0,0,2.93,2.43,19,19,0,0,1,13.78,9.2,18.52,18.52,0,0,1,2.48,7.75h21A62.87,62.87,0,0,1,191.49,333.07Z"/><path class="cls-6" d="M256,269.52l.43,0,0-15.09-.45,0a19,19,0,0,1-15-7.17,3.59,3.59,0,0,0-3.6-1.28,3.53,3.53,0,0,0-2.76,2.62,18.77,18.77,0,0,1-10.73,12.54,19.2,19.2,0,0,1-16.64-.54,3.58,3.58,0,0,0-3.82.27,3.46,3.46,0,0,0-1.44,3.5,18.48,18.48,0,0,1-4.63,15.76A19.08,19.08,0,0,1,182,286.35a3.55,3.55,0,0,0-3.38,1.78,3.42,3.42,0,0,0,.13,3.77A18.47,18.47,0,0,1,181,308.15,18.82,18.82,0,0,1,169.46,320a3.54,3.54,0,0,0-.67,6.37,18.76,18.76,0,0,1,6.45,6.72h16.25C191.49,298,220.43,269.52,256,269.52Z"/><path class="cls-6" d="M256,396.62a64.84,64.84,0,0,1-40.26-13.94v19.65a18.44,18.44,0,0,1,1.76,7.13,3.49,3.49,0,0,0,2.15,3.13,3.58,3.58,0,0,0,3.79-.52,19.15,19.15,0,0,1,12.16-4.35,20.29,20.29,0,0,1,4,.41,18.94,18.94,0,0,1,13.14,10.08,3.55,3.55,0,0,0,3.25,2h.24l0-23.57Z"/><path class="cls-5" d="M256.29,378.74H240a49.76,49.76,0,0,0,10.1,2.3h6.21Z"/><path class="cls-5" d="M256.35,333.07H206.94a48.46,48.46,0,0,0,33,45.67h16.31Z"/><path class="cls-5" d="M256.41,284.76H256c-27.05,0-49.06,21.67-49.06,48.32h49.41Z"/><path class="cls-3" d="M0,20.3V358.45a20.45,20.45,0,0,0,20.6,20.29H142.54a7.67,7.67,0,0,0-7.73-7.61H20.6A12.8,12.8,0,0,1,7.73,358.45V20.3A12.8,12.8,0,0,1,20.6,7.61H256.77V0H20.6A20.46,20.46,0,0,0,0,20.3Z"/><path class="cls-3" d="M74.33,49.71A28.16,28.16,0,0,1,50.47,73.22,13.79,13.79,0,0,0,38.64,86.76V292a13.79,13.79,0,0,0,11.83,13.54A28.16,28.16,0,0,1,74.33,329a13.88,13.88,0,0,0,13.75,11.66h37.09a7.67,7.67,0,0,0,7.72-7.62H88.07A6.1,6.1,0,0,1,82,327.94a35.77,35.77,0,0,0-30.41-30,6.07,6.07,0,0,1-5.21-6V86.76a6.07,6.07,0,0,1,5.21-6A35.76,35.76,0,0,0,82,50.81a6.1,6.1,0,0,1,6.09-5.14H256.72V38.06H88.07A13.87,13.87,0,0,0,74.33,49.71Z"/><path class="cls-4" d="M125.17,325.46H89.4a43.63,43.63,0,0,0-35.32-34.78V88.07A43.63,43.63,0,0,0,89.4,53.28H256.71V45.67H88.07A6.1,6.1,0,0,0,82,50.81a35.76,35.76,0,0,1-30.41,30,6.07,6.07,0,0,0-5.21,6V292a6.07,6.07,0,0,0,5.21,6,35.77,35.77,0,0,1,30.41,30,6.1,6.1,0,0,0,6.09,5.13h44.82A7.66,7.66,0,0,0,125.17,325.46Z"/><path class="cls-3" d="M226.77,381c-1.21-.72-2.39-1.49-3.54-2.3h-12c1.44,1.38,3,2.7,4.53,3.94V381Z"/><path class="cls-3" d="M199.22,333.07h-7.73a62.87,62.87,0,0,0,19.72,45.67h12A55.61,55.61,0,0,1,199.22,333.07Z"/><path class="cls-3" d="M256,277.14h.42v-7.61l-.43,0c-35.57,0-64.51,28.51-64.51,63.55h7.73C199.22,302.18,224.64,277.14,256,277.14Z"/><path class="cls-3" d="M256,389a57.17,57.17,0,0,1-29.23-8h-11v1.64A64.84,64.84,0,0,0,256,396.62h.27V389Z"/><path class="cls-3" d="M240,378.74H223.23c1.15.81,2.33,1.58,3.54,2.3h23.31A49.76,49.76,0,0,1,240,378.74Z"/><path class="cls-3" d="M206.94,333.07h-7.72a55.61,55.61,0,0,0,24,45.67H240A48.46,48.46,0,0,1,2Line truncated
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:none;}.cls-2{fill:#4acfd9;}.cls-3{fill:#fd6a33;}.cls-4{fill:#cdd4d5;}.cls-5{fill:#afafaf;}.cls-6{fill:#ffb69f;}.cls-7{fill:#f0353d;}.cls-8{fill:#0295aa;}.cls-9{fill:#365558;}.cls-10{fill:#ffd1a9;}.cls-11{fill:#ff8c29;}.cls-12{fill:#9baaab;}.cls-13{fill:#e6eaea;}</style></defs><title>referral-program</title><path class="cls-1" d="M470.73,29.38h-.44l.44.4Z"/><path class="cls-2" d="M231.27,258.1c0-62.69-50.38-113.53-112.59-113.55h0v51.17h26.23a11.58,11.58,0,0,0,11.34-9.47,5.37,5.37,0,0,1,.84-2,5.28,5.28,0,0,1,7.33-1.44l.06,0,8.89,6.13a29.64,29.64,0,0,1,4.14,3.44,30.58,30.58,0,0,1,.29,43l-4.59,4.71V254a19.61,19.61,0,1,1-.36,39.22h-1.47a54.43,54.43,0,0,1-52.7,40.88v11.45a86.93,86.93,0,0,0,38.76-9.15,5.3,5.3,0,0,1,7.15,2.26l0,0a5.37,5.37,0,0,1-2.28,7.22l-.15.08a97.59,97.59,0,0,1-43.5,10.27v15.28C180.84,371.54,231.25,320.76,231.27,258.1Zm-43.65,69.43c-2.13,2.14-4.36,4.19-6.65,6.11a5.31,5.31,0,0,1-7.47-.66l0,0a5.39,5.39,0,0,1,.69-7.55h0c2-1.71,4-3.55,5.93-5.45a5.29,5.29,0,0,1,7.48.09l0,0A5.39,5.39,0,0,1,187.62,327.53Z"/><path class="cls-3" d="M16.63,306.2a112.59,112.59,0,0,0,102,65.36h.07V356.28h0c-53.88,0-97.54-44-97.51-98.35a98.68,98.68,0,0,1,28.53-69.42,5.28,5.28,0,0,1,7.47,0l.05,0a5.38,5.38,0,0,1,0,7.58h0a88,88,0,0,0,0,123.91,86.53,86.53,0,0,0,61.37,25.61h0v-11.5a54.55,54.55,0,0,1-52.59-40.88H64.58A19.62,19.62,0,0,1,64.22,254V223.57a27.78,27.78,0,0,1,27.63-27.85h26.81V144.55C56.46,144.53,6,195.32,6,258c0,2.91.13,5.89.34,8.85v.5a5.34,5.34,0,0,1-4.73,5.46,118.69,118.69,0,0,0,8.11,30.76A5.42,5.42,0,0,1,16.63,306.2Z"/><path class="cls-4" d="M170.21,227.85a18.9,18.9,0,0,0,2.2-2.68,19.78,19.78,0,0,0-5.06-27.37L164,195.47a22.18,22.18,0,0,1-19.08,11H118.66v26.1h47Z"/><path class="cls-5" d="M91.85,206.44a17.07,17.07,0,0,0-17,17.12v9h43.8v-26.1Z"/><path class="cls-6" d="M64.21,264.71a8.9,8.9,0,0,0,.1,17.79c-.06-1.08-.1-2.16-.1-3.26Z"/><path class="cls-6" d="M181.65,273.6a8.88,8.88,0,0,0-8.47-8.89v14.53c0,1.09,0,2.19-.1,3.26A8.89,8.89,0,0,0,181.65,273.6Z"/><path class="cls-6" d="M74.85,279.24a44,44,0,0,0,43.81,44.18V310.47A20.59,20.59,0,0,1,99.4,297a5.34,5.34,0,0,1,10-3.73h0a10,10,0,0,0,5.81,5.84,9.78,9.78,0,0,0,3.47.63V284.8a5.32,5.32,0,0,1-5.28-5.35v-13.3a5.32,5.32,0,0,1,5.28-5.35V243.27H74.85Zm15.65-16a5.32,5.32,0,0,1,10.64,0h0v2.91a5.32,5.32,0,0,1-10.64,0h0Z"/><path class="cls-6" d="M118.69,260.79a5.34,5.34,0,0,1,5.32,5.36h0v13.3a5.34,5.34,0,0,1-5.32,5.36h0v14.95a10,10,0,0,0,9.38-6.5A5.33,5.33,0,0,1,138.36,296a5.56,5.56,0,0,1-.36,1,20.72,20.72,0,0,1-12.07,12.14,20.06,20.06,0,0,1-7.27,1.3v12.95h0a44,44,0,0,0,43.85-44.15v-36H118.66V260.8Zm17.56,2.45a5.32,5.32,0,0,1,10.64,0h0v2.91a5.32,5.32,0,0,1-10.64,0h0Z"/><path class="cls-7" d="M118.64,345.56A86.56,86.56,0,0,1,57.27,320a88.05,88.05,0,0,1-.09-123.86h0a5.38,5.38,0,0,0,0-7.58,5.28,5.28,0,0,0-7.47-.05l-.05.05A98.68,98.68,0,0,0,21.13,258c0,54.3,43.63,98.33,97.51,98.35h0Z"/><path class="cls-8" d="M180.1,320c-1.89,1.9-3.89,3.74-5.93,5.45h0a5.39,5.39,0,0,0-.69,7.55,5.29,5.29,0,0,0,7.46.71l0,0c2.29-1.92,4.52-4,6.65-6.11a5.39,5.39,0,0,0,0-7.45,5.29,5.29,0,0,0-7.48-.17Z"/><path class="cls-8" d="M162.31,345.93a5.37,5.37,0,0,0,2.28-7.22,5.3,5.3,0,0,0-7.13-2.32l0,0a86.93,86.93,0,0,1-38.76,9.15v10.72A97.47,97.47,0,0,0,162.16,346Z"/><path class="cls-9" d="M138,297a5.35,5.35,0,0,0-10-3.78h0a10,10,0,0,1-9.38,6.5v10.72a20.06,20.06,0,0,0,7.27-1.3A20.7,20.7,0,0,0,138,297Z"/><path class="cls-9" d="M115.19,299.12a10,10,0,0,1-5.81-5.84,5.34,5.34,0,0,0-10,3.73h0a20.59,20.59,0,0,0,19.26,13.46V299.75A9.89,9.89,0,0,1,115.19,299.12Z"/><path class="cls-9" d="M70.29,287.86H64.57a14.26,14.26,0,0,1,0-28.51h5V237.92h0V223.57a22.42,22.42,0,0,1,22.32-22.49h26.82v-5.36H91.85a27.78,27.78,0,0,0-27.63,27.85V254a19.61,19.61,0,1,0,.36,39.22h1.49a54.55,54.55,0,0,0,52.59,40.88v-5.38A49.26,49.26,0,0,1,70.29,287.86Z"/><path class="cls-9" d="M132.6,332.29a54.67,54.67,0,0,0,38.76-39.06h1.47a19.61,19.61,0,1,0,.36-39.22V240.1l4.59-4.71a30.58,30.58,0,0,0-.29-43,29.64,29.64,0,0,0-4.14-3.44l-8.89-6.13a5.28,5.28,0,0,0-7.35,1.34l0,.06a5.37,5.37,0,0,0-.84,2,11.58,11.58,0,0,1-11.34,9.47H118.66v5.36h26.23a16.93,16.93,0,0,0,16.58-13.83l8.89,6.13a25.16,25.16,0,0,1,6.44,34.81,24.86,24.86,0,0,1-2.8,3.42l-6.15,6.31v21.43h5a14.26,14.26,0,0,1,0,28.51h-5.73A49.33,49.33,0,0,1,127.27,328a47.76,47.76,0,0,1-8.61.75v5.38A53.79,53.79,0,0,0,132.6,332.29Z"/><path class="cls-9" d="M144.89,206.44a22.18,22.18,0,0,0,19.08-11l3.38,2.33a19.78,19.78,0,0,1,5.06,27.37,18.9,18.9,0,0,1-2.2,2.68l-4.58,4.69h-47v5.37h49.19l6.15-6.31a24.86,24.86,0,0,0,2.8-3.42,25.16,25.16,0,0,0-6.44-34.81l-8.89-6.13A16.93,16.93,0,0,1,144.86,201h-26.2v5.36Z"/><path class="cls-9" d="M69.52,223.57v14.34h49.14v-5.37H74.86v-9a17.07,17.07,0,0,1,17-17.12h26.81v-5.36H91.84A22.42,22.42,0,0,0,69.52,223.57Z"/><path class="cls-9" d="M118.66,243.27h43.88v36a44,44,0,0,1-43.82,44.18h0v5.31a47.76,47.76,0,0,0,8.61-.75,49.32,49.32,0,0,0,39.81-40.12h5.73a14.26,14.26,0,0,Line truncated
|
||||
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#fd6a33;}.cls-2{fill:#ff8c29;}.cls-3{fill:#ffb300;}.cls-4{fill:#ffa000;}.cls-5{fill:#f0353d;}.cls-6{fill:#e6eaea;}.cls-7{fill:#fff;}.cls-8{fill:#e3493c;}.cls-9{fill:#ffd1a9;}</style></defs><title>staking-program</title><g id="Layer_16" data-name="Layer 16"><path class="cls-1" d="M276.53,17a7.5,7.5,0,0,0-13,7.5l5.72,9.9a7.5,7.5,0,1,0,13-7.5Z"/><path class="cls-1" d="M246.81,56.89l-9.9-5.71a7.5,7.5,0,0,0-7.5,13l9.9,5.71a7.39,7.39,0,0,0,3.75,1,7.5,7.5,0,0,0,3.75-14Z"/><path class="cls-1" d="M231.12,100.57H219.68a7.5,7.5,0,0,0,0,15h11.44a7.5,7.5,0,0,0,0-15Z"/><path class="cls-2" d="M421.2,100.57H409.77a7.5,7.5,0,0,0,0,15H421.2a7.5,7.5,0,0,0,0-15Z"/><path class="cls-2" d="M414.23,54A7.51,7.51,0,0,0,404,51.21l-9.9,5.72a7.5,7.5,0,0,0,7.5,13l9.9-5.72A7.5,7.5,0,0,0,414.23,54Z"/><path class="cls-2" d="M374.63,14.33a7.48,7.48,0,0,0-10.24,2.74L358.67,27a7.5,7.5,0,1,0,13,7.5l5.72-9.9a7.49,7.49,0,0,0-2.75-10.24Z"/><path class="cls-2" d="M454.45,182.06H192.5a8.1,8.1,0,0,1-8.1-8.1V142.78a8.1,8.1,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1V174A8.1,8.1,0,0,1,454.45,182.06Z"/><path class="cls-2" d="M454.45,134.67h-30.9a8.1,8.1,0,0,1,8.1,8.1V174a8.1,8.1,0,0,1-8.1,8.1h30.9a8.1,8.1,0,0,0,8.1-8.1V142.77A8.1,8.1,0,0,0,454.45,134.67Z"/><rect class="cls-1" x="238.34" y="137.39" width="8.17" height="19.4"/><rect class="cls-1" x="304.72" y="137.39" width="8.17" height="19.4"/><rect class="cls-1" x="335.72" y="137.39" width="8.17" height="19.4"/><rect class="cls-1" x="271.06" y="137.39" width="8.17" height="19.4"/><rect class="cls-1" x="400.13" y="137.39" width="8.17" height="19.4"/><rect class="cls-1" x="369.49" y="137.39" width="8.17" height="19.4"/><path class="cls-1" d="M485.36,227.4h-262a8.09,8.09,0,0,1-8.1-8.1V188.12a8.09,8.09,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1V219.3A8.1,8.1,0,0,1,485.36,227.4Z"/><path class="cls-1" d="M485.36,180H454.45a8.1,8.1,0,0,1,8.1,8.1V219.3a8.1,8.1,0,0,1-8.1,8.1h30.91a8.1,8.1,0,0,0,8.1-8.1V188.12A8.1,8.1,0,0,0,485.36,180Z"/><rect class="cls-2" x="251.67" y="178.61" width="9.74" height="19.4"/><rect class="cls-2" x="330.82" y="178.61" width="9.74" height="19.4"/><rect class="cls-2" x="367.79" y="178.61" width="9.74" height="19.4"/><rect class="cls-2" x="290.69" y="178.61" width="9.74" height="19.4"/><rect class="cls-2" x="444.58" y="178.61" width="9.74" height="19.4"/><rect class="cls-2" x="408.05" y="178.61" width="9.74" height="19.4"/><path class="cls-2" d="M503.9,274.79H242a8.1,8.1,0,0,1-8.1-8.1V235.5a8.1,8.1,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1v31.19A8.1,8.1,0,0,1,503.9,274.79Z"/><path class="cls-2" d="M503.9,227.4H473a8.11,8.11,0,0,1,8.11,8.1v31.19a8.1,8.1,0,0,1-8.11,8.1H503.9a8.1,8.1,0,0,0,8.1-8.1V235.5A8.1,8.1,0,0,0,503.9,227.4Z"/><rect class="cls-1" x="290.59" y="224.25" width="8.17" height="19.4"/><rect class="cls-1" x="356.98" y="224.25" width="8.17" height="19.4"/><rect class="cls-1" x="387.98" y="224.25" width="8.17" height="19.4"/><rect class="cls-1" x="323.32" y="224.25" width="8.17" height="19.4"/><rect class="cls-1" x="452.38" y="224.25" width="8.17" height="19.4"/><rect class="cls-1" x="421.74" y="224.25" width="8.17" height="19.4"/><path class="cls-1" d="M503.9,322.18H242a8.1,8.1,0,0,1-8.1-8.1V282.89a8.1,8.1,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1v31.19A8.1,8.1,0,0,1,503.9,322.18Z"/><path class="cls-1" d="M503.9,274.79H473a8.11,8.11,0,0,1,8.11,8.1v31.19a8.11,8.11,0,0,1-8.11,8.1H503.9a8.1,8.1,0,0,0,8.1-8.1V282.89A8.1,8.1,0,0,0,503.9,274.79Z"/><rect class="cls-2" x="290.59" y="274.44" width="8.17" height="19.4"/><rect class="cls-2" x="356.98" y="274.44" width="8.17" height="19.4"/><rect class="cls-2" x="387.98" y="274.44" width="8.17" height="19.4"/><rect class="cls-2" x="323.32" y="274.44" width="8.17" height="19.4"/><rect class="cls-2" x="452.38" y="274.44" width="8.17" height="19.4"/><rect class="cls-2" x="421.74" y="274.44" width="8.17" height="19.4"/><path class="cls-2" d="M503.9,369.57H242a8.1,8.1,0,0,1-8.1-8.1V330.28a8.1,8.1,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1v31.19A8.1,8.1,0,0,1,503.9,369.57Z"/><path class="cls-2" d="M503.9,322.18H473a8.11,8.11,0,0,1,8.11,8.1v31.19a8.11,8.11,0,0,1-8.11,8.1H503.9a8.1,8.1,0,0,0,8.1-8.1V330.28A8.1,8.1,0,0,0,503.9,322.18Z"/><rect class="cls-1" x="290.59" y="322.18" width="8.17" height="19.4"/><rect class="cls-1" x="356.98" y="322.18" width="8.17" height="19.4"/><rect class="cls-1" x="387.98" y="322.18" width="8.17" height="19.4"/><rect class="cls-1" x="323.32" y="322.18" width="8.17" height="19.4"/><rect class="cls-1" x="452.38" y="322.18" width="8.17" height="19.4"/><rect class="cls-1" x="421.74" y="322.18" width="8.17" height="19.4"/><path class="cls-1" d="M503.9,417H242a8.1,8.1,0,0,1-8.1-8.1V377.67a8.1,8.1,0,0,1,8.1-8.1h262a8.1,8.1,0,0,1,8.1,8.1v31.19A8.1,8.1,0,0,1,503.9,417Z"/><path class="cls-1" d="M503.9,369.57H473a8.11,8.11,0,0,1,8.11,8.1v31.19A8.11,8.11,0,0,1,473,417H503.9a8.1,8.1,0,0,0,8.1-8.1V377.67A8.1,8.1,0,0,0,503.9,369.57Z"/><rect class="cls-2" Line truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#f0353d;}.cls-2{fill:#fd6a33;}.cls-3{fill:#0295aa;}.cls-4{fill:#4acfd9;}.cls-5{fill:#9baaab;}.cls-6{fill:#ffd1a9;}.cls-7{fill:#365558;}.cls-8{fill:#cdd4d5;}</style></defs><title>tokens-awarded</title><path class="cls-1" d="M64.12,502.44H22.92A15.41,15.41,0,0,1,7.5,487V366.63a15.41,15.41,0,0,1,15.42-15.41h41.2a15.41,15.41,0,0,1,15.41,15.41V487A15.41,15.41,0,0,1,64.12,502.44Z"/><path class="cls-2" d="M79.52,366.63V487a15.41,15.41,0,0,1-15.41,15.41H44.23A15.41,15.41,0,0,0,59.64,487V366.63a15.41,15.41,0,0,0-15.41-15.41H64.11A15.41,15.41,0,0,1,79.52,366.63Z"/><path class="cls-3" d="M215.8,9.56A14.25,14.25,0,0,0,202.2,28c11.27,37,33.23,47.69,33.23,47.69h40.81V9.56Z"/><path class="cls-4" d="M350.29,28a14.26,14.26,0,0,0-13.6-18.45H276.24V75.7h40.82S339,65,350.29,28Z"/><path class="cls-3" d="M235.34,108.53l-48.17,29.86a72.66,72.66,0,0,0-34.79,61.66v137.4a13.64,13.64,0,0,1-13.63,13.64,18.31,18.31,0,0,0-18.31,18.31v35a18.31,18.31,0,0,0,18.31,18.31H276.24V108.53Z"/><path class="cls-4" d="M413.74,351.09h0a13.64,13.64,0,0,1-13.64-13.64V200.05a72.65,72.65,0,0,0-34.78-61.66l-48.18-29.86h-40.9V422.72h137.5a18.31,18.31,0,0,0,18.31-18.31v-35A18.31,18.31,0,0,0,413.74,351.09Z"/><path class="cls-5" d="M296.17,75.7h20.89v32.83H296.17Z"/><path class="cls-6" d="M499.68,391.21a30.16,30.16,0,0,0-37.3-11.31L324.07,425.58l-.25,0a23.93,23.93,0,0,0-4.51-46.39l-75.89-14.93c-10.12-2-45-9.54-51.91-9.09-14.14.9-26.8,11.3-37.71,19-24.53,17.4-49.16,12.21-74.27,3.7v92.53L140,466.89A87.69,87.69,0,0,1,177.82,472l57.9,21.33c39.6,14.58,74.44-2.45,111.21-14.84,46.59-15.69,94.3-27.81,140.77-43.87a30.15,30.15,0,0,0,12-43.38Z"/><path class="cls-7" d="M252.16,296.46A7.51,7.51,0,0,0,243.94,309c9.42,6.16,15.86,8,24.14,8.5v7.85a7.51,7.51,0,1,0,15,0v-8.46c16.54-3.29,26.21-17,28.36-29.72,2.76-16.46-5.85-30.76-21.93-36.45-2.11-.75-4.28-1.53-6.43-2.35V213.76a22.31,22.31,0,0,1,8.84,4.28A7.5,7.5,0,0,0,302.05,207a38.24,38.24,0,0,0-19-8.49v-7a7.51,7.51,0,0,0-15,0v7.59c-1.07.24-2.15.51-3.25.84-10.6,3.19-18.52,12.26-20.67,23.66-2,10.41,1.37,20.44,8.71,26.19a70.58,70.58,0,0,0,15.21,8.72v44c-5.61-.43-9.53-1.84-15.92-6Zm10-58.53c-2.91-2.28-4.14-6.72-3.22-11.6.82-4.33,3.65-9.53,9.17-11.69v27.11A42.76,42.76,0,0,1,262.13,237.93Zm22.39,27c13.54,4.79,12.7,16.37,12.12,19.81a21.57,21.57,0,0,1-13.55,16.6V264.38Z"/><rect class="cls-5" x="235.43" y="75.7" width="40.82" height="32.83"/><rect class="cls-8" x="276.25" y="75.7" width="40.81" height="32.83"/></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#0295aa;}.cls-2{fill:#365558;}.cls-3{fill:#cdd4d5;}.cls-4{fill:#ff8c29;}.cls-5{fill:#fd6a33;}.cls-6{fill:#4acfd9;}</style></defs><title>tokens-bonus</title><g id="Bonus-Budget-Finance-Income-Monney_Bag" data-name="Bonus-Budget-Finance-Income-Monney Bag"><path class="cls-1" d="M376,401.28A25,25,0,0,1,350.64,424H49.36A25,25,0,0,1,24,401.28a23.89,23.89,0,0,1,10-20.72A32,32,0,0,0,48,355V264A112,112,0,0,1,160,152h80A112,112,0,0,1,352,264v91a32,32,0,0,0,14,25.52A23.89,23.89,0,0,1,376,401.28Z"/><circle class="cls-2" cx="160" cy="296" r="64"/><path class="cls-2" d="M208,408a16,16,0,0,1,16,16H96a16,16,0,0,1,16-16,16,16,0,0,1-16-16V376a16,16,0,0,1,16-16h96a16,16,0,0,1,16,16v16A16,16,0,0,1,208,408Z"/><circle class="cls-3" cx="144" cy="280" r="64"/><path class="cls-4" d="M192,392a16,16,0,0,1,16,16v16a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16V408a16,16,0,0,1,16-16Z"/><path class="cls-5" d="M192,344a16,16,0,0,1,16,16v16a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16V360a16,16,0,0,1,16-16Z"/><path class="cls-5" d="M192,440a16,16,0,0,1,16,16v16a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16V456a16,16,0,0,1,16-16Z"/><path class="cls-2" d="M248,136a16.13,16.13,0,0,1-16,16H168a16,16,0,0,1,0-32h64A16,16,0,0,1,248,136Z"/><path class="cls-1" d="M280,40l-48,80H168L120,40c20,0,20-16,40-16s20,16,40.08,16,20-16,39.92-16S260,40,280,40Z"/><path class="cls-2" d="M336,280a16,16,0,0,1,0-32h48a16,16,0,0,1,0,32Z"/><path class="cls-6" d="M432,184l-48,64H336l-48-64c20,0,12-8,32-8s20,16,40.08,16,20-16,39.92-16S412,184,432,184Z"/><path class="cls-6" d="M256,360a80,80,0,0,1,80-80h48a80,80,0,0,1,80,80v59a32,32,0,0,0,14,25.52,23.89,23.89,0,0,1,10,20.72A25,25,0,0,1,462.64,488H257.36A25,25,0,0,1,232,465.28a23.89,23.89,0,0,1,10-20.72A32,32,0,0,0,256,419Z"/><path d="M352,376h16a8,8,0,0,1,8,8h16a24,24,0,0,0-24-24v-8H352v8a24,24,0,0,0,0,48h16a8,8,0,0,1,0,16H352a8,8,0,0,1-8-8H328a24,24,0,0,0,24,24v8h16v-8a24,24,0,0,0,0-48H352a8,8,0,0,1,0-16Z"/><rect x="408" y="392" width="16" height="16"/><rect x="296" y="392" width="16" height="16"/><path d="M144,240v16a24,24,0,0,1,24,24h16A40.05,40.05,0,0,0,144,240Z"/><rect x="113.57" y="340.8" width="12.86" height="22.4"/><rect x="136.14" y="340.8" width="12.86" height="22.4"/><rect x="163.04" y="340.8" width="12.86" height="22.4"/><rect x="110.43" y="388.8" width="12.86" height="22.4"/><rect x="136.14" y="388.8" width="12.86" height="22.4"/><rect x="163.04" y="388.8" width="12.86" height="22.4"/><rect x="113.57" y="441.6" width="12.86" height="22.4"/><rect x="136.14" y="441.6" width="12.86" height="22.4"/><rect x="163.04" y="441.6" width="12.86" height="22.4"/></g><path class="cls-2" d="M231.91,182v8h16v-8a47.84,47.84,0,0,0-12.32-32H199.91A32,32,0,0,1,231.91,182Z"/><path class="cls-2" d="M320,318h16v-8a32,32,0,0,1,23.32-30.8H331.2A48,48,0,0,0,320,310Z"/><path class="cls-2" d="M151.91,190h16v-8a32,32,0,0,1,32-32H164.23a47.84,47.84,0,0,0-12.32,32Z"/><path class="cls-2" d="M399.32,318h-16v-8A32,32,0,0,0,360,279.18h28.12a47.94,47.94,0,0,1,11.2,30.8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1,.cls-7{fill:#9baaab;}.cls-1,.cls-2,.cls-3,.cls-4{fill-rule:evenodd;}.cls-10,.cls-2{fill:#e6eaea;}.cls-3,.cls-8{fill:#cdd4d5;}.cls-4,.cls-9{fill:#365558;}.cls-5{fill:#0295aa;}.cls-6{fill:#4acfd9;}</style></defs><title>tokens-mined</title><path class="cls-1" d="M123.51,201V167.65L56.27,126.41,20,201Z"/><path class="cls-2" d="M56.27,126.41l67.24,41.24,12.12-68.2Z"/><path class="cls-3" d="M135.63,99.45l-12.12,68.2V201h54.66l2.11-54Z"/><path class="cls-2" d="M135.63,99.45,180.28,147l60.44-48.11L197.13,36Z"/><path class="cls-1" d="M180.28,147l-2.11,54h54.67l7.88-34.4Z"/><path class="cls-1" d="M180.28,147l60.44,19.57,61-33.31-61-34.37Z"/><path class="cls-2" d="M197.13,36l43.59,62.92,43.14-46Z"/><path class="cls-3" d="M283.86,52.92l-43.14,46,61,34.37,26.85-37Z"/><path class="cls-3" d="M301.69,133.29l-61,33.31L232.84,201h96.71Z"/><path class="cls-2" d="M301.69,133.29,329.55,201,395.81,93.63l-67.27,2.65Z"/><path class="cls-3" d="M395.81,93.63,329.55,201l98.33-65.07Z"/><path class="cls-1" d="M427.88,135.93,329.55,201h98.33Z"/><path class="cls-1" d="M427.88,135.93V201H492l-11-41.8Z"/><path class="cls-4" d="M492,201H20a10,10,0,0,0-10,10v25a10,10,0,0,0,10,10H492a10,10,0,0,0,10-10V211A10,10,0,0,0,492,201Z"/><path class="cls-5" d="M30,246,65.1,404A50,50,0,0,1,160,426h96V246Z"/><path class="cls-6" d="M256,246V426h96a50,50,0,0,1,94.89-22L482,246Z"/><path class="cls-4" d="M160,426a50,50,0,1,0-50,50h0A50,50,0,0,0,160,426Z"/><path class="cls-4" d="M352,426a50,50,0,1,0,50-50h0A50,50,0,0,0,352,426Z"/><path class="cls-7" d="M110,416h0a10,10,0,1,0,10,10A10,10,0,0,0,110,416Z"/><path class="cls-8" d="M402,416h0a10,10,0,1,0,10,10A10,10,0,0,0,402,416Z"/><path class="cls-9" d="M170,296h0a10,10,0,1,0-10-10A10,10,0,0,0,170,296Z"/><path class="cls-9" d="M134.13,286a7.5,7.5,0,0,0-7.5-7.5H47a7.5,7.5,0,0,0,0,15h79.68A7.51,7.51,0,0,0,134.13,286Z"/><path class="cls-10" d="M431.67,42.89a37.16,37.16,0,0,0-20,10.46c-.44.44-.88.88-1.33,1.38a37.27,37.27,0,0,0-9.19,18.65.63.63,0,0,1-1.2,0,37.16,37.16,0,0,0-10.46-20l-.5-.51h-.06a37.29,37.29,0,0,0-19.47-10,.63.63,0,0,1,0-1.2,27.73,27.73,0,0,0,4.48-1.13,37.71,37.71,0,0,0,26-29.42.63.63,0,0,1,1.2,0,37.24,37.24,0,0,0,10.52,20,36.84,36.84,0,0,0,20,10.52.63.63,0,0,1,0,1.2Z"/><path class="cls-10" d="M467.4,132.78a37.29,37.29,0,0,0-20,10.46c-.44.44-.88.88-1.32,1.39a37.2,37.2,0,0,0-9.19,18.64.64.64,0,0,1-.6.44.62.62,0,0,1-.6-.44,37.22,37.22,0,0,0-10.46-20l-.5-.5h-.07a37.24,37.24,0,0,0-19.46-10,.63.63,0,0,1,0-1.19,26.4,26.4,0,0,0,4.47-1.14,37.71,37.71,0,0,0,26-29.41.62.62,0,0,1,.6-.44.64.64,0,0,1,.6.44,37.3,37.3,0,0,0,10.51,20,36.87,36.87,0,0,0,20,10.52.63.63,0,0,1,0,1.19Z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 79 KiB |
@@ -81,12 +81,12 @@
|
||||
"id": "bda21833-11b8-49d3-8c79-ff8e1c667dcc",
|
||||
"savedPayload": {
|
||||
"position": {
|
||||
"x": 31000.07168984726,
|
||||
"y": 23974.264068711924
|
||||
"x": 30936.297332942388,
|
||||
"y": 24042.62315256192
|
||||
},
|
||||
"targetPosition": {
|
||||
"x": 30787.939655491296,
|
||||
"y": 23762.13203435596
|
||||
"x": 30747.501215627435,
|
||||
"y": 23809.47936412483
|
||||
},
|
||||
"floatingObject": {
|
||||
"isPinned": false,
|
||||
@@ -114,7 +114,7 @@
|
||||
"floatingObject": {
|
||||
"isPinned": false,
|
||||
"isFrozen": false,
|
||||
"isCollapsed": true,
|
||||
"isCollapsed": false,
|
||||
"angleToParent": 3,
|
||||
"distanceToParent": 3,
|
||||
"arrangementStyle": 0
|
||||
@@ -13714,7 +13714,7 @@
|
||||
"floatingObject": {
|
||||
"isPinned": false,
|
||||
"isFrozen": false,
|
||||
"isCollapsed": true,
|
||||
"isCollapsed": false,
|
||||
"angleToParent": 2,
|
||||
"distanceToParent": 3,
|
||||
"arrangementStyle": 0
|
||||
|
||||
@@ -29,13 +29,6 @@
|
||||
"relatedUiObject": "Positions",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"actionProject": "Foundations",
|
||||
"label": "Add User Profile",
|
||||
"relatedUiObject": "User Profile",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"actionProject": "Foundations",
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
"text": "Search the exchange's website for information describing the listing process and requirements. Study the information carefully.",
|
||||
"updated": 1618562031958
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "If not enough information is available publicly, feel free to contact their support or listing teams for more information."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "You may also want to start filling a dummy listing requirement form to find out what kind of information the exchange requires."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Report on your findings using the Research Requirements bullet list below.",
|
||||
@@ -66,7 +74,8 @@
|
||||
},
|
||||
{
|
||||
"style": "Text",
|
||||
"text": "If you're not familiar with the process of editing pages in the Docs and contributing the pages you create or edit, please go to the Getting Started Plugin Workspace and do the Beyond the Basics Tutorial."
|
||||
"text": "If you're not familiar with the process of editing pages in the Docs and contributing the pages you create or edit, please go to the Getting Started Tutorials Plugin Workspace and do the Beyond the Basics Tutorial.",
|
||||
"updated": 1628509381517
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
@@ -85,8 +94,8 @@
|
||||
},
|
||||
{
|
||||
"style": "Json",
|
||||
"text": "docs.add Topic to Superalgos: Exchange Listing Requirements Research->Exchange Name Listing Requirements->N",
|
||||
"updated": 1618486204475
|
||||
"text": "docs.add Topic to Governance: Exchange Listing Requirements Research->Exchange Name Listing Requirements->N",
|
||||
"updated": 1628532030221
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
@@ -139,7 +148,8 @@
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange Name->exchangeURL.com"
|
||||
"text": "Exchange URL->exchangeURL.com",
|
||||
"updated": 1628513074678
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
@@ -161,6 +171,10 @@
|
||||
"text": "Listing request form->pageURL.com",
|
||||
"updated": 1618498025893
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Can list BEP 20 BSC tokens: Some exchanges may not be able to list tokens in the Binance Smart Chain. Make sure you find out if listing the token is technically possible."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing fee: Exchanges usually charge for listing new coins. Enter the fee and include any comments, exceptions, or details that may be relevant to our particular case.",
|
||||
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"topic": "Exchange Listing Requirements Research",
|
||||
"pageNumber": "2",
|
||||
"type": "Probit Global Listing Requirements",
|
||||
"definition": {
|
||||
"text": "The exchange is ready to list Superalgos. Listing fee is $25k, plus 1 BTC in project tokens.",
|
||||
"updated": 1628512539086
|
||||
},
|
||||
"paragraphs": [
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Listing Requirements",
|
||||
"updated": 1628515442342
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange name: Probit Global"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CMC ranking: 27",
|
||||
"updated": 1628510522467
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange home page: ",
|
||||
"updated": 1628510560296
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Exchange URL->www.probit.com",
|
||||
"updated": 1628519777927
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing requirements page: ",
|
||||
"updated": 1628510662586
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing requirements->www.probit.com/en-us/listing",
|
||||
"updated": 1628510672736
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing request form page: ",
|
||||
"updated": 1628510689962
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing request form->docs.google.com/forms/d/e/1FAIpQLSf4b5e25olgKVVY623XBe7Pw1LxFZcCVAGaBXLgJ0sw7KwvkA/viewform",
|
||||
"updated": 1628510737641
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Can list BEP 20 tokens in BSC: Yes",
|
||||
"updated": 1628511590834
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing fee: Bronze $25k, Silver $50k, Gold $80k -- plus 1 BTC in project tokens.",
|
||||
"updated": 1628512487779
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Security deposit: No",
|
||||
"updated": 1628510838412
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Volume requirements: No",
|
||||
"updated": 1628510856025
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Market-making requirements: Included for 1 month in all plans; not required afterwards.",
|
||||
"updated": 1628510894252
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange users requirement: No",
|
||||
"updated": 1628510904049
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Pairs available for first listing: USDT, BTC, ETH",
|
||||
"updated": 1628510967084
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Waiting period: 2 weeks.",
|
||||
"updated": 1628510983346
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal entity: A corporation is usually required.",
|
||||
"updated": 1628511032973
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal opinion: Usually required.",
|
||||
"updated": 1628511045422
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Selection process: N/A.",
|
||||
"updated": 1628511087443
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's comments: I have an open channel with the listing team and have clarified some issues, as explained under the Negotiation title below.",
|
||||
"updated": 1628512314800
|
||||
},
|
||||
{
|
||||
"style": "Png",
|
||||
"text": "PNGs/Governance/Docs/token-task-force/probit-listing-plans.png",
|
||||
"updated": 1628516831766
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Github.com Username: julian-molina",
|
||||
"updated": 1628511321864
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Telegram Username: @julianmolina",
|
||||
"updated": 1628511330617
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Date of last revision: August 9th, 2021.",
|
||||
"updated": 1628585744548
|
||||
},
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Negotiation"
|
||||
},
|
||||
{
|
||||
"style": "Text",
|
||||
"text": "@julianmolina has confirmed that:",
|
||||
"updated": 1628512180751
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "they accept Superalgos for listing;",
|
||||
"updated": 1628511554947
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "we can coordinate the listing date to suit PR & Marketing campaigns."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "they can wave the legal opinion requirement if it's clear the token is not a security;",
|
||||
"updated": 1628533059002
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "they don't need a corporation to sign the listing agreement; a KYCed executive (project leadership) works too;",
|
||||
"updated": 1628533074328
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "we can propose new or improved language in the listing agreement for a more balanced protection of both parties;",
|
||||
"updated": 1628511650104
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "we can have additional zero-fee accounts for market making at $5k each;",
|
||||
"updated": 1628533110459
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "they wouldn't de-list due to low volume for at least 6 months.",
|
||||
"updated": 1628533123086
|
||||
},
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Exchange Evaluation"
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Corporate Information",
|
||||
"updated": 1628527538347
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Country of registration: Seychelles (from TOS page and Listing Agreement).",
|
||||
"updated": 1628527930627
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Address: Suite 9, Ansuya Estate, Revolution Avenue, Victoria Mahe, Seychelles (from Listing Agreement)."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Year of registration: Unknown",
|
||||
"updated": 1628527959834
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Physical offices: Unknown",
|
||||
"updated": 1628527967290
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Licenses: Unknown",
|
||||
"updated": 1628527972228
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Corporate Transparency on Website"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Footer info: Probit Global Service Limited | Company Registration Number: 207189 | representative: Ronald Chan. In process of registration: Probit Exchange OÜ | Company Registration Number: 14894573 | Representative: Ronald Chan.",
|
||||
"updated": 1628527446408
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "About page info: N/A.",
|
||||
"updated": 1628527467687
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Leadership page info: N/A"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Observations: Poor. There is little clarity on the website as of where and how the company operates.",
|
||||
"updated": 1628530441154
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Website Traction",
|
||||
"updated": 1628528688773
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Alexa site rank: 3500",
|
||||
"updated": 1628517005331
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Alexa->www.alexa.com/siteinfo/probit.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Domain authority: 45",
|
||||
"updated": 1628517390639
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "DA by Moz->moz.com/domain-analysis?site=probit.com",
|
||||
"updated": 1628538393505
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CMC ranking: 27",
|
||||
"updated": 1628517194530
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CoinGecko ranking: 63"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Top 100 Google SERP? [*]: No",
|
||||
"updated": 1628527176017
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Top 200 Google SERP? [*]: No"
|
||||
},
|
||||
{
|
||||
"style": "Text",
|
||||
"text": "(*) We search Google (UK region, no personalization) for the keyphrase \"crypto exchange\". The domain is either listed within the top X SERP or not.",
|
||||
"updated": 1628527204901
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Community",
|
||||
"updated": 1628528888597
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Telegram: 29k",
|
||||
"updated": 1628528925197
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Telegram English Community->t.me/ProbitEnglish"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Observations: A quick glance on August 9th, 2021. Users complain about deposits not clearing and other issues. There is some response from admins announcing an issue with wallet upgrades. Conversation seems reasonable.",
|
||||
"updated": 1628532175405
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Liquidity & Volume"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "1m BTC-USDT Chart"
|
||||
},
|
||||
{
|
||||
"style": "Png",
|
||||
"text": "PNGs/Governance/Docs/token-task-force/probit-btc-usdt-1m-chart.PNG",
|
||||
"updated": 1628530005285
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "BTC - USDT Chart->www.probit.com/app/exchange/BTC-USDT",
|
||||
"updated": 1628530307201
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
{
|
||||
"topic": "Exchange Listing Requirements Research",
|
||||
"pageNumber": "3",
|
||||
"type": "LBank Listing Requirements",
|
||||
"definition": {
|
||||
"text": "Pending listing requirements and revision.",
|
||||
"updated": 1628538709584
|
||||
},
|
||||
"paragraphs": [
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Listing Requirements",
|
||||
"updated": 1628515469804
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange name: LBank",
|
||||
"updated": 1628512837877
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CMC ranking: The position of the exchange in the ranking as of the day of the research."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange home page: Edit the string below with the name of the exchange and the URL (without the protocol). ",
|
||||
"updated": 1628512823690
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Exchange URL->exchangeURL.com",
|
||||
"updated": 1628512847099
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing requirements page: Edit the string below with the URL (without the protocol) of the page where you got the core of the information in this report. ",
|
||||
"updated": 1628512803920
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing requirements->pageURL.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing request form page: Edit the string below with the URL (without the protocol) of the page (or online form) the project should use to request the listing of the token. ",
|
||||
"updated": 1628512810149
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing request form->pageURL.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Can list BEP 20 BSC tokens: Some exchanges may not be able to list tokens in the Binance Smart Chain. Make sure you find out if listing the token is technically possible."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing fee: Exchanges usually charge for listing new coins. Enter the fee and include any comments, exceptions, or details that may be relevant to our particular case."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Security deposit: Some exchanges require a security deposit to be returned to the project after the listing is completed. Describe the details of such requirements if they exist."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Volume requirements: Exchanges are in the business of charging transaction fees, so they usually expect to list tokens that have traction, in the understanding that such tokens will generate a certain level of trading volume. Some exchanges have a specific requirement about the expected volume. If the exchange requires a precise volume, enter it in numbers. Otherwise, describe what is expected in words."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Market-making requirements: Many times exchanges expect projects to guarantee liquidity for the token on both sides of the order book. They sometimes require projects to hire specific market-makers or ask the project how they will deal with the issue. Explain what the exchange expects in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange users requirement: Some exchanges require the project to drive a certain number of users to the exchange. Describe any requirements that may exist in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Pairs available for first listing: Some exchanges limit the number of pairs or even the precise quote assets that may be used for first listings. Describe whatever the exchange requires or offers in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Waiting period: Most exchanges have a queue of listing requests and they may be able to estimate how long it takes to process. If there is information in this regard, include it here. The exchange may not announce what the estimate is, but you may deduce it or find out in community chats, forums, etc. Do your research."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal entity: Some exchanges may require the project to be represented by a legal entity (a foundation, corporation, etc). If that is the case, enter \"Yes\", and describe what the requirement is. If there is no such requirement, enter \"No\"."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal opinion: Some exchanges may require the project to get legal advice in the form of a \"legal opinion letter\" or some instrument of the sort, most times about the nature of the token, in particular, to determine if the token is a security or not. If that is the case, enter \"Yes\", and describe what the requirement is. If there is no such requirement, enter \"No\"."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Selection process: Some exchanges describe the nature of the decision-making process to select which tokens shall be listed. Some involve the participation of their community, a voting process, or things of the sort. Describe what the process is like if there is any information about it."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's comments: If you notice any information of importance to the listing process that is not covered in this list, include it here."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Github.com Username: This helps track the author of each research contribution."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Telegram Username: Same as above."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Date of last revision: This report may be updated every once in a while. Use this field to note the last time the report was updated."
|
||||
},
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Negotiation"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "List what progress has been made in the ongoing negotiation."
|
||||
},
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Exchange Evaluation"
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Corporate Information"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Country of registration: ",
|
||||
"updated": 1628536538914
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Address: ",
|
||||
"updated": 1628536544461
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Year of registration: ",
|
||||
"updated": 1628536550106
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Physical offices: ",
|
||||
"updated": 1628536554948
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Licenses: ",
|
||||
"updated": 1628536559754
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Corporate Transparency on Website"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Footer info: None.",
|
||||
"updated": 1628539579292
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "About page info: None.",
|
||||
"updated": 1628539586129
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Leadership page info: None.",
|
||||
"updated": 1628539591833
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Observations: Obscure. Zero info provided as of where or how the company operates.",
|
||||
"updated": 1628539616801
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Website Traction"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Alexa site rank: 1100",
|
||||
"updated": 1628537403629
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Alexa->www.alexa.com/siteinfo/lbank.info",
|
||||
"updated": 1628537437035
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Domain authority: 44",
|
||||
"updated": 1628538376155
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "DA by Moz->moz.com/domain-analysis?site=lbank.info",
|
||||
"updated": 1628538362561
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CMC ranking: 52",
|
||||
"updated": 1628536646750
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CoinGecko ranking: 32",
|
||||
"updated": 1628536624836
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Top 100 Google SERP? [*]: No"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Top 200 Google SERP? [*]: No"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "(*) We search Google (UK region, no personalization) for the keyphrase \"crypto exchange\". The domain is either listed within the top X SERP or not."
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Community"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Telegram: 42k",
|
||||
"updated": 1628538502945
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Telegram English Community->t.me/LBank_en",
|
||||
"updated": 1628538533078
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Observations: A quick look on August 9th, 2021. Light and decent conversation. Some shilling of coins. Some support requests from users redirected to the website's chat by admins. Many admins present. ",
|
||||
"updated": 1628539131853
|
||||
},
|
||||
{
|
||||
"style": "Subtitle",
|
||||
"text": "Liquidity & Volume"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "1m BTC-USDT Chart"
|
||||
},
|
||||
{
|
||||
"style": "Png",
|
||||
"text": "PNGs/Governance/Docs/token-task-force/lbank-btc-usdt-1m-chart.PNG",
|
||||
"updated": 1628538612321
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "BTC - USDT Chart->www.lbank.info/exchange/btc/usdt",
|
||||
"updated": 1628538654684
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"topic": "Exchange Listing Requirements Research",
|
||||
"pageNumber": "4",
|
||||
"type": "Bittrex Global Listing Requirements",
|
||||
"definition": {
|
||||
"text": "Write a summary for this topic page."
|
||||
},
|
||||
"paragraphs": [
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Listing Requirements",
|
||||
"updated": 1628515483720
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange name: Use the official, most common name of the exchange; the same you used in the name of the page."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "CMC ranking: The position of the exchange in the ranking as of the day of the research."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange home page: Edit the string below with the name of the exchange and the URL (without the protocol). Test the link and make sure it works.",
|
||||
"updated": 1628513218161
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Exchange URL->exchangeURL.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing requirements page: Edit the string below with the URL (without the protocol) of the page where you got the core of the information in this report. Test the link and make sure it works.",
|
||||
"updated": 1628513207300
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing requirements->pageURL.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing request form page: Edit the string below with the URL (without the protocol) of the page (or online form) the project should use to request the listing of the token. Test the link and make sure it works.",
|
||||
"updated": 1628513198400
|
||||
},
|
||||
{
|
||||
"style": "Link",
|
||||
"text": "Listing request form->pageURL.com"
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Can list BEP 20 BSC tokens: Some exchanges may not be able to list tokens in the Binance Smart Chain. Make sure you find out if listing the token is technically possible."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Listing fee: Exchanges usually charge for listing new coins. Enter the fee and include any comments, exceptions, or details that may be relevant to our particular case."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Security deposit: Some exchanges require a security deposit to be returned to the project after the listing is completed. Describe the details of such requirements if they exist."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Volume requirements: Exchanges are in the business of charging transaction fees, so they usually expect to list tokens that have traction, in the understanding that such tokens will generate a certain level of trading volume. Some exchanges have a specific requirement about the expected volume. If the exchange requires a precise volume, enter it in numbers. Otherwise, describe what is expected in words."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Market-making requirements: Many times exchanges expect projects to guarantee liquidity for the token on both sides of the order book. They sometimes require projects to hire specific market-makers or ask the project how they will deal with the issue. Explain what the exchange expects in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Exchange users requirement: Some exchanges require the project to drive a certain number of users to the exchange. Describe any requirements that may exist in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Pairs available for first listing: Some exchanges limit the number of pairs or even the precise quote assets that may be used for first listings. Describe whatever the exchange requires or offers in this regard."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Waiting period: Most exchanges have a queue of listing requests and they may be able to estimate how long it takes to process. If there is information in this regard, include it here. The exchange may not announce what the estimate is, but you may deduce it or find out in community chats, forums, etc. Do your research."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal entity: Some exchanges may require the project to be represented by a legal entity (a foundation, corporation, etc). If that is the case, enter \"Yes\", and describe what the requirement is. If there is no such requirement, enter \"No\"."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Legal opinion: Some exchanges may require the project to get legal advice in the form of a \"legal opinion letter\" or some instrument of the sort, most times about the nature of the token, in particular, to determine if the token is a security or not. If that is the case, enter \"Yes\", and describe what the requirement is. If there is no such requirement, enter \"No\"."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Selection process: Some exchanges describe the nature of the decision-making process to select which tokens shall be listed. Some involve the participation of their community, a voting process, or things of the sort. Describe what the process is like if there is any information about it."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's comments: If you notice any information of importance to the listing process that is not covered in this list, include it here."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Github.com Username: This helps track the author of each research contribution."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Researcher's Telegram Username: Same as above."
|
||||
},
|
||||
{
|
||||
"style": "List",
|
||||
"text": "Date of last revision: This report may be updated every once in a while. Use this field to note the last time the report was updated."
|
||||
},
|
||||
{
|
||||
"style": "Title",
|
||||
"text": "Negotiation"
|
||||
},
|
||||
{
|
||||
"style": "Text",
|
||||
"text": "List what progress has been made in the ongoing negotiation."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
"pageNumber": "3",
|
||||
"type": "Referral Program Overview",
|
||||
"definition": {
|
||||
"text": "Before they may contribute, people need to find out about Superalgos in the first place! The referral program built-in the Governance Project is designed to incentivize the promotion of the project, either by word-of-mouth or “en masse” through articles, social media posts, videos, and other forms of influencer marketing.",
|
||||
"updated": 1624698267400
|
||||
"text": "The referral program built-in the Governance Project is designed to incentivize the promotion of the project, either by word-of-mouth or “en masse” through articles, social media posts, videos, and other forms of influencer marketing.",
|
||||
"updated": 1628099865032
|
||||
},
|
||||
"paragraphs": [
|
||||
{
|
||||
|
||||
@@ -12,17 +12,19 @@ function newGovernanceFunctionLibraryProfileConstructor() {
|
||||
/*
|
||||
Some validations first...
|
||||
*/
|
||||
if (node.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage("You need to reference the node that contains the data to be signed.")
|
||||
return
|
||||
}
|
||||
let data = UI.projects.foundations.utilities.nodeConfig.loadConfigProperty(node.payload, 'githubUsername')
|
||||
let githubUsername = UI.projects.foundations.utilities.nodeConfig.loadConfigProperty(node.payload, 'githubUsername')
|
||||
|
||||
if (data === undefined || data === "") {
|
||||
node.payload.referenceParent.payload.uiObject.setErrorMessage("githubUsername config property missing.")
|
||||
if (githubUsername === undefined || githubUsername === "") {
|
||||
node.payload.uiObject.setErrorMessage("githubUsername config property missing.")
|
||||
return
|
||||
}
|
||||
|
||||
let userProfile = UI.projects.foundations.functionLibraries.uiObjectsFromNodes.addUIObject(
|
||||
node,
|
||||
'User Profile',
|
||||
UI.projects.foundations.spaces.designSpace.workspace.workspaceNode.rootNodes
|
||||
)
|
||||
|
||||
createNewAccount()
|
||||
|
||||
function createNewAccount() {
|
||||
@@ -31,7 +33,7 @@ function newGovernanceFunctionLibraryProfileConstructor() {
|
||||
entropy: node.id + (new Date()).valueOf()
|
||||
}
|
||||
|
||||
let url = 'WEB3' // we don't need to ask this to any specific superalgos node.
|
||||
let url = 'WEB3' // We will access the default Client WEB3 endpoint.
|
||||
|
||||
httpRequest(JSON.stringify(params), url, onResponse)
|
||||
|
||||
@@ -62,7 +64,7 @@ function newGovernanceFunctionLibraryProfileConstructor() {
|
||||
params: {
|
||||
method: "signData",
|
||||
privateKey: privateKey,
|
||||
data: data
|
||||
data: githubUsername
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,11 +85,25 @@ function newGovernanceFunctionLibraryProfileConstructor() {
|
||||
console.log('Call to WEB3 Server failed. ' + response.error)
|
||||
return
|
||||
}
|
||||
UI.projects.foundations.utilities.nodeConfig.saveConfigProperty(node.payload.referenceParent.payload, 'signature', response.signature)
|
||||
/*
|
||||
We store at the User Profile the Signed githubUsername
|
||||
*/
|
||||
UI.projects.foundations.utilities.nodeConfig.saveConfigProperty(userProfile.payload, 'signature', response.signature)
|
||||
UI.projects.foundations.utilities.nodeConfig.saveConfigProperty(node.payload, 'address', address)
|
||||
UI.projects.foundations.utilities.nodeConfig.saveConfigProperty(node.payload, 'privateKey', privateKey)
|
||||
|
||||
node.payload.uiObject.setInfoMessage("Profile Account has been successfully created.")
|
||||
/*
|
||||
We set the name of the User Profile as the githubUsername
|
||||
*/
|
||||
userProfile.name = githubUsername
|
||||
/*
|
||||
We also Install the User Profile as a Plugin, which in turns saves it.
|
||||
*/
|
||||
userProfile.payload.uiObject.menu.internalClick('Install as Plugin')
|
||||
userProfile.payload.uiObject.menu.internalClick('Install as Plugin')
|
||||
/*
|
||||
Show nice message.
|
||||
*/
|
||||
node.payload.uiObject.setInfoMessage("Profile Private Key has been successfully created. User Profile installed as a plugin and saved. Use the Private Key at a crypto wallet and delete this node once done.", 10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@ function newGovernanceReportsCommmandInterface() {
|
||||
message = 'Automated PR merging process.'
|
||||
}
|
||||
|
||||
/* Closing the Governance Tab */
|
||||
UI.projects.governance.spaces.reportsSpace.sidePanelTab.close()
|
||||
UI.projects.education.spaces.docsSpace.sidePanelTab.open()
|
||||
|
||||
/* Find the Username and Password */
|
||||
let apisNode = UI.projects.foundations.spaces.designSpace.workspace.getHierarchyHeadByNodeType('APIs')
|
||||
if (apisNode === undefined) {
|
||||
@@ -62,36 +66,53 @@ function newGovernanceReportsCommmandInterface() {
|
||||
return
|
||||
}
|
||||
|
||||
UI.projects.education.spaces.docsSpace.navigateTo('Governance', 'Topic', 'Gov Message - Processing Pull Requests')
|
||||
|
||||
message = message.replaceAll('#', '_HASHTAG_')
|
||||
message = message.replaceAll('/', '_SLASH_')
|
||||
|
||||
httpRequest(
|
||||
undefined,
|
||||
'Gov/PRs/' +
|
||||
message + '/' +
|
||||
config.username + '/' +
|
||||
config.token + '/' +
|
||||
UI.projects.education.spaces.docsSpace.currentBranch + '/' +
|
||||
UI.projects.education.spaces.docsSpace.contributionsBranch
|
||||
, onResponse)
|
||||
/* Lets execute this command against the Client */
|
||||
|
||||
UI.projects.education.spaces.docsSpace.navigateTo('Governance', 'Topic', 'Gov Message - Processing Pull Requests')
|
||||
let params = {
|
||||
method: 'mergePullRequests',
|
||||
commitMessage: message,
|
||||
username: config.username,
|
||||
token: config.token
|
||||
}
|
||||
|
||||
return
|
||||
let url = 'GOV' // We will access the default Client GOV endpoint.
|
||||
|
||||
httpRequest(JSON.stringify(params), url, onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
|
||||
/* Lets check the result of the call through the http interface */
|
||||
data = JSON.parse(data)
|
||||
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result && data.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call via HTTP Interface failed.' + err.stack)
|
||||
console.log('[ERROR] Params = ' + JSON.stringify(params))
|
||||
return
|
||||
}
|
||||
|
||||
let response = JSON.parse(data)
|
||||
|
||||
/* Lets check the result of the method call */
|
||||
if (response.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call to Client Github Server failed.' + err.stack)
|
||||
console.log('[ERROR] Params = ' + JSON.stringify(params))
|
||||
}
|
||||
|
||||
/* Successful Call */
|
||||
|
||||
if (response.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
UI.projects.education.spaces.docsSpace.navigateTo('Governance', 'Topic', 'Gov Message - Pull Requests Processed')
|
||||
} else {
|
||||
UI.projects.education.spaces.docsSpace.navigateTo(
|
||||
data.docs.project,
|
||||
data.docs.category,
|
||||
data.docs.type,
|
||||
data.docs.anchor,
|
||||
response.docs.project,
|
||||
response.docs.category,
|
||||
response.docs.type,
|
||||
response.docs.anchor,
|
||||
undefined,
|
||||
data.docs.placeholder
|
||||
response.docs.placeholder
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,15 +231,6 @@ function newGobernanceReportsSpace() {
|
||||
'width: ' + thisObject.container.frame.width + 'px;' +
|
||||
'height: ' + thisObject.container.frame.height + 'px'
|
||||
}
|
||||
|
||||
/*
|
||||
Monitor the Docs Space to see if its tab is opened, to close this space tab.
|
||||
*/
|
||||
if (UI.projects.education.spaces.docsSpace.sidePanelTab.isOpen === true &&
|
||||
thisObject.sidePanelTab.isOpen === true
|
||||
) {
|
||||
thisObject.sidePanelTab.close()
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer(point, purpose) {
|
||||
|
||||
@@ -37,7 +37,7 @@ function newGovernanceUserProfileSpace() {
|
||||
If the workspace is not related to governance, then we exit the Intialize Function
|
||||
*/
|
||||
let resultsArary = UI.projects.foundations.spaces.designSpace.workspace.getHierarchyHeadsByNodeType('User Profile')
|
||||
if (resultsArary.length === 0 || resultsArary.length === 1) { return }
|
||||
if (resultsArary.length === 0) { return }
|
||||
|
||||
/* Find the Username and Password */
|
||||
|
||||
@@ -68,69 +68,135 @@ function newGovernanceUserProfileSpace() {
|
||||
requestStars()
|
||||
|
||||
function requestStars() {
|
||||
httpRequest(
|
||||
undefined,
|
||||
'Gov/getGithubStars/' +
|
||||
'Superalgos' + '/' +
|
||||
config.username + '/' +
|
||||
config.token
|
||||
, onGithubStarsResponse)
|
||||
|
||||
let params = {
|
||||
method: 'getGithubStars',
|
||||
repository: 'Superalgos',
|
||||
username: config.username,
|
||||
token: config.token
|
||||
}
|
||||
|
||||
let url = 'GOV' // We will access the default Client GOV endpoint.
|
||||
|
||||
httpRequest(JSON.stringify(params), url, onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
|
||||
/* Lets check the result of the call through the http interface */
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call via HTTP Interface failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
return
|
||||
}
|
||||
|
||||
let response = JSON.parse(data)
|
||||
|
||||
/* Lets check the result of the method call */
|
||||
if (response.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call to Client Github Server failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
console.log('[ERROR] response = ' + JSON.stringify(response))
|
||||
return
|
||||
}
|
||||
|
||||
/* Successful Call */
|
||||
|
||||
let githubStarsArray = response.githubListArray
|
||||
|
||||
for (let i = 0; i < githubStarsArray.length; i++) {
|
||||
let githubUsername = githubStarsArray[i]
|
||||
thisObject.githubStars.set(githubUsername, 1)
|
||||
}
|
||||
|
||||
requestWatchers()
|
||||
}
|
||||
}
|
||||
|
||||
function requestWatchers() {
|
||||
httpRequest(
|
||||
undefined,
|
||||
'Gov/getGithubWatchers/' +
|
||||
'Superalgos' + '/' +
|
||||
config.username + '/' +
|
||||
config.token
|
||||
, onGithubWatchersResponse)
|
||||
|
||||
let params = {
|
||||
method: 'getGithubWatchers',
|
||||
repository: 'Superalgos',
|
||||
username: config.username,
|
||||
token: config.token
|
||||
}
|
||||
|
||||
let url = 'GOV' // We will access the default Client GOV endpoint.
|
||||
|
||||
httpRequest(JSON.stringify(params), url, onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
|
||||
/* Lets check the result of the call through the http interface */
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call via HTTP Interface failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
return
|
||||
}
|
||||
|
||||
let response = JSON.parse(data)
|
||||
|
||||
/* Lets check the result of the method call */
|
||||
if (response.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call to Client Github Server failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
console.log('[ERROR] response = ' + JSON.stringify(response))
|
||||
return
|
||||
}
|
||||
|
||||
/* Successful Call */
|
||||
|
||||
let githubWatchersArray = response.githubListArray
|
||||
|
||||
for (let i = 0; i < githubWatchersArray.length; i++) {
|
||||
let githubUsername = githubWatchersArray[i]
|
||||
thisObject.githubWatchers.set(githubUsername, 1)
|
||||
}
|
||||
|
||||
requestForks()
|
||||
}
|
||||
}
|
||||
|
||||
function requestForks() {
|
||||
httpRequest(
|
||||
undefined,
|
||||
'Gov/getGithubForks/' +
|
||||
'Superalgos' + '/' +
|
||||
config.username + '/' +
|
||||
config.token
|
||||
, onGithubForksResponse)
|
||||
}
|
||||
|
||||
function onGithubStarsResponse(err, githubData) {
|
||||
//console.log(githubData)
|
||||
/* Lets check the result of the call through the http interface */
|
||||
let githubStarsArray = JSON.parse(githubData)
|
||||
|
||||
for (let i = 0; i < githubStarsArray.length; i++) {
|
||||
let githubUsername = githubStarsArray[i]
|
||||
thisObject.githubStars.set(githubUsername, 1)
|
||||
let params = {
|
||||
method: 'getGithubForks',
|
||||
repository: 'Superalgos',
|
||||
username: config.username,
|
||||
token: config.token
|
||||
}
|
||||
|
||||
requestWatchers()
|
||||
}
|
||||
let url = 'GOV' // We will access the default Client GOV endpoint.
|
||||
|
||||
function onGithubWatchersResponse(err, githubData) {
|
||||
//console.log(githubData)
|
||||
/* Lets check the result of the call through the http interface */
|
||||
let githubWatchersArray = JSON.parse(githubData)
|
||||
httpRequest(JSON.stringify(params), url, onResponse)
|
||||
|
||||
for (let i = 0; i < githubWatchersArray.length; i++) {
|
||||
let githubUsername = githubWatchersArray[i]
|
||||
thisObject.githubWatchers.set(githubUsername, 1)
|
||||
}
|
||||
function onResponse(err, data) {
|
||||
|
||||
requestForks()
|
||||
}
|
||||
/* Lets check the result of the call through the http interface */
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call via HTTP Interface failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
return
|
||||
}
|
||||
|
||||
function onGithubForksResponse(err, githubData) {
|
||||
//console.log(githubData)
|
||||
/* Lets check the result of the call through the http interface */
|
||||
let githubForksArray = JSON.parse(githubData)
|
||||
let response = JSON.parse(data)
|
||||
|
||||
for (let i = 0; i < githubForksArray.length; i++) {
|
||||
let githubUsername = githubForksArray[i]
|
||||
thisObject.githubForks.set(githubUsername, 1)
|
||||
/* Lets check the result of the method call */
|
||||
if (response.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
console.log('[ERROR] Call to Client Github Server failed. err.stack = ' + err.stack)
|
||||
console.log('[ERROR] params = ' + JSON.stringify(params))
|
||||
console.log('[ERROR] response = ' + JSON.stringify(response))
|
||||
return
|
||||
}
|
||||
|
||||
/* Successful Call */
|
||||
|
||||
let githubForksArray = response.githubListArray
|
||||
|
||||
for (let i = 0; i < githubForksArray.length; i++) {
|
||||
let githubUsername = githubForksArray[i]
|
||||
thisObject.githubForks.set(githubUsername, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,7 +871,28 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"CL": {},
|
||||
"CL": {
|
||||
"utilities": [
|
||||
{
|
||||
"name": "Async Functions",
|
||||
"propertyName": "asyncFunctions",
|
||||
"functionName": "newFoundationsUtilitiesAsyncFunctions",
|
||||
"fileName": "AsyncFunctions.js"
|
||||
},
|
||||
{
|
||||
"name": "Web Access",
|
||||
"propertyName": "webAccess",
|
||||
"functionName": "newFoundationsUtilitiesWebAccess",
|
||||
"fileName": "WebAccess.js"
|
||||
},
|
||||
{
|
||||
"name": "Plugins",
|
||||
"propertyName": "plugins",
|
||||
"functionName": "newFoundationsUtilitiesPlugins",
|
||||
"fileName": "Plugins.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
"Data Mines",
|
||||
"Trading Mines",
|
||||
|
||||
@@ -15,94 +15,116 @@ Superalgos is not just another open-source project. We are an open and welcoming
|
||||
|
||||
Follow the link to [INSTALL.md](https://github.com/Superalgos/Superalgos/blob/develop/INSTALL.md).
|
||||
|
||||
# What is Superalgos?
|
||||
# The Superalgos Project
|
||||
|
||||
## Superalgos is a token-incentivized open-source project.
|
||||
## Superalgos is a token-incentivized open-source project
|
||||
|
||||
The project incentivizes users to continuously improve Superalgos. Users contribute to the codebase, to the library of trading intelligence, and to project development in general -- and earn SA tokens for their contributions. Providing free, high-quality, real-time trading-intelligence over the Superalgos peer-to-peer network is a key activity, also incentivized.
|
||||
The protocol incentivizes users to improve Superalgos. To do that, users contribute to the codebase, add to the library of trading intelligence, and help with project development in general, earning Superalgos (SA) tokens for their contributions. Protocol-incentivized contributions allow the project to distribute free of charge, high-quality trading intelligence over the Superalgos peer-to-peer network, currently in the making.
|
||||
|
||||
## Superalgos is an open-network project built on top of the Internet + Bitcoin + Lighting open networks.
|
||||
## Superalgos is an open-network project built on top of other open networks: Internet + Bitcoin + Lightning
|
||||
|
||||
This means that the Superalgos open network target audience is 8 billion people and that payments of products and services offered through the Superalgos Network are done with bitcoin over the Lighting Network.
|
||||
Because it's an open network, our target audience is, theoretically, 8 billion people. While all products and services provided by the project are free of charge, third-party products and services distributed through the Superalgos Network will be payable in bitcoin over the Lighting Network.
|
||||
|
||||
## Superalgos is a free and open trading-intelligence network anyone can plug-in to emit or consume real-time trading signals.
|
||||
## The Superalgos Network is an open trading intelligence network distributing trading signals
|
||||
|
||||
Signals are cryptographically signed by trading intelligence producers and backed by their token holdings and reputation. The Superalgos p2p Network sorts how signals are distributed, prioritizing signals-consumers with the biggest token holdings.
|
||||
Anyone may plug in to provide or consume trading signals in a permissionless manner. Signals are cryptographically signed by trading intelligence providers with a reputation reflected in their token holdings. The Superalgos p2p Network prioritizes signals distribution according to the token holdings of consumers.
|
||||
|
||||
## Superalgos has the ultimate scalable and defensible business model.
|
||||
## Superalgos has a scalable and defensible business model
|
||||
|
||||
* Everything is free and open source for its user base: trading automation tools + mobile apps for consuming real-time trading intelligence.
|
||||
* The Superalgos algo-traders community members compete with each other to mine SA tokens by producing high quality real-time trading intelligence which is consumed for free by the Superalgos user base to automate their trading.
|
||||
* Trading Intelligence is distributed via a protocol-incentivized p2p network with no network fees.
|
||||
* The long term viability is guaranteed since the business model can not be disrupted.
|
||||
* Everything is open-source and free of charge for all users: trading automation tools to produce trading intelligence, and mobile apps to consume it.
|
||||
|
||||
## Superalgos massive adoption is highly likely since all friction has been removed.
|
||||
* Algo traders compete to mine SA tokens, producing high-quality, ever-evolving trading intelligence paid for by the protocol.
|
||||
|
||||
* Users don’t need to pay for the mobile app to consume trading intelligence.
|
||||
* Users don’t need to pay for high-quality trading intelligence.
|
||||
* Algo-traders don’t need to pay for the tools to produce trading intelligence.
|
||||
* Real-time trading Intelligence does not need to be bought or sold. The Superalgos Project buys real-time trading intelligence (via minting new tokens) from the algo-traders community and distributes it for free to all the user base via its p2p network.
|
||||
* The Superalgos SA token does not need to be spent to be used, avoiding the need to pay blockchain fees. Only it’s balance is relevant to backup the user profile’s reputation and skin on the game, and in the case of real-time trading intelligence consumers give them priority access to signals.
|
||||
* Trading Intelligence is distributed via a p2p network with zero network fees.
|
||||
|
||||
## Holding the SA Token is the open network business model for all participants.
|
||||
* The long-term viability is guaranteed since the business model is undisruptable.
|
||||
|
||||
* Buying pressure will come from users competing to be among the first to receive the trading-signals.
|
||||
* Buying pressure will also come from algo-traders competing to be at the top of the list of real-time trading intelligence providers.
|
||||
* Algo trades make money, users make money, the token appreciates, everyone wins.
|
||||
## With all friction removed, mass adoption is inevitable
|
||||
|
||||
## Superalgos will become one of the most powerful consumer brands on the planet because:
|
||||
* Users do not pay for the mobile app.
|
||||
|
||||
* We are building a brand that is inline and incentivized with our users.
|
||||
* We have the business acumen and profile of a token-incentivized-open source project.
|
||||
* The project acts as an union, collecting benefits for its user base, like better exchange fees for all.
|
||||
* We don’t collect or sell user data.
|
||||
* We don’t sell ads to anyone.
|
||||
* We don’t collect or sell users trading information that can be used to front run them.
|
||||
* We know how we are going to make money, and it is on token appreciation.
|
||||
* Founders and team are just token holders as any other contributors.
|
||||
* Users do not pay for trading intelligence.
|
||||
|
||||
## Superalgos Mobile Apps will have the best user experience possible because:
|
||||
* Algo traders do not pay for the tools to produce trading intelligence.
|
||||
|
||||
* The best user experience means users should be able to consume top quality, free real-time trading intelligence and autonomously execute trades while they are sleeping.
|
||||
* Users just need to select their exchange, provide an exchange access token, define their base asset, amount of funds to be traded and trading intelligence providers.
|
||||
* Their mobile phone will become a 24/7 trading bot plugged into the Superalgos Network to receive trading signals and firing trading orders at any exchange.
|
||||
* Similar to a bitcoin wallet, anyone will be able to develop Superalgos Mobile Apps for consuming trading-signals. This open competition will be a race to the best UX possible.
|
||||
* Established crypto wallets or any trading app in general, can plugin into the Superalgos Network and consume real-time trading intelligence for free.
|
||||
* Trading Intelligence does not need to be bought or sold. The project pays for trading intelligence by minting new tokens and distributes intelligence to all users, free of charge.
|
||||
|
||||
## Superalgos does not sell it’s tokens to anyone for any reason.
|
||||
* The Superalgos (SA) token use case does not require spending, avoiding blockchain fees. Only wallet balance is relevant to determining the reputation and skin in the game of intelligence providers. The same is true for consumers. It is their wallet balance that defines the order of distribution of signals.
|
||||
|
||||
SA Tokens are distributed after each software release among the contributors of that release. If you want to mine SA tokens you can start contributing yourself or hire / sponsor someone (usually a developer or trader) to do it on your behalf.
|
||||
## Holding the SA Token is the business model for all participants
|
||||
|
||||
Users are free to buy or sell their SA Tokens. No exchange has listed SA Tokens yet. We expect that to happen soon.
|
||||
* Buying pressure will come from users competing to be among the first to receive trading signals.
|
||||
|
||||
* Algo traders build up their holdings by producing top trading intelligence and compete for the reputation entailed in their holdings.
|
||||
|
||||
* Project developers earn tokens for their contributions.
|
||||
|
||||
## Superalgos will become a powerful consumer brand because it is user-centric:
|
||||
|
||||
* We are building a brand 100% in line with consumer interests.
|
||||
|
||||
* We cherish the values of a decentralized, token-incentivized, open-source project.
|
||||
|
||||
* The project acts as a union, acquiring benefits for users, like better exchange fees for all.
|
||||
|
||||
* We do not collect or sell user data.
|
||||
|
||||
* We do not sell ads.
|
||||
|
||||
* We do not collect or sell user trading information.
|
||||
|
||||
* We know how we are going to make money: token appreciation.
|
||||
|
||||
* Founders and team are just token holders, like every other contributor.
|
||||
|
||||
## Superalgos Mobile Apps will feature a seamless user experience
|
||||
|
||||
* The app will consume top-quality trading intelligence and autonomously execute trades.
|
||||
|
||||
* Users will select an exchange, provide an exchange access token, define their base asset, initial capital, and trading intelligence providers.
|
||||
|
||||
* A mobile phone will become a 24/7 trading bot plugged into the Superalgos Network, receiving trading signals and firing orders on any exchange.
|
||||
|
||||
* Similar to a bitcoin wallet, anyone will be able to develop Superalgos Mobile Apps to consume trading signals. This open competition will be a race to the best UX possible.
|
||||
|
||||
* Crypto wallets and trading apps will plug into the Superalgos Network and consume real-time trading intelligence for free.
|
||||
|
||||
## The Superalgos Project does not sell tokens
|
||||
|
||||
The protocol distributes Superalgos (SA) Tokens after each software release, among contributors of that release. If you wish to mine tokens, you may start contributing anytime. You may also hire/sponsor someone (usually a developer or trader) to do it on your behalf.
|
||||
|
||||
# Software Architecture
|
||||
|
||||
Superalgos features these 3 main components:
|
||||
Superalgos features three main components:
|
||||
|
||||
1. **Superalgos Platform:** An already functional set of tools designed for algo-traders for automating their own trading and producing trading-signals.
|
||||
1. **Superalgos Platform:** A set of tools designed for algo-traders to design, build, test, and deploy trading bots and produce trading signals. The platform has been trading live since mid-2020 and is virtually ready to go out of beta.
|
||||
|
||||
2. **Superalgos Mobile:** An under-development mobile app reference implementation that consumes existing trading intelligence to automate trading.
|
||||
|
||||
2. **Superalgos Mobile:** An under-development mobile app reference implementation for cosuming real-time trading intelligence and automate users trading.
|
||||
3. **Superalgos Network:** An under-development open p2p network for distributing trading intelligence from providers (algo-traders) to consumers (the project's user base).
|
||||
|
||||
|
||||
3. **Superalgos Network:** An under-development open p2p network for distributing real-time trading intelligence between producers (algo-traders) and consumers (the project's user base).
|
||||
|
||||
|
||||
All of the above is / will be hosted in this repository.
|
||||
All of the above is or will be hosted in this repository.
|
||||
|
||||
# Superalgos is User-centric
|
||||
|
||||
* No ads, anywhere.
|
||||
* No sign up / logins.
|
||||
|
||||
* No sign-up / logins.
|
||||
|
||||
* No user/usage data collection of any kind.
|
||||
|
||||
* No user trading information collected or sold.
|
||||
|
||||
* Runs 100% on uncompiled code anyone can read and audit.
|
||||
|
||||
# Superalgos Development Pipeline
|
||||
|
||||
* **Superalgos P2P Network:** will allow algo-traders to share trading signals with Superalgos users consuming these signals via a mobile app.
|
||||
* **Real-time Trading Signals:** will allow users to emit trading signals and be rewarded with SA Tokens.
|
||||
* **Superalgos P2P Network:** Will allow the project to distribute trading intelligence produced by algo-traders.
|
||||
|
||||
* **Trading Signals:** Will allow providers to broadcast trading signals and be rewarded with SA Tokens.
|
||||
|
||||
* **Superalgos Mobile:** Will allow users to consume trading signals for free and autonomously execute trades from their mobile phones.
|
||||
|
||||
* **Ethereum Integration:** Will allow mining data from an Ethereum network node, and bring it into the Superalgos workflow.
|
||||
|
||||
# What is the Superalgos Platform?
|
||||
|
||||
@@ -31,6 +31,8 @@ exports.newMultiProject = function () {
|
||||
projectInstance.processModules = {}
|
||||
projectInstance.botModules = {}
|
||||
|
||||
if (projectDefinition.TS === undefined) { continue }
|
||||
|
||||
/* Set up Utilities of this Project */
|
||||
if (projectDefinition.TS.utilities !== undefined) {
|
||||
for (let j = 0; j < projectDefinition.TS.utilities.length; j++) {
|
||||
|
||||