Settings

Blockchain
Network
Unit
Language
Theme
Sound New Block

Transaction

5af0c4fd0e000e495e47f931c971aa342f1a8afce41cc6f23a0bb094caad033c
Timestamp (utc)
2021-05-26 17:11:22
Fee Paid
0.00008462 BSV
(
0.00438376 BSV
-
0.00429914 BSV
)
Fee Rate
504.4 sat/KB
Version
1
Confirmations
297,898
Size Stats
16,774 B

3 Outputs

Total Output:
0.00429914 BSV
  • jrun cryptofightsM@{"in":0,"ref":["8274e9df5e9eecd7521765fb31b91c903cf6c1e35824db61c37735c06f520a4a_o1","472b1979b21826d790004aba1cfa114d9c924d05c57d0a2de11800bd06550951_o1","061794f23a21f2d4f65b73512757be2927494acc42b1df875cce6d29b67d6fb5_o1","9165f35def20216c4ff96cdd3860672e83b672d7043678b8657332929807057a_o1","d89de2885558914c6df84a981c4bafdda2f3b30f94b9dd89449eb66c1f8f3c1f_o1","9593d4e5a149c9772c406fdc90a0fbabf8cad4fa6af953263e01b502e9dda026_o1","bae0ac544aa9f54857090d427510207a9a9a353d202558ad96cb2eeb23960ee8_o1","0388093d0fbe67cbf69791185954954519e087750836a38c57b5041ca4e032a9_o1","b6bd42104afa8669284e0e600b01d65752ed45010bbac4366eb8cf68ad21df2c_o1","ea9ac349faaaffd00c377bea089a2e445f58e257c5faa45870d43b95c44a9833_o1"],"out":["9e3641c9c0426f9e1a35fb5467649e721d0953c7a84bc0805ebbdeabe608d89b"],"del":[],"cre":["n2Bd4cWhEQK1aVjb1R7EBGV9mrw3etvSdC"],"exec":[{"op":"DEPLOY","data":["class ClientAgent extends Agent {\n async init() {\n this.jigHandlers.set(Fighter.origin, this.onFighter);\n this.jigHandlers.set(FyxItem.origin, this.onItem);\n\n this.messageHandlers.set('BattleFound', () => this.emit('client', 'BattleFound'));\n this.messageHandlers.set('BattleCreated', this.onBattleCreated);\n this.messageHandlers.set('BattleUpdated', this.onBattleUpdated);\n this.messageHandlers.set('BattleCompleted', this.onBattleCompleted);\n this.messageHandlers.set('ActionError', this.onActionError);\n this.messageHandlers.set('ExitQueue', this._exitQueue);\n this.messageHandlers.set('SignBattle', this.signBattle);\n this.messageHandlers.set('QueueStatus', this._queueStatus);\n this.messageHandlers.set('Requeue', this._enqueue);\n\n this.eventHandlers.set('Act', this.Act);\n this.eventHandlers.set('EnterQueue', this.EnterQueue);\n this.eventHandlers.set('ExitQueue', this.ExitQueue);\n this.eventHandlers.set('Forfeit', this.Forfeit);\n this.eventHandlers.set('SimulateFighterState', this.SimulateFighterState);\n this.eventHandlers.set('SimulateFightersState', this.SimulateFightersState);\n this.eventHandlers.set('GetItems', this.GetItems);\n this.eventHandlers.set('GetLastBattleUpdated', this.GetLastBattleUpdated);\n \n this.eventHandlers.set('LevelUp', this.LevelUp);\n\n const url = `${Config.baseUrl}/cryptofights/lobbies`;\n console.log(`Fetching lobbies: ${url}`);\n const {data: lobbies} = await this.lib.axios(url);\n this.lobbies = lobbies;\n console.log(`Lobbies: ${JSON.stringify(this.lobbies)}`);\n\n this.battle = {};\n this.battleUpdates = {};\n this.emit('subscribe', 'QueueStatus');\n }\n\n onFighter(fighter) {\n this.emit('client', 'FighterUpdated', fighter.toObject());\n }\n\n onItem(item) {\n this.emit('client', 'ItemUpdated', item.toObject());\n }\n\n async onBattleCreated(message) {\n const { id, origin } = message.payloadObj;\n if(!this.battle || id !== this.battle.id) return;\n delete this.queueMessage;\n\n const { data: battleData } = await this.lib.axios(`${Config.baseUrl}/battles/${origin}`);\n console.log(`BattleCreated: ${JSON.stringify(battleData)}`);\n \n // const battle = await this.wallet.loadJig(origin);\n // this.emit('client', 'BattleCreated', battle.toObject());\n // await battle.sync();\n if(this.battleUpdates[battleData.id]) {\n this.battleUpdates[battleData.id].forEach((state) => {\n if(!state) return;\n this.updateBattle(state);\n });\n }\n \n }\n\n _queueStatus(message) {\n this.emit('client', 'QueueStatus', message.payload);\n }\n\n async onBattleUpdated(message) {\n console.log(`BattleUpdated: ${message.payload}`);\n const state = message.payloadObj;\n\n if(!this.battle || state.battleId !== this.battle.id) return; \n this.updateBattle(state);\n }\n\n updateBattle(state) {\n console.log('updateBattle', JSON.stringify(state));\n this.battle.states[state.turnCount] = state;\n if(state.turnCount <= this.battle.turnCount) return;\n if(this.battleUpdates[state.battleId]) {\n this.battleUpdates[state.battleId] = [];\n }\n this.battleUpdates[state.battleId][state.turnCount] = state;\n this.battle.turnCount = state.turnCount;\n this.battlePromise = this.wallet.loadJig(state.location);\n this.emit('client', 'BattleUpdated', state);\n }\n\n async onBattleCompleted(message) {\n const { origin } = message.payloadObj;\n // const battleData = message.payloadObj;\n await this.addToQueue(async () => {\n const { data: battleData} = await this.lib.axios(`${Config.baseUrl}/battles/${origin}`);\n \n if(battleData.victor.userId === this.wallet.handle) {\n const battle = await this.wallet.loadJig(battleData.location);\n const { fighter } = battle.victor;\n await fighter.sync();\n fighter.recordVictory(battle);\n await fighter.sync();\n this.onFighter(fighter);\n }\n delete this.battle;\n \n this.emit('client', 'BattleCompleted', battleData);\n console.log(`BattleCompleted: ${JSON.stringify(battleData)}`);\n });\n }\n\n async signBattle(message) {\n console.log('signBattle');\n if (!this.queueMessage || !message.context.includes(this.queueId)){\n console.log('Invalid Queue:', this.queueMessage, this.queueId);\n return;\n }\n delete this.queueMessage;\n const { id, rawtx, paths } = message.payloadObj;\n console.log(`Client-Agent - signBattle: id = ${id}, rawtx = ${rawtx}`);\n const { Br, Tx} = this.bsv;\n let tx = this.bsv.Tx.fromHex(rawtx);\n console.log(`Client-Agent - signBattle: tx = ${tx}`);\n const outputs = await Promise.all(tx.txIns.map(async txIn => {\n const txid = new Br(txIn.txHashBuf).readReverse().toString('hex');\n const outTx = Tx.fromHex(await this.blockchain.fetch(txid));\n return {\n location: `${txid}_o${txIn.txOutNum}`,\n script: outTx.txOuts[txIn.txOutNum].script.toString(),\n };\n }));\n console.log('OUTPUTS:', JSON.stringify(outputs, null, 2));\n const t = await this.wallet.loadTransaction(rawtx);\n console.log(`Executed wallet.loadTransaction.`); // Added debug log #1\n this.emit('setDerivations', paths);\n const newRawTx = await t.export({sign: true, pay: false});\n console.log(`Executed t.export.`);// Added debug log #4\n tx = this.bsv.Tx.fromHex(newRawTx);\n console.log(`Executed this.bsv.Tx.fromHex(newRawTx).`);// Added debug log #5\n let sigs = tx.txIns.map(txIn => txIn.scriptVi.toNumber() && txIn.script.toString());\n console.log('SIGS AFTER:', sigs);\n\n this.battle = {\n id,\n turnCount: -1,\n states: [],\n actLocations: new Set()\n };\n console.log('this.battle set', this.battle);\n const sigMessage = this.wallet.buildMessage({\n to: [message.from],\n subject: 'BattleSigned',\n context: [id],\n payload: JSON.stringify({\n id,\n sigs\n })\n });\n await this.blockchain.sendMessage(sigMessage, `${Config.baseUrl}/${Config.fyxId}`);\n }\n\n async Act(request) {\n console.log('Act', JSON.stringify(request));\n const { actionIndex, stateLocation } = request;\n const battle = await this.battlePromise;\n if(!battle) throw new FyxError(400, 'Invalid battle:', stateLocation);\n if(battle.location !== stateLocation) throw new FyxError(400, `Invalid Act State location: ${stateLocation} ${battle.location}`);\n \n if(this.battle.actLocations.has(stateLocation)) {\n console.log('Duplicate act:', stateLocation);\n return;\n }\n this.battle.actLocations.add(stateLocation);\n console.log('Act owner:', battle.actor);\n const {actionToken} = battle;\n if(!actionToken) {\n throw new FyxError(400, `Missing actionToken: ${stateLocation}`);\n }\n await actionToken.sync();\n actionToken.act(actionIndex);\n await actionToken.sync();\n\n const state = await this.blockchain.sendMessage(this.wallet.buildMessage({\n subject: 'Act',\n payload: JSON.stringify({ location: actionToken.location })\n }), `${Config.baseUrl}/${Config.fyxId}`);\n this.updateBattle(state);\n return state;\n }\n\n async onActionError(message) {\n throw new Error(message.payload);\n }\n\n async EnterQueue(request) {\n const rules = this.lobbies[request.lobbyId-1];\n console.log(`RULES: ${JSON.stringify(rules)}`);\n console.log('Loading Fighter:', request.fighterLocation);\n const fighter = await this.wallet.loadJig(request.fighterLocation);\n console.log('Fighter Loaded:', request.fighterLocation);\n if(!fighter) throw new Error('CLIENT: Invalid Fighter');\n console.time('Fighter Sync');\n await fighter.sync({inner: false});\n console.timeEnd('Fighter Sync');\n const items = await Promise.all(request.itemLocations.map(async location => {\n if(!location) return null;\n const item = await this.wallet.loadJig(location);\n if(!item) return;\n console.time(`Item Sync: ${location}`);\n await item.sync({inner: false});\n console.timeEnd(`Item Sync: ${location}`);\n return item;\n }));\n \n if(rules.fee && fighter.satoshis < rules.fee + 273) {\n fighter.setSatoshis(rules.fee + 273);\n await fighter.sync();\n }\n console.log(`Everything Sync'd`);\n\n\n console.log('Build Message');\n this.queueMessage = {\n subject: 'EnterQueue',\n payload: JSON.stringify({\n lobbyId: rules.rulesId,\n fighterLocation: fighter.location,\n itemLocations: items.map(i => i && i.location),\n skills: request.actionIds,\n })\n };\n \n console.log('Message Sent');\n await this._enqueue();\n console.log('Returning');\n return request.lobbyId;\n }\n\n async _enqueue() {\n if(!this.queueMessage) this._exitQueue();\n const message = this.wallet.buildMessage(this.queueMessage);\n this.queueId = message.id;\n console.log('_enqueue:', message.id);\n \n await this.blockchain.sendMessage(\n message,\n `${Config.baseUrl}/${Config.fyxId}`\n );\n this.wallet.setTimeout(async () => this._refreshQueue(message.id), 45000);\n }\n\n async _refreshQueue(queueId) {\n if(this.queueId !== queueId || !this.queueMessage) return;\n try {\n const refreshed = await this.blockchain.sendMessage(\n this.wallet.buildMessage({\n subject: 'RefreshQueue',\n payload: JSON.stringify({queueId})\n }),\n `${Config.baseUrl}/${Config.fyxId}`\n );\n console.log('Refreshed:', refreshed);\n if(refreshed) this.wallet.setTimeout(async () => this._refreshQueue(queueId), 45000);\n else {\n console.log('Queue expired.');\n this.emit('client', 'OnExitQueue', 'Refresh expired');\n }\n } catch(e) {\n console.error('Refresh Queue Error:', e.message);\n }\n }\n\n async ExitQueue() {\n delete this.queueMessage;\n const message = this.wallet.buildMessage({\n subject: 'ExitQueue'\n });\n await this.blockchain.sendMessage(message, `${Config.baseUrl}/${Config.fyxId}`);\n }\n\n async _exitQueue(message) {\n delete this.queueMessage;\n this.emit('client', 'OnExitQueue', message && message.payload);\n if(message && message.payload) {\n this.emit('client', 'Error', message.payload);\n }\n }\n\n async Forfeit() {\n const message = this.wallet.buildMessage({\n subject: 'Forfeit',\n payload: JSON.stringify({ id: this.battle.id })\n });\n console.log(`Forfeit::Sending message ${JSON.stringify(message,null,4)} to blockchain`);\n try {\n await this.blockchain.sendMessage(message, `${Config.baseUrl}/${Config.fyxId}`);\n } catch (e) {\n console.error('Forfeit Error:', e.message);\n }\n console.log(`Forfeit::Sending message completed`);\n }\n \n SimulateFighterState(message) {\n return BattleUtils.simulateFighterState(message);\n }\n\n SimulateFightersState(message) {\n const fighterStates = [];\n message.forEach(f => fighterStates.push(BattleUtils.simulateFighterState(f)));\n return fighterStates;\n }\n\n async GetLastBattleUpdated() {\n if(!this.battleLocation) return;\n const battle = await this.wallet.loadJig(this.battleLocation);\n return battle.getState();\n }\n\n async GetPlayer() {\n console.log('GetPlayer');\n const config = {\n address: this.purse,\n pubkey: this.pubkey,\n owner: this.address,\n userId: this.wallet.handle,\n balance: 0,\n xpTable: {\n cumulativeXp: Constants.LevelUpXP,\n xpPerKill: Battle.LevelXPReward\n },\n lobbiesPerLevel: Constants.LobbiesPerLevel,\n tierPerLobby: Constants.TierPerLobby,\n abilityScoreLevels: Constants.AbilityScoreLevels,\n skillLevels: Constants.SkillLevels,\n skills: Object.entries(Constants.SkillData).map(([k, v]) => {\n if(['location', 'origin', 'owner', 'nonce', 'deps', 'satoshis'].includes(k)) return;\n return {\n ...v,\n skillType: k\n };\n }).filter(x => !!x),\n lobbies: this.lobbies\n };\n\n console.log('Player:', config);\n return config;\n }\n\n async LevelUp(request) {\n const { fighterLocation, ability, skillType } = request;\n let fighter = await this.wallet.loadJig(fighterLocation);\n if(!fighter) throw new Error('Invalid Fighter');\n await fighter.sync();\n\n const {paths, rawtx} = await this.blockchain.sendMessage(this.wallet.buildMessage({\n subject: 'LevelUp',\n payload: JSON.stringify({\n fighterLocation: fighter.location,\n ability,\n skillType\n })\n }), `${Config.baseUrl}/${Config.fyxId}`);\n this.emit('setDerivations', paths);\n\n const t = await this.wallet.loadTransaction(rawtx);\n fighter = t.outputs.find(o => o instanceof Fighter);\n await t.publish({pay: false, sign: true});\n await fighter.sync();\n this.onFighter(fighter);\n return fighter.toObject();\n }\n\n static async preDeploy() {\n ClientAgent.whitelist = [\n ClientAgent.deps.Battle.origin,\n ClientAgent.deps.BattleToken.origin,\n ClientAgent.deps.Fighter.origin,\n ClientAgent.deps.FyxItem.origin,\n ];\n }\n}",{"agentId":"client","deps":{"Agent":{"$jig":0},"Battle":{"$jig":1},"BattleToken":{"$jig":2},"BattleUtils":{"$jig":3},"Config":{"$jig":4},"Constants":{"$jig":5},"Fighter":{"$jig":6},"FyxClass":{"$jig":7},"FyxError":{"$jig":8},"FyxItem":{"$jig":9}},"hash":"7eb7919da8d37e119e3bed447ddff8e9415dcd3f2736a943cea5ec522a781941","sealed":false,"whitelist":["472b1979b21826d790004aba1cfa114d9c924d05c57d0a2de11800bd06550951_o1","061794f23a21f2d4f65b73512757be2927494acc42b1df875cce6d29b67d6fb5_o1","4c0c1ca5a61939bbb442ba67fa79a357f9b8295069d36b585713f7d575667300_o1","ea9ac349faaaffd00c377bea089a2e445f58e257c5faa45870d43b95c44a9833_o1"]}]}]}
    https://whatsonchain.com/tx/5af0c4fd0e000e495e47f931c971aa342f1a8afce41cc6f23a0bb094caad033c