UNPKG

ethers-meow

Version:

A simple CLI for CryptoKitties using ethers.js.

491 lines (407 loc) 14.5 kB
'use strict'; var https = require('https'); var ethers = require('ethers'); var kittyCoreInterface = require('./contracts/KittyCore.json'); var saleClockInterface = require('./contracts/SaleClockAuction.json'); var siringClockInterface = require('./contracts/SiringClockAuction.json'); var geneScienceInterface = require('./contracts/GeneScience.json'); var kittyCoreAddress = '0x06012c8cf97BEaD5deAe237070F9587f8E7A266d'; var saleClockAddress = '0xb1690C08E213a35Ed9bAb7B318DE14420FB57d8C'; var siringClockAddress = '0xC7af99Fe5513eB6710e6D5f44F9989dA40F27F26'; // This is static; no need to look it up in the contract var cooldowns = [ //uint32(1 minutes), (1 * 60), //uint32(2 minutes), (2 * 60), //uint32(5 minutes), (5 * 60), //uint32(10 minutes), (10 * 60), //uint32(30 minutes), (30 * 60), //uint32(1 hours), (60 * 60), //uint32(2 hours), (2 * 60 * 60), //uint32(4 hours), (4 * 60 * 60), //uint32(8 hours), (8 * 60 * 60), //uint32(16 hours), (16 * 60 * 60), //uint32(1 days), (24 * 60 * 60), //uint32(2 days), (2 * 24 * 60 * 60), //uint32(4 days), (4 * 24 * 60 * 60), //uint32(7 days) (7 * 24 * 60 * 60), ]; var cooldownNames = [ 'fast', 'swift', 'snappy', 'brisk', 'plodding', 'slow', 'sluggish', 'catatonic' ]; function Kitty(kittyId, details) { ethers.utils.defineProperty(this, 'id', kittyId); ethers.utils.defineProperty(this, 'matronId', details.matronId.toNumber()); ethers.utils.defineProperty(this, 'sireId', details.sireId.toNumber()); ethers.utils.defineProperty(this, 'birthTime', details.birthTime.toNumber()); ethers.utils.defineProperty(this, 'generation', details.generation.toNumber()); ethers.utils.defineProperty(this, 'genes', details.genes.toHexString()); ethers.utils.defineProperty(this, 'cooldownIndex', details.cooldownIndex.toNumber()); ethers.utils.defineProperty(this, 'nextActionAt', details.nextActionAt.toNumber()); ethers.utils.defineProperty(this, 'ready', details.isReady); ethers.utils.defineProperty(this, 'pregnant', details.isGestating); ethers.utils.defineProperty(this, 'siringWithId', details.siringWithId.toNumber()); ethers.utils.defineProperty(this, 'owner', details.owner); } function Manager(providerOrSigner) { var signer = null; var provider = providerOrSigner; if (provider.provider) { signer = provider; provider = provider.provider; } ethers.utils.defineProperty(this, 'signer', signer); ethers.utils.defineProperty(this, 'provider', provider); ethers.utils.defineProperty(this, '_siringClock', new ethers.Contract(siringClockAddress, siringClockInterface, providerOrSigner)); ethers.utils.defineProperty(this, '_saleClock', new ethers.Contract(saleClockAddress, saleClockInterface, providerOrSigner)); ethers.utils.defineProperty(this, '_kittyCore', new ethers.Contract(kittyCoreAddress, kittyCoreInterface, providerOrSigner)); } Manager.prototype.getKitty = function(kittyId) { return Promise.all([ this._kittyCore.getKitty(kittyId), this._kittyCore.ownerOf(kittyId), ]).then(function(result) { result[0].owner = result[1]; return new Kitty(kittyId, result[0]); }) } Manager.prototype.getStatus = function() { var toNumber = { pregnantKitties: true, promoCreatedCount: true, secondsPerBlock: true, totalSupply: true }; var keys = [ 'autoBirthFee', 'ceoAddress', 'cfoAddress', 'cooAddress', 'paused', 'pregnantKitties', 'promoCreatedCount', 'secondsPerBlock', 'symbol', 'totalSupply', ]; var promises = []; keys.forEach(function(key) { promises.push(this._kittyCore[key]()); }, this); return Promise.all(promises).then(function(result) { var status = {}; result.forEach(function(result, index) { var key = keys[index]; result = result; if (toNumber[key]) { result = result.toNumber(); } status[key] = result; }); return status; }); } Manager.prototype.getKittyCount = function(address) { return this._kittyCore.balanceOf(address).then(function(result) { return result.toNumber(); }); } Manager.prototype.getKittyIds = function(address) { return this._kittyCore.tokensOfOwner(address).then(function(result) { var ids = []; result.forEach(function(id) { ids.push(id.toNumber()); }); return ids; }); } Manager.prototype.check = function(matronId, sireId) { return Promise.all([ this._kittyCore.canBreedWith(sireId, matronId), this._kittyCore.isReadyToBreed(matronId), this._kittyCore.isReadyToBreed(sireId), ]).then(function(result) { return { canBreed: result[0], matronReady: result[1], sireReady: result[2], } }); } Manager.prototype.breed = function(matronId, sireId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var self = this; return Promise.all([ this.check(matronId, sireId), this._kittyCore.ownerOf(matronId), this._kittyCore.autoBirthFee() ]).then(function(result) { if (!result[0].canBreed) { throw new Error('kitties cannot breed'); } if (!result[0].matronReady) { throw new Error('matron not ready'); } if (!result[0].sireReady) { throw new Error('sire not ready'); } if (result[1] !== self.signer.address) { throw new Error('account does not own matron'); } var options = { gasLimit: 125000, value: result[2] }; return self._kittyCore.breedWithAuto(matronId, sireId, options); }); } Manager.prototype.giveBirth = function(kittyId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 300000 }; return this._kittyCore.giveBirth(kittyId, options); } Manager.prototype.approveSiring = function(kittyId, address) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 125000 }; return this._kittyCore.approveSiring(address, kittyId, options); } Manager.prototype.transfer = function(kittyId, address) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 125000 }; return this._kittyCore.transfer(address, kittyId, options); } Manager.prototype._getAuction = function(contract, kittyId) { return Promise.all([ contract.getAuction(kittyId), contract.getCurrentPrice(kittyId), ]).then(function(result) { return { seller: result[0].seller, startPrice: result[0].startingPrice, endPrice: result[0].endingPrice, duration: result[0].duration, currentPrice: result[1] } }, function (error) { return null; }); } Manager.prototype.getSaleAuction = function(kittyId) { return this._getAuction(this._saleClock, kittyId); } Manager.prototype.getSiringAuction = function(kittyId) { return this._getAuction(this._siringClock, kittyId); } Manager.prototype.createSaleAuction = function(kittyId, startPrice, endPrice, duration) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 250000 }; return this._kittyCore.createSaleAuction(kittyId, startPrice, endPrice, duration, options); } Manager.prototype.createSiringAuction = function(kittyId, startPrice, endPrice, duration) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 250000 }; return this._kittyCore.createSiringAuction(kittyId, startPrice, endPrice, duration, options); } Manager.prototype.bidOnSaleAuction = function(kittyId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var self = this; return this.getSaleAuction(kittyId).then(function(result) { if (result == null) { throw new Error('invalid auction'); } var options = { gasLimit: 275000, value: result.currentPrice }; return self._saleClock.bid(kittyId, options) }) } Manager.prototype.bidOnSiringAuction = function(sireId, matronId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var self = this; return Promise.all([ this.getSiringAuction(sireId), this._kittyCore.autoBirthFee() ]).then(function(result) { var options = { gasLimit: 275000, value: result[0].currentPrice.add(result[1]) }; return self._kittyCore.bidOnSiringAuction(sireId, matronId, options) }) } Manager.prototype.cancelSaleAuction = function(kittyId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 150000 }; return this._saleClock.cancelAuction(kittyId, options); } Manager.prototype.cancelSiringAuction = function(kittyId) { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } var options = { gasLimit: 150000 }; return this._siringClock.cancelAuction(kittyId, options); } Manager.prototype._getGeneScience = function() { if (!this._geneSciencePromise) { var self = this; this._geneSciencePromise = this._kittyCore.geneScience().then(function(result) { return new ethers.Contract(result, geneScienceInterface, self.provider); }); } return this._geneSciencePromise; } Manager.prototype.mixGenes = function(genes1, genes2, targetBlock) { var self = this; return this._getGeneScience().then(function(contract) { return contract.mixGenes(genes1, genes2, targetBlock).then(function(result) { return result; }); }); } Manager.prototype._fetch = function(method, path, body) { var self = this; return new Promise(function(resolve, reject) { var headers = { 'Content-Length': String(body.length), 'Content-Type': 'application/json;charset=UTF-8', }; if (self.token) { headers['Authorization'] = self.token; } var request = https.request({ hostname: 'api.cryptokitties.co', port: 443, method: method, path: path, headers: headers, Agent: 'ethers-meow' }, function(response) { var data = new Buffer([]); response.on('data', function(chunk) { data = Buffer.concat([data, chunk]); }); response.on('end', function() { try { var result = JSON.parse(data.toString()); resolve(result); } catch (error) { reject(error); } }); }); request.write(body); request.end(); }); } Manager.prototype.getToken = function() { if (this.signer == null) { return Promise.reject(new Error('missing signer')); } if (this.token) { return Promise.resolve(this.token); } var addressPromise = this.signer.getAddress ? this.signer.getAddress(): this.signer.address; if (!(addressPromise instanceof Promise)) { addressPromise = Promise.resolve(addressPromise); } var signaturePromise = this.signer.signMessage('Cryptokitties'); if (!(signaturePromise instanceof Promise)) { signaturePromise = Promise.resolve(signaturePromise); } var self = this; return Promise.all([ addressPromise, signaturePromise ]).then(function(result) { var payload = JSON.stringify({ address: result[0].toLowerCase(), sign: result[1] }); return self._fetch('POST', '/sign', payload).then(function(info) { if (info.token) { self.token = info.token; } return self.token; }); }); } Manager.prototype.rename = function(kittyId, name) { var self = this; return this.getToken().then(function(token) { var payload = JSON.stringify({ id: kittyId, name: name }); return self._fetch('PATCH', '/kitties/' + kittyId, payload).then(function(result) { return result; }); }); } Manager.prototype.setUser = function(nickname, email) { var self = this; return this.getToken().then(function(token) { var payload = JSON.stringify({ email: email, image: 3, nickname: nickname }); return self._fetch('PATCH', '/user/me', payload).then(function(result) { return result; }); }); } /* var https = require('https'); (function() { var payload = JSON.stringify({ id: 84216, name: 'Stumps - test4 - Fast (V)' }); var url = 'https://api.cryptokitties.co/kitties/84216'; var method = 'PATCH'; var auth = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZGRyZXNzIjoiMHg4YmExZjEwOTU1MWJkNDMyODAzMDEyNjQ1YWMxMzZkZGQ2NGRiYTcyIn0.qakaN4w6cXlsWTZZ8fyrsSeND6TrgvfnrYa3lgicwxU'; var headers = { 'Authorization': auth, 'Content-Length': String(payload.length), 'Content-Type': 'application/json;charset=UTF-8', }; var request = https.request({ hostname: 'api.cryptokitties.co', port: 443, method: 'PATCH', path: '/kitties/84216', headers: headers, Agent: 'ethers-meow' }, function(response) { console.log('ARG', arguments); var data = new Buffer([]); response.on('data', function(chunk) { console.log(chunk); data = Buffer.concat([data, chunk]); }); response.on('end', function() { var result = JSON.parse(data.toString()); console.log('end', result); }); }); console.log(request); request.write(payload); request.end(); })(); */ module.exports = { Kitty: Kitty, Manager: Manager }