genesis
This commit is contained in:
commit
01fcbbf3fc
1
.txo/txo.txt
Normal file
1
.txo/txo.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
txo:tbtc4:e0a84ec838712ddec78c57a7dc1ce65b777cbf58bfa861f289e3533a60399493:0 10000
|
11
bin/post.sh
Executable file
11
bin/post.sh
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
HASH=$(rad inspect)
|
||||||
|
|
||||||
|
cd /home/melvin/npub.info/pages/multi-hash/"${HASH:4}" || exit
|
||||||
|
|
||||||
|
git pull
|
||||||
|
|
||||||
|
cd - || exit
|
||||||
|
|
||||||
|
/home/melvin/go/bin/nak event -c "deployed" --kind 613 --sec $(git config nostr.privkey) wss://npub.info/ &
|
28
bin/u2.sh
Executable file
28
bin/u2.sh
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
PUBKEY=$(cat nostr.json | jq -r .pubkey)
|
||||||
|
|
||||||
|
echo "[\"REQ\", \"x\", { \"kinds\" : [611], \"limit\" : 0, \"#p\" : [\"${PUBKEY}\"] }]" | websocat -n --ping-interval 20 wss://npub.info | while read -r line; do
|
||||||
|
# Process each line received here
|
||||||
|
echo "Received: $line"
|
||||||
|
|
||||||
|
echo "$line" | jq
|
||||||
|
|
||||||
|
TYPE=$(echo "$line" | jq -r ".[0]")
|
||||||
|
|
||||||
|
echo "type: --${TYPE}--"
|
||||||
|
|
||||||
|
if [ "$TYPE" = "EVENT" ]
|
||||||
|
then
|
||||||
|
echo event
|
||||||
|
bash -x bin/validate.sh
|
||||||
|
|
||||||
|
time bash -x bin/post.sh
|
||||||
|
|
||||||
|
# /home/melvin/go/bin/nak event -c "deployed" --kind 612 --sec $(git config nostr.privkey) wss://npub.info/ &
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
done
|
||||||
|
|
49
bin/validate.sh
Executable file
49
bin/validate.sh
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
EVENT=$(echo '["REQ", "x", { "kinds": [611] }]' | websocat --ping-interval 20 wss://npub.info | tail -2 | head -1)
|
||||||
|
|
||||||
|
ID=$(echo "$EVENT" | jq -r .[2].id)
|
||||||
|
|
||||||
|
echo "$ID"
|
||||||
|
|
||||||
|
CONTENT=$(echo "$EVENT" | jq -r .[2].content)
|
||||||
|
|
||||||
|
echo "$CONTENT"
|
||||||
|
|
||||||
|
echo "$EVENT" | jq -r .[2] > ./contract/calls/"$ID".json
|
||||||
|
|
||||||
|
PROOF=$(echo "$EVENT" | jq -r .[2].tags[0][1])
|
||||||
|
|
||||||
|
echo "$PROOF"
|
||||||
|
|
||||||
|
# check unspent
|
||||||
|
TX=$(echo "$PROOF" | cut -d : -f 5)
|
||||||
|
VOUT=$(echo "$PROOF" | cut -d : -f 6)
|
||||||
|
|
||||||
|
# check keys
|
||||||
|
SPENT=$(curl -sSL "https://mempool.space/testnet4/api/tx/$TX/outspend/${VOUT}" | jq .spent)
|
||||||
|
|
||||||
|
echo SPENT "$SPENT"
|
||||||
|
|
||||||
|
if [ "$SPENT" = 'false' ]
|
||||||
|
then
|
||||||
|
|
||||||
|
/home/melvin/go/bin/nak event -c "accepted" --kind 612 --sec $(git config nostr.privkey) wss://npub.info/ &
|
||||||
|
|
||||||
|
contract/contract.js "$CONTENT"
|
||||||
|
|
||||||
|
~/bin/gitmark/bin/gitmark.sh call-"$ID"
|
||||||
|
|
||||||
|
/home/melvin/go/bin/nak event -c "marked" --kind 612 --sec $(git config nostr.privkey) wss://npub.info/ &
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: spend it
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# jq ".hue = $CONTENT" contract/state.json > .git/state
|
||||||
|
# mv .git/state contract/state.json
|
||||||
|
|
||||||
|
|
216
call.html
Normal file
216
call.html
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="refresh" content="3600" />
|
||||||
|
<title>Ledgr</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 50px auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #3498db;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
width: 95%;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 95%;
|
||||||
|
height: 100px;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container" id="root"></div>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import {
|
||||||
|
html,
|
||||||
|
render,
|
||||||
|
Component
|
||||||
|
} from 'https://unpkg.com/htm/preact/standalone.module.js'
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
const token = params.get('token')
|
||||||
|
const status = ['Click Submit to call contract']
|
||||||
|
if (token) {
|
||||||
|
this.state = { fileContent: token, hue: '', status }
|
||||||
|
}
|
||||||
|
this.state = { fileContent: token, hue: '', status }
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
var file = './nostr.json'
|
||||||
|
var response = await fetch(file) // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file ${file}: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var txt = await response.text()
|
||||||
|
this.setState({ nostrContent: txt }) // Update state with file content
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTextareaChange = event => {
|
||||||
|
this.setState({ fileContent: event.target.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHueChange = event => {
|
||||||
|
this.setState({ hue: event.target.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleButtonClick = async () => {
|
||||||
|
const { fileContent, hue, status, nostrContent } = this.state
|
||||||
|
|
||||||
|
if (!fileContent || !hue) {
|
||||||
|
alert('Both fields must be filled out!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status.push('Processing')
|
||||||
|
this.setState(status)
|
||||||
|
|
||||||
|
// Establish WebSocket connection and send the event
|
||||||
|
const relay = 'wss://npub.info'
|
||||||
|
const ws = new WebSocket(relay)
|
||||||
|
|
||||||
|
status.push('Opening socket to ' + relay)
|
||||||
|
this.setState(status)
|
||||||
|
|
||||||
|
ws.onopen = async () => {
|
||||||
|
status.push('connected to ' + relay)
|
||||||
|
this.setState(status)
|
||||||
|
const message = JSON.stringify({
|
||||||
|
content: 'sethue',
|
||||||
|
data: { fileContent, hue }
|
||||||
|
})
|
||||||
|
var nostr = JSON.parse(nostrContent)
|
||||||
|
var ev = await window.nostr.signEvent({
|
||||||
|
kind: 611,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
tags: [
|
||||||
|
['proof', fileContent],
|
||||||
|
['p', nostr?.pubkey]
|
||||||
|
],
|
||||||
|
content: hue
|
||||||
|
})
|
||||||
|
|
||||||
|
var req = JSON.stringify(['EVENT', ev])
|
||||||
|
ws.send(req)
|
||||||
|
console.log('Message sent:', req)
|
||||||
|
status.push('message sent ' + req)
|
||||||
|
this.setState(status)
|
||||||
|
|
||||||
|
let now = new Date().getTime()
|
||||||
|
now = Math.floor(now / 1000.0)
|
||||||
|
let subscribe = `["REQ", "tail", {"kinds": [612, 613], "since": ${now} }]`
|
||||||
|
// if (qs.pubkey) {
|
||||||
|
// subscribe = `["REQ", "tail", { "authors": ["${qs.pubkey}"], "since": ${now} }]`
|
||||||
|
// }
|
||||||
|
console.log(subscribe)
|
||||||
|
status.push('subscribe ' + subscribe)
|
||||||
|
this.setState(status)
|
||||||
|
ws.send(subscribe)
|
||||||
|
|
||||||
|
// ws.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onmessage = async event => {
|
||||||
|
const json = JSON.parse(event?.data)
|
||||||
|
if (json[0] === 'EOSE') {
|
||||||
|
console.log('EOSE')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (event) {
|
||||||
|
status.push(event?.data)
|
||||||
|
this.setState(status)
|
||||||
|
console.log('event', event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onerror = error => {
|
||||||
|
console.error('WebSocket Error:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional actions can be taken here if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h2>Enter Ecash Token</h2>
|
||||||
|
<textarea
|
||||||
|
value=${this.state.fileContent}
|
||||||
|
onInput=${this.handleTextareaChange}
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<h2>Sethue</h2>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value=${this.state.hue}
|
||||||
|
onInput=${this.handleHueChange}
|
||||||
|
placeholder="Enter hue value (0-360)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button onClick=${this.handleButtonClick}>Submit</button>
|
||||||
|
|
||||||
|
<pre>${this.state.stateContent}</pre>
|
||||||
|
|
||||||
|
<h2>Status</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
|
||||||
|
${this.state.status
|
||||||
|
.map(status =>
|
||||||
|
typeof status === 'object' ? JSON.stringify(status) : status
|
||||||
|
)
|
||||||
|
.map(status => html`${status}<br />`)}
|
||||||
|
|
||||||
|
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(html`<${App} />`, document.getElementById('root'))
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
3
contract/README.md
Normal file
3
contract/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
`sethue` allows you to set a value between 0 and 360 that will be used as the "hue" of the background-color of this website in an HSL formula.
|
||||||
|
|
||||||
|
Be sure to pay at least 1000 sat as the price for having this amazing color-changing opportunity!
|
76
contract/contract.js
Executable file
76
contract/contract.js
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { promises as fs } from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
class SmartContract {
|
||||||
|
constructor() {
|
||||||
|
this.stateFilePath = path.resolve('./contract/state.json')
|
||||||
|
this.state = { hue: 0 }
|
||||||
|
this.loadState()
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadState() {
|
||||||
|
try {
|
||||||
|
const data = await fs.readFile(this.stateFilePath, 'utf-8')
|
||||||
|
this.state = JSON.parse(data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading state:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveState() {
|
||||||
|
try {
|
||||||
|
await fs.writeFile(this.stateFilePath, JSON.stringify(this.state, null, 2))
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving state:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async setHue(call) {
|
||||||
|
if (call.msatoshi < 1000000) {
|
||||||
|
throw new Error('pay at least 1000 sats!')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof call.payload.hue !== 'number') {
|
||||||
|
throw new Error('hue is not a number!')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (call.payload.hue < 0 || call.payload.hue > 360) {
|
||||||
|
throw new Error('hue is out of the 0~360 range!')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.hue = call.payload.hue
|
||||||
|
await this.saveState()
|
||||||
|
|
||||||
|
this.send('86fa35fef8ab4f5906cedfcd966a69e0126973097fd4ea270ddefc505a1a824e', call.msatoshi)
|
||||||
|
}
|
||||||
|
|
||||||
|
send(address, msatoshi) {
|
||||||
|
console.log(`Sending ${msatoshi} msatoshi to ${address}`)
|
||||||
|
// Here you would implement the actual logic to transfer the msatoshi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SmartContract
|
||||||
|
|
||||||
|
let hue = process.argv[2] || 99
|
||||||
|
hue = parseInt(hue)
|
||||||
|
|
||||||
|
const contract = new SmartContract()
|
||||||
|
|
||||||
|
const call = {
|
||||||
|
msatoshi: 1500000, // Example value
|
||||||
|
payload: {
|
||||||
|
hue: hue // Example value within the valid range
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await contract.setHue(call)
|
||||||
|
console.log('Hue set successfully:', contract.state.hue)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message)
|
||||||
|
}
|
||||||
|
})()
|
20
contract/contract.lua
Normal file
20
contract/contract.lua
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
function __init__ ()
|
||||||
|
return {hue=0}
|
||||||
|
end
|
||||||
|
|
||||||
|
function sethue ()
|
||||||
|
if call.msatoshi < 1000000 then
|
||||||
|
error('pay at least 1000 sats!')
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(call.payload.hue) ~= 'number' then
|
||||||
|
error('hue is not a number!')
|
||||||
|
end
|
||||||
|
|
||||||
|
if call.payload.hue < 0 or call.payload.hue > 360 then
|
||||||
|
error('hue is out of the 0~360 range!')
|
||||||
|
end
|
||||||
|
|
||||||
|
contract.state.hue = call.payload.hue
|
||||||
|
contract.send('86fa35a3d26f3c0f332e3e812420057cf0e6cf997c5be1c548066a09c634dafe', call.msatoshi)
|
||||||
|
end
|
1
contract/ledgr.json
Normal file
1
contract/ledgr.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
3
contract/state.json
Normal file
3
contract/state.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"hue": 130
|
||||||
|
}
|
239
index.html
Normal file
239
index.html
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<!-- Refresh every hour (3600 seconds) -->
|
||||||
|
<meta http-equiv="refresh" content="3600" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<title>Ledgr</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import {
|
||||||
|
html, // Import html from htm instead of h
|
||||||
|
render,
|
||||||
|
Component
|
||||||
|
} from 'https://unpkg.com/htm/preact/standalone.module.js'
|
||||||
|
|
||||||
|
import 'https://cdn.skypack.dev/nostrefresh'
|
||||||
|
|
||||||
|
class App extends Component {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.state = { fileContent: '', readmeContent: '' } // Initialize state to store file content
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
try {
|
||||||
|
var response = await fetch('./.txo/txo.txt') // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var txt = await response.text()
|
||||||
|
this.setState({ fileContent: txt }) // Update state with file content
|
||||||
|
|
||||||
|
var file = './nostr.json'
|
||||||
|
var response = await fetch(file) // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file ${file}: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var txt = await response.text()
|
||||||
|
this.setState({ nostrContent: txt }) // Update state with file content
|
||||||
|
|
||||||
|
response = await fetch('./contract/ledgr.json') // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
txt = await response.text()
|
||||||
|
this.setState({ ledgrContent: txt }) // Update state with file content
|
||||||
|
|
||||||
|
response = await fetch('./contract/state.json') // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
txt = await response.text()
|
||||||
|
this.setState({ stateContent: txt }) // Update state with file content
|
||||||
|
|
||||||
|
response = await fetch('./contract/README.md') // Fetch the file
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch text file: ${response.statusText}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
txt = await response.text()
|
||||||
|
this.setState({ readmeContent: txt }) // Update state with file content
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching file:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var lines = this.state.fileContent.split('\n')
|
||||||
|
// Use the html function for creating elements
|
||||||
|
var assets = 0
|
||||||
|
var ledgr
|
||||||
|
var nostr
|
||||||
|
var chain = 'tbtc4'
|
||||||
|
console.log('ledgr', this.state.ledgrContent)
|
||||||
|
if (this.state.ledgrContent) {
|
||||||
|
ledgr = JSON.parse(this.state.ledgrContent)
|
||||||
|
ledgr = Object.entries(ledgr)
|
||||||
|
}
|
||||||
|
if (this.state.nostrContent) {
|
||||||
|
nostr = JSON.parse(this.state.nostrContent)
|
||||||
|
}
|
||||||
|
if (this?.state?.stateContent) {
|
||||||
|
var hue = JSON.parse(this.state.stateContent)
|
||||||
|
console.log('hue', hue.hue)
|
||||||
|
document.body.style.backgroundColor = `hsl(${hue.hue}, 66%, 89%)`
|
||||||
|
}
|
||||||
|
console.log('ledgr', ledgr)
|
||||||
|
var href
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h2>README</h2>
|
||||||
|
<pre>${this.state.readmeContent}</pre>
|
||||||
|
|
||||||
|
<h2>State</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
${this.state.stateContent}
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
|
||||||
|
<h2>Contract</h2>
|
||||||
|
|
||||||
|
<a target="_blank" href="./contract/contract.js">view source</a>
|
||||||
|
<br />
|
||||||
|
<a target="_blank" href="./call.html">call contract</a>
|
||||||
|
|
||||||
|
<h2>Nostr</h2>
|
||||||
|
|
||||||
|
Pubkey: ${nostr?.pubkey}
|
||||||
|
|
||||||
|
<h2>Proofs</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Transaction</th>
|
||||||
|
<th>Reserves</th>
|
||||||
|
<th>Proof</th>
|
||||||
|
<th>Verified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${lines.map((l, i) => {
|
||||||
|
var double = l.split(' ')
|
||||||
|
console.log(double)
|
||||||
|
if (double.length !== 2) return
|
||||||
|
chain = double[0].split(':')[1]
|
||||||
|
assets = double[1]
|
||||||
|
if (chain === 'tbtc4') {
|
||||||
|
href =
|
||||||
|
'https://mempool.space/testnet4/tx/' +
|
||||||
|
double[0].split(':')[2]
|
||||||
|
}
|
||||||
|
if (chain === 'vtc') {
|
||||||
|
href =
|
||||||
|
'https://vtc5.trezor.io/tx/' + double[0].split(':')[2]
|
||||||
|
}
|
||||||
|
return html`<tr>
|
||||||
|
<td>
|
||||||
|
<a target="_blank" href="${href}">${double[0]}</a>
|
||||||
|
</td>
|
||||||
|
<td>${assets}</td>
|
||||||
|
<td><a href="${href}">Proof</a></td>
|
||||||
|
<td>✅</td>
|
||||||
|
</tr>`
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 style="display:none">Reserves</h2>
|
||||||
|
<table style="display:none">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Reserves</th>
|
||||||
|
<th>Chain</th>
|
||||||
|
<th>Proof</th>
|
||||||
|
<th>Verified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>${assets}</td>
|
||||||
|
<td>${chain}</td>
|
||||||
|
<td><a href="${href}">Proof</a></td>
|
||||||
|
<td>✅</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2 style="display:none">Ledgr</h2>
|
||||||
|
|
||||||
|
<table style="display:none">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>User</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Proof</th>
|
||||||
|
<th>Verified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${ledgr?.map((i, l) => {
|
||||||
|
return html`<tr>
|
||||||
|
<td>${i[0]}</td>
|
||||||
|
<td>${i[1]}</td>
|
||||||
|
<td><a href="${href}">Proof</a></td>
|
||||||
|
<td>✅</td>
|
||||||
|
</tr>`
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(html`<${App} />`, document.getElementById('root'))
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
ledgr.json
Normal file
1
ledgr.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
1
nostr.json
Normal file
1
nostr.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"id":"100c04247b3881f4c80615c80abb426ed27f803aa7efef39ae9ff9f8970c63a7","pubkey":"86fa35a3d26f3c0f332e3e812420057cf0e6cf997c5be1c548066a09c634dafe","created_at":1720642724,"kind":30617,"tags":[["d","sethue"],["relays","wss://npub.info/"],["c","txo:tbtc4:e0a84ec838712ddec78c57a7dc1ce65b777cbf58bfa861f289e3533a60399493:0"],["clone","http://git.melvincarvalho.com/smart/32.git"]],"content":"","sig":"0fb78e651f8ebe33a864dd7cf6e0de851220da4de062334e654564ef9db7c5235df7a9f95188769e2a4ec4047c71f6c28cdef0049684f631ac894ecfb8f31081"}
|
Loading…
Reference in New Issue
Block a user