Last active
October 11, 2018 20:47
-
-
Save witoldsz/be9060579b6ec80730f08a85d2c2a145 to your computer and use it in GitHub Desktop.
jedna8 created by witoldsz - https://repl.it/@witoldsz/jedna8
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
const DELEGATE_ADDR = '0x6f673a46f3529a8e0933145dde78d91004a5d944' | |
const TXS_URL = `https://semux.online/v2.1.0/account/transactions?address=${DELEGATE_ADDR}&from=${0}&to=99999` | |
const BURNED_SEM_OWNER = shortHash('0x0d2a67855fae0a04509198d7591f9c09450053cf') | |
const BURNED_SEM_PAID_DATE = new Date('2018-10-10T00:00:00Z') | |
async function main() { | |
const txs = await fetchTxs() | |
const initialState = { | |
stakes: {}, // { owner1: semAmount }, { owner2: semAmount }, …} | |
gains: {}, // { owner1: semAmount }, { owner2: semAmount }, …} | |
} | |
const finalState = txs | |
.reduce((state, tx) => ( | |
isStakeIn(tx) ? stakeInAction(state, tx) | |
: isStakeOut(tx) ? stakeOutAction(state, tx) | |
: isSelfVote(tx) ? selfVoteAction(state, tx) | |
: state | |
), initialState) | |
return { | |
stakesSum: Math.round($objSumValues(finalState.stakes)), | |
gainsSum: Math.round($objSumValues(finalState.gains)), | |
stakes: roundValues(finalState.stakes), | |
gains: roundValues(finalState.gains), | |
} | |
} | |
main().then(console.log, console.warn) | |
// --------------------------------------------------------------- | |
// actions | |
function stakeInAction(state, tx) { | |
const owner = shortHash(tx.from) | |
const amount = nanoToSem(tx.value) | |
const oldStakes = state.stakes | |
const newStakes = { | |
...oldStakes, | |
[owner]: (oldStakes[owner] || 0) + amount | |
} | |
const oldGains = state.gains | |
const newGains = { | |
...oldGains, | |
[owner]: oldGains[owner] || 0, | |
} | |
console.log(`${showDate(tx)},STAKE_IN,${owner},${amount},${showValues(newStakes)}`) | |
return { ...state, stakes: newStakes, gains: newGains } | |
} | |
function stakeOutAction(state, tx) { | |
const recipient = shortHash(tx.to) | |
const amount = nanoToSem(tx.value) | |
const oldStakes = state.stakes | |
const newStakes = { | |
...oldStakes, | |
[recipient]: oldStakes[recipient] - amount, | |
} | |
const oldGains = state.gains | |
const newGains = { | |
...oldGains, | |
[recipient]: oldGains[recipient] - amount, | |
} | |
console.log(`${showDate(tx)},STAKE_OUT,${recipient},${amount},${showValues(newStakes)}`) | |
return { ...state, stakes: newStakes, gains: newGains } | |
} | |
function selfVoteAction(state, tx) { | |
const amount = nanoToSem(tx.value) | |
const oldStakes = state.stakes | |
const totalStake = totalStakeOf(oldStakes, tx) | |
const newStakes = $mapObj( | |
({ key: owner, val: stake }) => stake + gainOf(owner, stake, totalStake, tx), | |
oldStakes | |
) | |
const newGains = $mapObj( | |
({ key: owner, val: ownerGain }) => ownerGain + gainOf(owner, oldStakes[owner], totalStake, tx), | |
state.gains | |
) | |
console.log(`${showDate(tx)},SELF_VOTE,${Math.round(amount)},${showValues(newGains)}`) | |
return { ...state, stakes: newStakes, gains: newGains } | |
} | |
function isStakeIn(tx) { | |
return tx.type === 'VOTE' | |
&& tx.from !== DELEGATE_ADDR | |
&& tx.to === DELEGATE_ADDR | |
} | |
function isStakeOut(tx) { | |
return tx.type === 'TRANSFER' | |
&& tx.from === DELEGATE_ADDR | |
&& tx.to !== DELEGATE_ADDR | |
} | |
function isSelfVote(tx) { | |
return tx.type === 'VOTE' | |
&& tx.from === DELEGATE_ADDR | |
&& tx.to === DELEGATE_ADDR | |
} | |
// --------------------------------------------------------------- | |
// utils | |
function totalStakeOf(stakes, tx) { | |
return $objSumValues(stakes) + dateOf(tx) < BURNED_SEM_PAID_DATE ? 1000 : 0 | |
} | |
function gainOf(owner, stake, totalStake, tx) { | |
const amount = nanoToSem(tx.value) | |
const stake_ = stake + (owner === BURNED_SEM_OWNER && dateOf(tx) < BURNED_SEM_PAID_DATE ? 1000 : 0) | |
return stake_ * amount / totalStake | |
} | |
function roundValues(obj) { | |
return $mapObj(({ val }) => Math.round(val), obj) | |
} | |
function showValues(stakes) { | |
return JSON.stringify(roundValues(stakes)) | |
} | |
async function fetchTxs() { | |
const a = await fetch(TXS_URL) | |
const b = await a.json() | |
return b.result | |
} | |
function dateOf(tx) { | |
return new Date(parseInt(tx.timestamp)) | |
} | |
function showDate(tx) { | |
return dateOf(tx).toISOString().substr(0, 10) | |
} | |
function nanoToSem(nano) { | |
return nano / 1e9 | |
} | |
function shortHash(hash) { | |
return hash.substr(2, 6) | |
} | |
// --------------------------------------------------------------- | |
// libs | |
function $objValues(obj) { | |
return Object.keys(obj).map((k) => obj[k]) | |
} | |
function $mapObj(keyValFn, objIn) { | |
const objOut = {} | |
for (const key in objIn) { | |
const val = objIn[key] | |
objOut[key] = keyValFn({ key, val }) | |
} | |
return objOut | |
} | |
function $objSumValues(obj) { | |
const initialVal = 0 | |
return $objValues(obj) | |
.reduce((v1, v2) => v1 + v2, initialVal) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment