Transaction

dc42af8b4a38665c05c3459710c15b6451a37a73dbc202567281b36373507b7d
( - )
225,261
2020-09-24 10:22:04
1
12,419 B

4 Outputs

Total Output:
  • jrunMi/{"in":0,"ref":["native://Jig"],"out":["7d1a3343d266a28ccdaf6dc9e769ac2b95f52a326cf58f4e7ee5b32553167a63","1fec6ed7b106fb25ef2b2d9c3beb00524f999bb35122b201f770ea37b2328d58"],"del":[],"cre":["mzcwZjsbBHgy4rxfULW4mFXVRb6N9pkLV4","mzcwZjsbBHgy4rxfULW4mFXVRb6N9pkLV4"],"exec":[{"op":"DEPLOY","data":["class TokenContract extends Jig {\n //\n // with RUN 0.6 preview version \n //\n init(...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 if (caller == null) throw function_id + \"cannot be called directly by user\";\n\n if (caller === this.constructor) {\n // call from static function of this class\n if (caller.combine_timestamp) {\n // Case: Combine\n //\n const function_id_combine = function_id + \" combine : \";\n\n try {\n this._checkTimestamp(caller.combine_timestamp); // important to check here\n\n\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 tokens to combine\n });\n this.action = \"combine\";\n this.timestamp = caller.combine_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 } else if (caller.mint_timestamp) {\n // Case: Mint\n //\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 caller.mint_timestamp=\" + caller.mint_timestamp + \"\\n caller=\", caller, \"\\n \" + caller);\n\n this._checkTimestamp(caller.mint_timestamp); // important to check here\n\n\n this.timestamp = caller.mint_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 }\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\n this._checkTimestamp(caller.send_timestamp); // very important to check here because we can't do it in: static send()\n\n\n this.timestamp = caller.send_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 this.mint_timestamp = timestamp;\n const token = new this();\n delete this.mintAmount;\n this.supply += amount;\n delete this.mint_timestamp;\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 this.combine_timestamp = timestamp;\n const token = new this(...tokens);\n delete this.combine_timestamp;\n return token;\n }\n\n static _destroy_reduceSupplyIfAdmin(amount) {\n // since this function is private it can only be called from this class, so no need for if(caller instanceof this) {}\n // working if you call it from destroy() with this.constructor.reduceSupply(this.amount)\n const function_id = this.name + (this.tokenName ? \" (\" + this.tokenName + \")\" : \"\") + \": _reduceSupply(): \";\n console.log(function_id + \" caller = \\n \" + caller + \"\\n \", caller);\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 because that would require the class's owner access\n // so you should use BURN to burn coins & reduce supply at the same time\n // we could also check in destroy() if the caller is the class owner to reduce supply in that case\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 user detected : try to reduce token supply\");\n\n this.constructor._destroy_reduceSupplyIfAdmin(this.amount);\n }\n\n super.destroy();\n this.action = \"burn\";\n this.amount = 0;\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_timestamp = timestamp;\n this.send_oldest_mint_count = this.oldest_mint_count;\n const sent = new this.constructor();\n delete this.sendAmount;\n delete this.sendOwner;\n delete this.sendSender;\n delete this.send_timestamp;\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/dc42af8b4a38665c05c3459710c15b6451a37a73dbc202567281b36373507b7d