Skip to content

Instantly share code, notes, and snippets.

@QuasarChains
Created September 23, 2023 04:42
Show Gist options
  • Save QuasarChains/d9dd7a4c256487f02fd3615cef9ef496 to your computer and use it in GitHub Desktop.
Save QuasarChains/d9dd7a4c256487f02fd3615cef9ef496 to your computer and use it in GitHub Desktop.
GC POAP
<!DOCTYPE html>
<html>
<head>
<title>Gamechanger Attendance NFT</title>
<link rel="stylesheet" href="index.css" />
<link rel="icon" type="image/x-icon" href="./favicon.ico">
<script type="text/javascript" src="https://unpkg.com/json-url@2.3.1/dist/browser/json-url.js"></script>
<script src="https://cdn.jsdelivr.net/gh/ethereumjs/browser-builds/dist/ethereumjs-tx/ethereumjs-tx-1.3.3.min.js"></script>
</head>
<body>
<div class="flex-container">
<div>
<h1>Gamechanger - Cardano over coffee</h1>
<h2>Proof of attendance NFT</h2>
<div id='nft-svg'><svg viewBox="0 0 800 400">
<path id="bg" d="M 0 0 H 800 V 400 H 0 Z" fill='url("#bgG")' stroke="none"/>
<path id="NFT" d="M 20 50 C 40 40, 40 20, 650 60" fill="none" stroke-width="15" stroke='url("#NFTG")' stroke-linecap="round"></path>
<defs><linearGradient id="NFTG"><stop id="NFTg0" stop-color="hsl(276, 100%, 50%)" offset="0"></stop>
<stop id="NFTg1" stop-color="hsl(247, 100%, 50%)" offset="1"></stop></linearGradient>
<linearGradient id="bgG"><stop id="BGg0" stop-color="hsl(247, 100%, 50%)" offset="0"></stop>
<stop id="BGg1" stop-color="hsl(276, 100%, 50%)" offset="1"></stop></linearGradient></defs>
<path fill="none" stroke="#000000" stroke-width="20" stroke-dasharray="none" stroke-opacity="1" d="m 385, 162 h -169 v 75 h 159 V 200 H 270"/>
<path fill="none" stroke="#000000" stroke-width="20" stroke-dasharray="none" stroke-opacity="1" d="M 593,162 h -169 v 75 h 169"/>
</svg></div>
<h2 class="donation">Make a donation to the team. Move the slider</h2>
<div class="slidecontainer">
<input type="range" min="1" max="1000" value="3" class="slider" id="myRange"
oninput="dragRange(this.value)">
<input type="text" id="amountInput" class="amountInput" value="3" onchange="changeAmount(this.value)">
<div id="denomination" class="denomination">ADA</div>
</div>
<button class="button" onclick="MakeGcScript()">Generate NFT transaction link</button>
<div id="linkDiv" class="link"><a id="poapLink" target=”_blank” href="https://gamechanger.finance/">Click this link to start the transaction</a></div>
<h3>Checkout the code and experiment</h3>
<a target=”_blank” href="https://codepen.io/M2tec/pen/LYggbRq">M2tec dApp codepen</a></div>
</div>
</div>
<script src="./index.js"></script>
</body>
</html>
function formatPoints(points, close) {
points = [...points];
if (!Array.isArray(points[0])) {
points = points.map(({ x, y }) => [x, y]);
}
if (close) {
const lastPoint = points[points.length - 1];
const secondToLastPoint = points[points.length - 2];
const firstPoint = points[0];
const secondPoint = points[1];
points.unshift(lastPoint);
points.unshift(secondToLastPoint);
points.push(firstPoint);
points.push(secondPoint);
//console.log(points)
}
return points.flat();
}
function spline(points = [], tension = 1, close = false, cb) {
points = formatPoints(points, close);
const size = points.length;
const last = size - 4;
const startPointX = close ? points[2] : points[0];
const startPointY = close ? points[3] : points[1];
let path = "M" + [startPointX, startPointY];
cb && cb("MOVE", [startPointX, startPointY]);
const startIteration = close ? 2 : 0;
const maxIteration = close ? size - 4 : size - 2;
const inc = 2;
for (let i = startIteration; i < maxIteration; i += inc) {
const x0 = i ? points[i - 2] : points[0];
const y0 = i ? points[i - 1] : points[1];
const x1 = points[i + 0];
const y1 = points[i + 1];
const x2 = points[i + 2];
const y2 = points[i + 3];
const x3 = i !== last ? points[i + 4] : x2;
const y3 = i !== last ? points[i + 5] : y2;
const cp1x = x1 + ((x2 - x0) / 6) * tension;
const cp1y = y1 + ((y2 - y0) / 6) * tension;
const cp2x = x2 - ((x3 - x1) / 6) * tension;
const cp2y = y2 - ((y3 - y1) / 6) * tension;
path += "C" + [cp1x, cp1y, cp2x, cp2y, x2, y2];
cb && cb("CURVE", [cp1x, cp1y, cp2x, cp2y, x2, y2]);
}
return path;
}
function generateRandomIntegerInRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function generatePoints(amount) {
points = []
yscale = 45 + 345 * ( parseInt(amount)/1000)
for (var i=1;i<=6; i++) {
x1 = generateRandomIntegerInRange(10, 790)
y1 = 400 - generateRandomIntegerInRange(20, yscale)
point = [x1, y1]
points.push(point)
}
return points
}
function makeShape() {
let newAmount = document.getElementById('amountInput').value;
z = generatePoints(newAmount)
const path = spline(z, 1, false)
const nftPath = document.getElementById("NFT");
nftPath.attributes.d.value = path
updateGradient(newAmount)
}
makeShape();
function updateGradient(newAmount) {
// Line color
scaleValue = 50 + 50 * newAmount/1000
color_purple = "hsl(276," + scaleValue + "%,60%)"
scaleValue = 50 + 50 * newAmount/1000
color_blue = "hsl(243," + scaleValue + "%,60%)"
const bgGradient0 = document.getElementById("NFTg0");
bgGradient0.style.stopColor = color_purple;
const bgGradient1 = document.getElementById("NFTg1");
bgGradient1.style.stopColor = color_blue;
// Background color
scaleValue = 20 + 80 * newAmount/1000
color_purple = "hsl(276," + scaleValue + "%,50%)"
scaleValue = 20 + 80 * newAmount/1000
color_blue = "hsl(243," + scaleValue + "%,50%)"
const bgGradient2 = document.getElementById("BGg0");
bgGradient2.style.stopColor = color_blue;
const bgGradient3 = document.getElementById("BGg1");
bgGradient3.style.stopColor = color_purple;
}
function dragRange(newVal) {
let amountField = document.getElementById('amountInput');
amountField.value = newVal;
makeShape()
}
function changeAmount(newVal) {
let myRange = document.getElementById('myRange');
myRange.value = newVal;
makeShape()
}
//auxiliar function: Splits a buffer into a list of buffers
function bufferIntoBufferChunks(data, max){
if(max <= 0) throw new Error('cannot split into zero (or smaller) length buffers')
if(data.length <= max)
return [data]
var out = [], len = 0
while(len < data.length) {
out.push(data.slice(len, Math.min(len + max, data.length)))
len += max
}
return out
}
//Auxiliar function. Works with unicode chars, can be tested against LoremIpsumTransactum demo
function str2ArrayOfStr(str, size) {
if(!str)
return [];
const chunks = bufferIntoBufferChunks(ethereumjs.Buffer.Buffer.from(str),size).map(buffer=>buffer?.toString());
return chunks;
}
//Turns a string into a "metadata string"
function str2metadataStr(str, size=64) {
if(!str)
return "";
const chunks=str2ArrayOfStr(str,size);
if(chunks.length===1)
return chunks[0]
else
return chunks
}
//Turns a "metadata string" into the former string
function metadataStr2Str(strOrArray) {
if(!strOrArray)
return ""
if (Array.isArray(strOrArray))
return strOrArray.join("");
else
return strOrArray;
}
function MakeGcScript() {
const nftSvg = document.getElementById("nft-svg").innerHTML;
base64Svg = btoa(nftSvg)
splitSvg = str2metadataStr("data:image/svg+xml;base64," + base64Svg)
//console.log(splitSvg)
const link = document.getElementById("poapLink");
const code = {
"type": "tx",
"ttl": 86400,
"title": "Proof of Attendance GC - Cardano over coffee",
"description": "",
"outputs": {
"addr_test1qzwg9p0zw6au40nwls803mx9lfeaxjfxy9p6el25r3nctjnp6ydulqht6r9z4ld0jms3a3c7gw45u32vhc2ftdp2f6rq57a9g2": [
{
"quantity": "2000000",
"policyId": "ada",
"assetName": "ada"
}
]
},
"mints": [
{
"script": {
"issuers": [
{
"accountIndex": 0,
"addressIndex": 0
}
],
"beforeSlotOffset": 90000
},
"assets": [
{
"assetName": "GC-POAP-COFFEE",
"quantity": "1"
}
]
}
],
"metadata": {
"721": {
"0": {
"GC-POAP-COFFEE": {
"author": "GC",
"name": "GC-POAP",
"image": "data:image/svg+xml;base64",
"mediaType": "image/svg+xml",
}
}
}
}
}
let amountRange = document.getElementById('myRange');
lovelace_donation = parseInt(amountRange.value) * 1000000
//console.log(lovelace_donation)
address = Object.keys(code.outputs)[0]
code.outputs[address][0]["quantity"] = lovelace_donation
code.metadata['721']['0']['GC-POAP-COFFEE']['image'] = splitSvg
//console.log(code)
//console.log(code.metadata['721']['0']['GC-POAP-COFFEE'])
//console.log(code.outputs)
const lib = JsonUrl('lzw'); // JsonUrl is added to the window
//generates the URL that is packed with the script
lib.compress(code)
.then(gcscript => {
link.href = "https://preprod-wallet.gamechanger.finance/api/1/tx/" + gcscript;
})
.catch(err => {
link.innerHTML = "Error: " + err.message;
});
const linkDiv = document.getElementById("linkDiv")
linkDiv.style.visibility = 'visible'
}
body {
background-color: #191c24;
font-family: Arial, Helvetica, sans-serif;
height: 100%;
color:#f9f9f9;
}
h1 {
display: flex;
justify-content: center;
margin-top: 50px;
margin-bottom: 5px;
}
h2 {
display: flex;
justify-content: center;
margin-top:10px;
margin-bottom: 40px;
}
.donation {
margin-top:80px;
}
input[type=text] {
padding: 12px 20px;
margin: 0 10px;
border-radius: 5px;
border: 2px solid #000000;
background-color: #6c7293;
color:#f9f9f9;
font-size: large;
font-weight: bold;
}
.button {
background-color: #191c24;
color: #6c7293;
border: 2px solid #6c7293;
width: 800px;
height: 100px;
font-size: 25px;
font-weight: bold;
border-radius: 3px;
}
a {
color: white;
font-size: 30px;
}
.link {
padding: 50px;
visibility: hidden;
display: flex;
justify-content: center;
}
.button:hover {
background-color: #0f1015; /* Green */
color: white;
}
.flex-container {
display: flex;
justify-content:center;
width: 100%;
}
.slider {
width: 100%;
}
.slidecontainer {
margin-top: 30px;
margin-bottom: 30px;
display: flex;
}
.amountInput {
width: 100px;
text-align: right;
margin-left: 30px;
}
.denomination {
width: 70px;
display:flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: white;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment