Settings

Blockchain
Network
Unit
Language
Theme
Sound New Block

Transaction

03f06751672ce200efbec91c14df7fd696e6a433edbaf98a4d46f5142d55d441
Timestamp (utc)
2020-09-24 15:10:51
Fee Paid
0.00006838 BSV
(
0.00126531 BSV
-
0.00119693 BSV
)
Fee Rate
500 sat/KB
Version
1
Confirmations
340,213
Size Stats
13,674 B

4 Outputs

Total Output:
0.00119693 BSV
  • jrunMP4{"in":0,"ref":["native://Jig"],"out":["bdf20396bfd61d841476da5f5376984956f43a655224e2ad747e295cf6d9a0b1","706efe061411d5810db64b76e5be3cc3230a98c5afe74e52226bf44d095bdf88"],"del":[],"cre":["mpGejheEaTfJ4nuoVt5t9poKrmVgSFciJD","mpGejheEaTfJ4nuoVt5t9poKrmVgSFciJD"],"exec":[{"op":"DEPLOY","data":["class TokenContract extends Jig {\n //\n // with RUN 0.6 preview version \n //\n init(timestamp, ...tokens) {\n this.classname = \"TokenContract: \";\n const function_id = this.classname + \"init(): \"; // The base Token class cannot be created on its own\n\n if (Object.getPrototypeOf(this.constructor) === Jig) {\n throw new Error(function_id + 'must be extended');\n }\n\n this._checkTimestamp(timestamp); // important to check here because we can't do it in static functions\n // Case: Combine\n\n\n if (caller == null) {\n //called by user\n const function_id_combine = function_id + \" combine : \";\n\n try {\n if (!Array.isArray(tokens) || tokens.length < 2) {\n throw new Error(function_id_combine + \"Invalid tokens to combine : \", tokens);\n } // Each token to combine must all be of this type\n\n\n if (tokens.some(token => token.constructor !== this.constructor)) {\n throw new Error(function_id_combine + \"Cannot combine different token classes\");\n } // Check for duplicate tokens in the array\n\n\n const countOf = token => tokens.reduce((count, next) => next === token ? count + 1 : count, 0);\n\n if (tokens.some(token => countOf(token) > 1)) throw new Error(function_id_combine + \"Cannot combine duplicate tokens\"); // Destroy each token, absorbing it into this one\n\n this.amount = 0;\n var oldest_mint_count = null;\n tokens.forEach(token => {\n this.amount += token.amount;\n if (oldest_mint_count == null || token.oldest_mint_count < oldest_mint_count) oldest_mint_count = token.oldest_mint_count;\n token.destroy(); // this ensures only the owner of the tokens can combine because this needs to be signed by the owner of the tokens to combine\n });\n this.action = \"combine\";\n this.timestamp = timestamp;\n this.oldest_mint_count = oldest_mint_count; // Make sure our new amount is within safe range\n\n this._checkAmount(this.amount);\n } catch (e) {\n throw function_id_combine + e;\n }\n\n return;\n } // Case: Mint\n\n\n if (caller === this.constructor) {\n // call from static function of this class\n const function_id_mint = function_id + \" mint : \";\n\n try {\n this._checkAmount(caller.mintAmount); // important to check here\n\n\n this.amount = caller.mintAmount;\n this.action = \"mint\";\n console.log(function_id_mint + \" \\n caller.mintAmount=\" + caller.mintAmount + \"\\n timestamp=\" + timestamp + \"\\n caller=\", caller, \"\\n \" + caller);\n this.timestamp = timestamp;\n this.oldest_mint_count = this.constructor.nonce; // TODO see if we should add +1 here ?\n\n console.log(function_id_mint + \" this.oldest_mint_count = \" + this.oldest_mint_count);\n } catch (e) {\n throw function_id_mint + e;\n }\n\n return;\n } // Case: Send\n\n\n if (caller && caller.constructor === this.constructor) {\n // call from a non-static function of this class\n const function_id_send = function_id + \" send : \";\n\n try {\n this._checkAmount(caller.sendAmount);\n\n this.amount = caller.sendAmount;\n this.owner = caller.sendOwner;\n this.timestamp = timestamp;\n this.sender = caller.sendSender;\n this.oldest_mint_count = caller.send_oldest_mint_count;\n this.action = \"send\";\n } catch (e) {\n throw function_id_send + e;\n }\n\n return;\n }\n }\n\n static mint(amount, timestamp) {\n const function_id = this.name + (this.tokenName ? \" (\" + this.tokenName + \")\" : \"\") + \": mint(): \";\n this.mintAmount = amount; // we cannot call _checkTimestamp in a static function because it's private but make sure to check in the init()\n\n const token = new this(timestamp);\n delete this.mintAmount;\n this.supply += amount;\n return token;\n }\n\n static combine(timestamp, ...tokens) {\n const function_id = this.name + (this.tokenName ? \" (\" + this.tokenName + \")\" : \"\") + \": combine(): \"; // we cannot call _checkTimestamp in a static function because it's private but make sure to check in the init()\n\n const token = new this(timestamp, ...tokens);\n return token;\n }\n\n static reduceSupplyIfAdmin(amount) {\n const function_id = this.name + (this.tokenName ? \" (\" + this.tokenName + \")\" : \"\") + \": reduceSupplyIfAdmin(): \"; // working if you call it from destroy() with this.constructor.reduceSupplyIfAdmin(this.amount)\n\n if (!(caller instanceof this)) throw function_id + \" this function cannot be called by a user (it is static but also private in a way)\"; // checkAmount, we have to redo it step by step here since we cannot call private functions from static ones\n\n if (typeof amount !== 'number') throw new Error(function_id + 'amount is not a number : ' + amount); // using throw gives better error trace than expect()\n\n if (!Number.isInteger(amount)) throw new Error(function_id + 'amount must be an integer : ' + amount);\n if (amount <= 0) throw new Error(function_id + 'amount must be positive : ' + amount);\n if (amount > Number.MAX_SAFE_INTEGER) throw new Error(function_id + 'amount too large : ' + amount);\n if (amount > this.supply) throw function_id + \" amount too large, you are trying to reduce supply by \" + amount + \" but supply is \" + this.supply; //console.log(function_id+\" caller = \\n \"+caller+\"\\n \",caller)\n\n this.supply -= amount; // this can only be done by the class' owner so it enforces that only the admin can call this function\n } // redefining the one from extended Jig class\n\n\n destroy() {\n // BEWARE YOU SHOULD RATHER USE BURN TO ATTACH A PRECISE TIMESTAMP TO THIS ACTION\n const function_id = this.classname + \"destroy(): \"; // beware destroy applies to all coins so it doesn't decrease supply if someone that isn't the class' owner destroys his coins\n\n console.log(function_id + \" caller : \" + caller + \"\\n\", caller);\n\n if (caller == null && this.owner == this.constructor.owner) {\n // caller is user and is the owner of the token's class\n // user called destroy(). we are not combining or sending tokens\n console.log(function_id + \" destroy from admin detected : try to reduce token supply\");\n this.constructor.reduceSupplyIfAdmin(this.amount);\n }\n\n super.destroy();\n this.action = \"destroy\";\n this.amount = 0;\n }\n\n burn(timestamp, amount_to_burn) {\n // amount_to_burn is optional, if not given will burn all\n const function_id = this.classname + \"burn(): \";\n if (this.owner != this.constructor.owner) throw function_id + \" Only \" + this.classname + \"'s owner can burn\\n class owner is \" + this.constructor.owner + \" and you are \" + this.owner; //if no amount_to_burn specified, burn all\n\n amount_to_burn = typeof amount_to_burn === 'undefined' ? this.amount : amount_to_burn;\n\n this._checkAmount(amount_to_burn);\n\n if (amount_to_burn > this.amount) throw function_id + \" not enough funds. Trying to burn \" + amount_to_burn + \" & this.amount=\" + this.amount;\n if (!timestamp) throw function_id + \" timestamp missing: \" + timestamp;\n\n this._checkTimestamp(timestamp); // all checks passed\n\n\n this.timestamp = timestamp;\n this.action = \"burn\";\n this.amount_burnt = amount_to_burn;\n this.action_count = this.constructor.nonce; // TODO see if we should do +1 ?\n\n if (amount_to_burn == this.amount) {\n //this.destroy() // TODO maybe we should use that instead ?\n this.amount = 0;\n } else {\n this.amount -= amount_to_burn; // decrease amount\n }\n\n console.log(function_id + \" state of parent class : \", this.constructor);\n this.constructor.reduceSupplyIfAdmin(amount_to_burn);\n }\n\n send(to, timestamp, amount = this.amount) {\n const function_id = this.classname + \"send(): \";\n\n try {\n this._checkAmount(amount);\n\n if (amount > this.amount) {\n throw new Error(function_id + 'Not enough funds');\n }\n\n this.sendAmount = amount;\n this.sendOwner = to;\n this.sendSender = this.owner;\n\n this._checkTimestamp(timestamp);\n\n if (timestamp <= this.timestamp) throw function_id + \"you cannot send with a timestamp that is before the coin to send's timestamp: \" + timestamp + \" <= \" + this.timestamp;\n this.send_oldest_mint_count = this.oldest_mint_count;\n const sent = new this.constructor(timestamp);\n delete this.sendAmount;\n delete this.sendOwner;\n delete this.sendSender;\n delete this.send_oldest_mint_count;\n\n if (this.amount === amount) {\n this.destroy();\n } else {\n this.amount -= amount;\n this.action = \"change\";\n }\n\n return sent;\n } catch (e) {\n throw function_id + e;\n }\n }\n\n _checkAmount(amount) {\n const function_id = this.classname + \": _checkAmount(): \";\n if (typeof amount !== 'number') throw new Error(function_id + 'amount is not a number : ' + amount); // using throw gives better error trace than expect()\n\n if (!Number.isInteger(amount)) throw new Error(function_id + 'amount must be an integer : ' + amount);\n if (amount <= 0) throw new Error(function_id + 'amount must be positive : ' + amount);\n if (amount > Number.MAX_SAFE_INTEGER) throw new Error(function_id + 'amount too large : ' + amount);\n }\n\n _checkNum(number) {\n // check that number is a positive number (but can be float)\n const function_id = this.classname + \": _checkNum(): \";\n if (typeof number !== 'number') throw function_id + 'number is not a number : ' + number;\n if (!(number > 0)) throw new Error(function_id + 'number must be positive : ' + number);\n if (number > Number.MAX_SAFE_INTEGER) throw new Error(function_id + 'number too large : ' + number);\n }\n\n _checkTimestamp(timestamp) {\n const function_id = this.classname + \": _checkTimestamp(): \";\n\n try {\n this._checkAmount(timestamp); // applies as well to timestamp\n\n } catch (e) {\n throw function_id + e;\n }\n\n if (!(timestamp > 1600939295117)) throw function_id + ': timestamp must be older than 1600939295117 : ' + timestamp; // make sure the timestamp here is in ms !!\n }\n\n}",{"decimals":8,"deps":{"expect":{"$jig":2},"Jig":{"$jig":0}},"icon":{"emoji":null},"sealed":false,"supply":0,"symbol":null},"function expect(t){let e=!1;const n=t=>{if(\"object\"!=typeof t||!t)return t;try{return JSON.stringify(t)}catch(e){return t.toString()}};function r(r,o,i){if(e?r:!r)throw new Error(i||`expected value${e?\" not\":\"\"} to be ${o} but was ${n(t)}`)}function o(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(\"object\"!=typeof t)return!1;if(null===t||null===e)return!1;if(Object.getPrototypeOf(t)!==Object.getPrototypeOf(e))return!1;if(Object.keys(t).length!==Object.keys(e).length)return!1;if(!Object.keys(t).every(n=>o(t[n],e[n])))return!1;if(t instanceof Set){if(t.size!==e.size)return!1;if(!o(Array.from(t.entries()),Array.from(e.entries())))return!1}if(t instanceof Map){if(t.size!==e.size)return!1;if(!o(Array.from(t.entries()),Array.from(e.entries())))return!1}return!0}function i(t,e){if(\"function\"!=typeof t)return!1;if(\"function\"!=typeof e)return!1;for(;t;)if((t=Object.getPrototypeOf(t))===e)return!0;return!1}return{get not(){return e=!e,this},toBe:(e,o)=>r(t===e,\"\"+n(e),o),toEqual:(e,i)=>r(o(t,e),\"equal to \"+n(e),i),toBeInstanceOf:(e,n)=>r(t&&t instanceof e,\"an instance of \"+(e&&e.name),n),toBeDefined:e=>r(void 0!==t,\"defined\",e),toBeNull:e=>r(null===t,\"null\",e),toBeNumber:e=>r(\"number\"==typeof t,\"a number\",e),toBeInteger:e=>r(Number.isInteger(t),\"an integer\",e),toBeLessThan:(e,n)=>r(t<e&&\"number\"==typeof t&&\"number\"==typeof e,\"less than \"+e,n),toBeLessThanOrEqualTo:(e,n)=>r(t<=e&&\"number\"==typeof t&&\"number\"==typeof e,\"less than or equal to \"+e,n),toBeGreaterThan:(e,n)=>r(t>e&&\"number\"==typeof t&&\"number\"==typeof e,\"greater than \"+e,n),toBeGreaterThanOrEqualTo:(e,n)=>r(t>=e&&\"number\"==typeof t&&\"number\"==typeof e,\"greater than or equal to \"+e,n),toBeBoolean:e=>r(\"boolean\"==typeof t,\"a boolean\",e),toBeString:e=>r(\"string\"==typeof t,\"a string\",e),toBeObject:e=>r(t&&\"object\"==typeof t,\"an object\",e),toBeArray:e=>r(Array.isArray(t),\"an array\",e),toBeSet:e=>r(t instanceof Set,\"a set\",e),toBeMap:e=>r(t instanceof Map,\"a map\",e),toBeUint8Array:e=>r(t instanceof Uint8Array,\"a uint8array\",e),toBeClass:e=>r(\"function\"==typeof t&&t.toString().startsWith(\"class\"),\"a class\",e),toBeFunction:e=>r(\"function\"==typeof t&&!t.toString().startsWith(\"class\"),\"a function\",e),toBeJigClass:e=>r(\"function\"==typeof t&&t.toString().startsWith(\"class\")&&i(t,Jig),\"a jig class\",e),toExtendFrom:(e,n)=>r(i(t,e),\"an extension of \"+(e&&e.name),n)}}",{"deps":{"Jig":{"$dup":["1","deps","Jig"]}}}]}]}
    https://whatsonchain.com/tx/03f06751672ce200efbec91c14df7fd696e6a433edbaf98a4d46f5142d55d441