keycard-redeem/scripts/create-gift.js

165 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
import Web3 from 'web3';
import parseArgs from 'minimist';
import fs from 'fs';
const argv = parseArgs(process.argv.slice(2), {boolean: ["deploy-factory", "deploy-bucket"], string: ["sender", "factory", "bucket", "token"], default: {"endpoint": "ws://127.0.0.1:8546", "validity-days": 365}});
const web3 = new Web3(argv["endpoint"]);
const GiftBucketConfig = loadEmbarkArtifact('./embarkArtifacts/contracts/GiftBucket.js');
const GiftBucketFactoryConfig = loadEmbarkArtifact('./embarkArtifacts/contracts/GiftBucketFactory.js');
const GiftBucketFactory = new web3.eth.Contract(GiftBucketFactoryConfig["abiDefinition"]);
const GiftBucket = new web3.eth.Contract(GiftBucketConfig["abiDefinition"]);
function loadEmbarkArtifact(path) {
let file = fs.readFileSync(path, "utf-8");
let json = file.replace(/import.*/, "").replace(/.*EmbarkJS.Blockchain.*/, "").replace(/export default.*/, "").replace(/const[^=]*= /, "").replace(/;/, "").trim();
let loadedAsset = JSON.parse(json);
return loadedAsset;
}
async function getDefaultSender() {
let accounts = await web3.eth.getAccounts();
return accounts[0];
}
function loadAccount(account, passfile) {
let json = fs.readFileSync(account, "utf-8");
let pass = fs.readFileSync(passfile, "utf-8").split("\n")[0].replace("\r", "");
return web3.eth.accounts.decrypt(json, pass);
}
async function sendMethod(methodCall, sender, to) {
let receipt;
if (typeof(sender) == "string") {
let gasAmount = await methodCall.estimateGas({from: sender});
receipt = await methodCall.send({from: sender, gas: gasAmount});
} else {
let gasAmount = await methodCall.estimateGas({from: sender.address});
let data = methodCall.encodeABI();
let signedTx = await sender.signTransaction({to: to, data: data, gas: gasAmount});
receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
}
return receipt;
}
async function deployFactory(sender) {
let code = "0x" + GiftBucketFactoryConfig["code"];
let methodCall = GiftBucketFactory.deploy({data: code});
let receipt = await sendMethod(methodCall, sender, null);
return receipt.contractAddress;
}
async function deployBucket(sender, factory, token, validityInDays) {
let now = Math.round(new Date().getTime() / 1000);
let expirationDate = now + (60 * 60 * 24 * validityInDays);
GiftBucketFactory.options.address = factory;
let methodCall = GiftBucketFactory.methods.create(token.toLowerCase(), expirationDate);
try {
let receipt = await sendMethod(methodCall, sender, GiftBucketFactory.options.address);
return receipt.events.BucketCreated.returnValues.bucket;
} catch(err) {
console.error(err);
return null;
}
}
async function createGift(sender, bucket, keycard) {
GiftBucket.options.address = bucket;
let methodCall = GiftBucket.methods.createGift(keycard.keycard, keycard.amount, keycard.code);
try {
let receipt = await sendMethod(methodCall, sender, GiftBucket.options.address);
return receipt;
} catch(err) {
console.error(err);
return null;
}
}
function processLine(line) {
let c = line.split(",").map((e) => e.toLowerCase().trim());
return {keycard: c[0], amount: parseInt(c[1]), code: c[2]};
}
async function run() {
GiftBucketFactory.transactionConfirmationBlocks = 3;
GiftBucket.transactionConfirmationBlocks = 3;
let sender;
let hasDoneSomething = false;
if (argv["account"]) {
if (!argv["passfile"]) {
console.error("the ---passfile option must be specified when using the --account option");
process.exit(1);
}
if (argv["sender"]) {
console.warn("--account used, --sender will be ignored");
}
sender = loadAccount(argv["account"], argv["passfile"]);
} else {
sender = argv["sender"] || await getDefaultSender();
}
let factory;
if (argv["deploy-factory"]) {
factory = await deployFactory(sender);
hasDoneSomething = true;
console.log("Factory deployed at: " + factory);
} else {
factory = argv["factory"];
}
let bucket;
if (argv["deploy-bucket"]) {
if (!factory) {
console.error("the --factory or --deploy-factory option must be specified");
process.exit(1);
}
if (!argv["token"]) {
console.error("the --token option must be specified");
process.exit(1);
}
if (!argv["validity-days"]) {
console.error("the --validity-days option must be specified");
process.exit(1);
}
bucket = await deployBucket(sender, factory, argv["token"], argv["validity-days"]);
hasDoneSomething = true;
console.log("Bucket deployed at: " + bucket);
} else {
bucket = argv["bucket"];
}
let keycards;
if (argv["file"]) {
let file = fs.readFileSync(argv["file"], 'utf8');
keycards = file.split("\n").map(processLine);
for (let keycard of keycards) {
await createGift(sender, bucket, keycard)
}
} else if (!hasDoneSomething) {
console.error("the --file option must be specified");
process.exit(0);
}
process.exit(0);
}
run();