// If you don't want to set up your own nodejs environment,
// this script is also available at https://batch.xtz.tools/
// with a friendlier interface.
require('dotenv').config();
const fs = require("fs");
const path = require('path');
const parse = require('csv-parse/lib/sync');
const sotez = require('sotez');
const cryptoUtils = sotez.cryptoUtils;
const TezosToolkit = require("@taquito/taquito").TezosToolkit;
const InMemorySigner = require("@taquito/signer").InMemorySigner;
const contractAddress = process.env.CONTRACT || "KT1RJ6PbjHpwc3M5rw5s2Nbmefwbuwbdxton";
const inputFile = process.env.INPUT || path.join('data', 'send.csv');
const outputFile = process.env.OUTPUT || path.join('data', 'completed.csv');
const txConfirmations = process.env.CONFIRMATIONS || 3;
const txConfirmationTimeout = process.env.CONFIRMATIONTIMEOUT || txConfirmations * (2 * 60);
const main = async () => {
const Tezos = new TezosToolkit("https://mainnet.smartpy.io/");
var signer;
if (process.env.MNEMONIC) {
const keys = await cryptoUtils.generateKeys(process.env.MNEMONIC);
signer = new InMemorySigner(keys.sk);
} else if (process.env.SECRET) {
signer = new InMemorySigner(process.env.SECRET);
} else {
throw "Neither MNEMONIC nor SECRET is set!";
}
const walletAddress = await signer.publicKeyHash();
console.log("Running for sender " + walletAddress);
Tezos.setProvider({ signer });
// Prepare smart contract parameters
const params = [
{
from_: walletAddress,
txs: []
}
];
console.log("Reading input " + inputFile);
const content = fs.readFileSync(inputFile, 'utf8');
console.log("Parsing input");
// Parse CSV input
const records = parse(content, {
columns: ['target_address', 'token_id', 'amount'],
skip_empty_lines: true,
trim: true,
bom: true
});
if (records.length == 0) {
throw "No entries to process!";
}
records.forEach(record => {
if (record.target_address == "target_address") {
return;
}
console.log(`Found entry: ${record.amount} × #${record.token_id} to ${record.target_address}`);
params[0].txs.push({
to_: record.target_address,
token_id: record.token_id,
amount: record.amount
});
});
console.log("Getting information for FA2 contract " + contractAddress);
const contract = await Tezos.contract.at(contractAddress);
console.log("Sending transaction");
const operation = await contract.methods.transfer(params).send({ amount: 0, mutez: true });
console.log("Waiting for " + txConfirmations + " transaction confirmations with a timeout of " + txConfirmationTimeout + " seconds, see https://tzstats.com/" + operation.hash);
await operation.confirmation(txConfirmations, 10, txConfirmationTimeout);
console.log("Transaction confirmed!");
console.log("Saving transaction hash to " + outputFile);
if (!fs.existsSync(outputFile)) {
fs.writeFileSync(outputFile, 'txn,date');
}
fs.appendFileSync(outputFile, operation.hash + ',' + new Date().toISOString());
console.log("Done!");
};
main().catch(error => {
console.error("Failed! Here is why:");
console.error(error);
});
# ONE OF THE NEXT TWO IS REQUIRED
SECRET=
MNEMONIC=
# EVERYTHING BELOW HERE IS OPTIONAL
CONTRACT=
CONFIRMATIONS=
CONFIRMATIONTIMEOUT=
INPUT=
OUTPUT=
{
"name": "objkt-batch-sender",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "PureSpider",
"license": "CC-BY-NC-SA-4.0",
"private": true,
"dependencies": {
"@taquito/signer": "^9.0.0",
"@taquito/taquito": "^9.0.0",
"csv-parse": "^4.15.4",
"dotenv": "^8.2.0",
"sotez": "^8.0.1"
}
}
target_address,token_id,amount
tz1PqooZUtCQqP539PmMzUWHtaUX6EQtFY5S,64620,1