-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Explorer rebuilt for Flask; initial Creator tool
- Loading branch information
Showing
33 changed files
with
1,077 additions
and
248 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# WAXBadges Achievements CREATOR | ||
_A tool for game studios (and anyone else) to create their own WAXBadges achievement ecosystem_ | ||
|
||
|
||
This creator is built as static html/JS that you run locally to create and management your WAXBadges achievements. By running locally we can make some safe-ish security compromises that greatly enhance your workflow speed (i.e. hard-coding your private key for instant transaction signing; normally a MEGA no-no!!). | ||
|
||
|
||
### Getting started: | ||
* Set up your WAX blockchain account | ||
* Create a free WAX All Access account ([account.wax.io](https://account.wax.io)) | ||
* On the Scatter step, opt to generate new keys that are stored in Scatter. We'll need direct access to your private key. | ||
* Fund it with some WAX tokens | ||
* Buy from an exchange and transfer to your WAX account (details are beyond the scope of this doc) | ||
* Purchase some RAM | ||
* Spend WAX to buy RAM in Scatter (how much? A couple hundred kB is fine for starters) | ||
* Download the static html/js files | ||
* Optionally build it from source yourself | ||
* Customize the `local_settings.js` file | ||
* Enter your account's private key | ||
* Enter the associated WAX account name (e.g. abc12.waa) | ||
* Double click the `index.html` to run it as a locally-hosted webpage | ||
|
||
Now that you've hard-coded your private key you must keep these files secure on your local machine. Never upload or host these files on the web! The creator looks and acts like a normal website, but treat it as a tool that you install on your local machine. If anyone else on your team needs access, they'll have to download and customize their own local copy. | ||
|
||
|
||
### Wait, isn't this risky? | ||
I mean, kinda. We're greatly reducing risk by only running this customized javascript on your local computer. But anytime you're directly handling a private key you are absolutely in a danger zone. | ||
|
||
A future enhancement will enable an _authorize-in-Scatter_ option. This will keep your private key in Scatter (or, even better, in a hardware wallet that's connected to Scatter). But as a trade-off you'll have to manually approve every transaction. If you're adding 30 achievements to your new ecosystem it's going to be a pain, though hopefully we'll be able to batch transactions to reduce the number of approvals. | ||
|
||
|
||
### Bonus security | ||
Add a hardware wallet like a Ledger to Scatter and change your WAX account's "owner" key to the hardware wallet key. The steps above risk compromising your WAX account's "active" key but if you retain tight control of the "owner" key, you can always generate a new "active" key for your account. | ||
|
||
|
||
|
||
## Building from source | ||
Grab the `npm` modules: | ||
``` | ||
npm init | ||
npm install | ||
``` | ||
|
||
Build for dev: | ||
``` | ||
npm run dev | ||
``` | ||
|
||
Run locally with Hot Module Replacement: | ||
``` | ||
webpack-dev-server --hot --host 0.0.0.0 | ||
``` | ||
|
||
Build minified production payload: | ||
``` | ||
npm run build | ||
``` | ||
|
File renamed without changes.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
let $ = require("jquery"); | ||
|
||
import { Api, JsonRpc, RpcError } from 'eosjs'; | ||
import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'; | ||
|
||
let PageOverlay = require("./pageoverlay"); | ||
var pageoverlay; | ||
|
||
|
||
var rpc = new JsonRpc('https://chain.wax.io'); | ||
var api; | ||
var signatureProvider; | ||
|
||
|
||
let CONTRACT = 'waxbadgesftw'; | ||
|
||
|
||
async function renderIndex() { | ||
console.log(ACCOUNT_NAME); | ||
|
||
pageoverlay.initPageOverlay($("#add_ecosys_container")); | ||
$("#add_ecosys_button").click(function() { | ||
console.log("click"); | ||
pageoverlay.showPageOverlay($("#add_ecosys_container")); | ||
}); | ||
|
||
$("#add_ecosys_submit_button").click(function() { | ||
let name = $("#add_ecosys_name").val(); | ||
let description = $("#add_ecosys_description").val(); | ||
let website = $("#add_ecosys_website").val(); | ||
let assetbaseurl = $("#add_ecosys_assetbaseurl").val(); | ||
let logoassetname = $("#add_ecosys_logoassetname").val(); | ||
|
||
if (name == "") { | ||
alert("ecosystem name is required!"); | ||
return; | ||
} | ||
if (website != "" && (!website.startsWith('http://') && !website.startsWith('https://'))) { | ||
alert("website should begin with 'http' or 'https'"); | ||
return; | ||
} | ||
if (website == "" && assetbaseurl != "") { | ||
alert("website is required if assetbaseurl is specified!"); | ||
return; | ||
} | ||
|
||
(async () => { | ||
const result = await api.transact( | ||
{ | ||
actions: [{ | ||
account: CONTRACT, | ||
name: 'addecosys', | ||
authorization: [{ | ||
actor: ACCOUNT_NAME, | ||
permission: 'active', | ||
}], | ||
data: { | ||
ecosystem_owner: ACCOUNT_NAME, | ||
ecosystem_name: name, | ||
description: description, | ||
website: website, | ||
assetbaseurl: assetbaseurl, | ||
logoassetname: logoassetname | ||
}, | ||
}] | ||
}, | ||
{ | ||
blocksBehind: 3, | ||
expireSeconds: 30, | ||
} | ||
); | ||
|
||
console.dir(result); | ||
})(); | ||
|
||
}); | ||
|
||
|
||
const resp = await rpc.get_table_rows({ | ||
json: true, // Get the response as json | ||
code: CONTRACT, // Contract that we target | ||
scope: CONTRACT, // Account that owns the data | ||
table: 'ecosystems', // Table name | ||
index_position: 2, // Table secondary key index | ||
key_type: 'i64', // Secondary index type | ||
lower_bound: ACCOUNT_NAME, // Table secondary key value | ||
upper_bound: ACCOUNT_NAME, // Table secondary key value | ||
limit: 10, // Maximum number of rows that we want to get | ||
}); | ||
|
||
console.log(resp.rows); | ||
|
||
for(var i=0; i < resp.rows.length; i++) { | ||
var ecosystem = resp.rows[i]; | ||
$("#page_index").find(".ecosystems_list").append("<div><a href='/ecosys/" + ecosystem.key + "'>" + ecosystem.name + "</a></div>"); | ||
} | ||
|
||
$("#page_index").show(); | ||
} | ||
|
||
|
||
|
||
// ecosys.html | ||
async function renderEcosys(key) { | ||
const resp = await rpc.get_table_rows({ | ||
json: true, // Get the response as json | ||
code: CONTRACT, // Contract that we target | ||
scope: CONTRACT, // Account that owns the data | ||
table: 'ecosystems', // Table name | ||
lower_bound: key, | ||
upper_bound: key, | ||
limit: 1, // Maximum number of rows that we want to get | ||
}); | ||
|
||
console.log(resp.rows); | ||
|
||
if (resp.rows.length == 0) { | ||
window.location.href = "/"; | ||
return; | ||
} | ||
|
||
var ecosystem = resp.rows[0]; | ||
document.title = ecosystem.name + " | WAXBadges Achievements Explorer" | ||
$("meta[property='og:title']").attr("content", ecosystem.name + " | WAXBadges Achievements Explorer"); | ||
$("meta[property='og:description']").attr("content", ecosystem.description); | ||
$("meta[name='twitter:card'][content='summary']").text(ecosystem.description); | ||
$("#ecosystem_name").text(ecosystem.name); | ||
$("#ecosystem_website").append("<a href='" + ecosystem.website + "' target='_new'>" + ecosystem.website + "</a>"); | ||
$("#ecosystem_description").text(ecosystem.description); | ||
|
||
for (var i=0; i < ecosystem.categories.length; i++) { | ||
let category = ecosystem.categories[i]; | ||
console.log(category); | ||
|
||
let $cat_template = $(".category_template").clone().appendTo("#category_list"); | ||
$cat_template.attr("id", "cat_" + i); | ||
$cat_template.find(".cat_name").text(category.name); | ||
$cat_template.show(); | ||
|
||
for (var j=0; j < category.achievements.length; j++) { | ||
let achievement = category.achievements[j]; | ||
console.log(achievement); | ||
let $ach_template = $(".achievement_template").first().clone(); | ||
$ach_template.insertBefore($cat_template.find('.ach_list .clearfix')); | ||
$ach_template = $ach_template.attr("id", "cat_" + i + "_ach_" + j); | ||
$ach_template.find(".ach_name").text(achievement.name); | ||
$ach_template.find(".ach_asset").attr("src", "//" + ecosystem.assetbaseurl + "/" + achievement.assetname); | ||
|
||
if (achievement.maxquantity != "0") { | ||
$ach_template.find(".ach_quantity").text("max: " + achievement.maxquantity); | ||
} else { | ||
$ach_template.find(".ach_quantity").text("unlimited"); | ||
} | ||
|
||
$ach_template.find(".ach_description").text(achievement.description); | ||
$ach_template.show(); | ||
} | ||
} | ||
|
||
$("#ecosystem_container").show(); | ||
} | ||
|
||
|
||
|
||
$(document).ready(function() { | ||
|
||
signatureProvider = new JsSignatureProvider([PRIVATE_KEY]); | ||
api = new Api({ rpc, signatureProvider }); | ||
|
||
$(".account_name").text(ACCOUNT_NAME); | ||
|
||
pageoverlay = new PageOverlay(); | ||
|
||
let pathParts = window.location.pathname.split('/', 3); | ||
let page = pathParts[1]; | ||
var param; | ||
if (page != "") { | ||
param = parseInt(pathParts[2]); | ||
} | ||
if (page == 'ecosys') { | ||
renderEcosys(param); | ||
} else { | ||
renderIndex(); | ||
} | ||
|
||
}); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
let $ = require("jquery"); | ||
|
||
|
||
class PageOverlay { | ||
constructor() { | ||
const style = ` | ||
<style> | ||
.page_overlay { | ||
display: none; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
background-color: rgba(0,0,0, 0.75); | ||
text-align: center; | ||
z-index: 20; | ||
} | ||
.page_overlay_popup { | ||
display: none; | ||
opacity: 0.0; | ||
margin: 0 auto; | ||
max-width: 650px; | ||
text-align: center; | ||
border-radius: 3em; | ||
border: 5px solid #6cc7cc; | ||
background-color: #eee; | ||
padding: 0.5em; | ||
padding-bottom: 1.5em; | ||
z-index: 30; | ||
} | ||
</style> | ||
`; | ||
const content = ` | ||
<div class="page_overlay" id="page_overlay"> | ||
<div class="page_overlay_popup" id="page_overlay_popup"> | ||
<div id="page_overlay_popup_content"></div> | ||
<!--div class="float_right"><div id="page_overlay_popup_cancel_button" class="stylized_button stylized_button_tiny">cancel</div></div--> | ||
<br/> | ||
<div class="clear-both"></div> | ||
</div> | ||
</div> | ||
`; | ||
document.head.insertAdjacentHTML('beforeend', style); | ||
document.body.insertAdjacentHTML('beforeend', content); | ||
} | ||
|
||
initPageOverlay(content_selector) { | ||
// Transfer the content to a new hidden div | ||
var $holder = $("<div/>").hide().appendTo("body"); | ||
$(content_selector).appendTo($holder); | ||
|
||
// Make sure the content will be visible, even though it'll still be hidden in its parent div. | ||
$(content_selector).show(); | ||
} | ||
|
||
|
||
showPageOverlay(content_selector) { | ||
// Transfer the content to the popup overlay div | ||
$(content_selector).appendTo($("#page_overlay_popup_content")); | ||
$("#page_overlay").show(); | ||
|
||
var top_position = (window.innerHeight/2) - $("#page_overlay_popup").height(); | ||
if (top_position < 20) { top_position = 20; } | ||
$("#page_overlay_popup").css({ | ||
"position": "relative", | ||
"display": "block", | ||
"top": top_position, | ||
}); | ||
|
||
window.scrollTo(0, 0); | ||
$("#page_overlay_popup").animate({opacity:1.0}, 500); | ||
} | ||
|
||
|
||
hidePageOverlay() { | ||
// Transfer the content back into a holder div | ||
this.initPageOverlay($("#page_overlay_popup_content").children()); | ||
|
||
$("#page_overlay").hide(); | ||
$("#page_overlay_popup").css({opacity:0.0}); | ||
} | ||
|
||
} | ||
|
||
|
||
module.exports = PageOverlay |
Oops, something went wrong.