I'm really new to Iota and specifically flash, so apologies if this is an obvious question!
I've been following the example in iota.flash.js under the examples folder, and want to modify this example to create an M of N multisig channel, where there will be three participants and only one signer. I haven't seen an example of how this is done in any examples provided so want to attempt it.
I'm able to generate the signature for the signer, but once I call Helpers.createTransaction, I get an "undefined" error.
I poked around the code and it looks like the culprit is in multisigs.js. For the last value it's returning undefined, so when the rest of the code tries to execute the find() method, it throws. I noticed that the callback was returning both e and success, and it turns out success is undefined for some reason. When I send e to the console, here is the error that multisig returns: invalid value transfer: The transfer does not require a signature.
I'm sending Iota from the signer (defined by oneFlash,) to one of the other two parties.
First, here is the error stack trace:
Error: Invalid value transfer: the transfer does not require a signature.
at Function.Multisig.initiateTransfer (C:\Users\munawar\syncoms\iota.flash.js\node_modules\iota.crypto.js\lib\multisig\multisig.js:253:25)
at Object.compose (C:\Users\munawar\syncoms\iota.flash.js\lib\transfer.js:133:23)
at Object.createTransaction (C:\Users\munawar\syncoms\iota.flash.js\examples\functions.js:44:24)
at sse (C:\Users\munawar\syncoms\iota.flash.js\examples\flash.js:222:25)
at proceed (C:\Users\munawar\syncoms\iota.flash.js\examples\flash.js:241:1)
at iota.api.sendTransfer (C:\Users\munawar\syncoms\iota.flash.js\examples\flash.js:26:3)
at C:\Users\munawar\syncoms\iota.flash.js\node_modules\iota.lib.js\lib\api\api.js:555:28
at makeRequest.prepareResult (C:\Users\munawar\syncoms\iota.flash.js\node_modules\iota.lib.js\lib\utils\makeRequest.js:190:12)
at exports.XMLHttpRequest.request.onreadystatechange (C:\Users\munawar\syncoms\iota.flash.js\node_modules\iota.lib.js\lib\utils\makeRequest.js:62:25)
at exports.XMLHttpRequest.dispatchEvent (C:\Users\munawar\syncoms\iota.flash.js\node_modules\xmlhttprequest\lib\XMLHttpRequest.js:591:25)
Next, here is my full code. Can someone please let me know if it's possible to do what I want to do (where only one signer is the authority, and whether or not I'm even doing this correctly?):
const IOTA = require("iota.lib.js");
require("isomorphic-fetch");
var iota = new IOTA({
//provider:
// Math.random() > 0.5
// ? "https://testnet.tangle.works:443"
// : "https://testnet2.tangle.works:443"
provider: "http://p101.iotaledger.net:14700"
});
console.log(iota);
const fundChannel = async address => {
var transfers = [{ value: 2000, address:address }];
// Get your free seeeed
var response = await fetch("https://seeds.tangle.works/");
var wallet = await response.json();
return new Promise(function(resolve, reject) {
iota.api.sendTransfer(wallet.seed, 5, 9, transfers, (e, r) => {
if (e !== null) {
console.log(e);
reject(e);
} else {
console.log("Channel funded!");
proceed();
resolve(r);
}
})
})
}
const IOTACrypto = require("iota.crypto.js")
const transfer = require("../lib/transfer")
const multisig = require("../lib/multisig")
const Helpers = require("./functions")
// Security level
const SECURITY = 1;
// Number of parties taking signing part in the channel
const SIGNERS_COUNT = 1;
// Flash tree depth
const TREE_DEPTH = 4;
var channels = [];
channels["abc"] = {participants:[], userIndex: 0, deposits:[2000, 0, 0], balance:2000};
const platform = "def";
const platformSeed = "BGYFYVQSGZDRLJLTPOFCTPAMMU9TCPMSR9TTTAQLNXOUS9LEIHYNWKBUHSZMIWIYQH9PEMSNDPPHSSXEZ"
const platformSettlement = "AKTFFZCMUZVPX9VBHIBPSUKMJDLVNFGTW9ZYMHTXAEYIQBZEBDZUAONIKVKZBZPIVFOPRTYKITIIPPQHD";
var addresses = [];
addresses.push(platformSettlement);
addresses.push("JEYP9TTIQJVVBQZP9OZQQHNCUDWKGIUQQB9HOQYQTQPSYOSKFLTDGXOI9ICCIKSUXVHZ9BPL9EBXDHSTB");
addresses.push("SXD9NNQFKRS9XYKGYN9GYCUDSWMRHRYAEJVDHMEQRDSU9JPULOZFVPSB9VUZGVRUSE9GL9FFABJOESWD9");
oneFlash = {
userIndex: channels["abc"].userIndex,
partialDigests:[],
index: 0,
bundles: [],
settlementAddress: addresses[0],
userSeed: platformSeed,
flash: {
signersCount: 1,
balance: channels["abc"].balance,
deposit: channels["abc"].deposits.slice(),
settlementAddresses: addresses,
remainderAddress: null,
outputs: {},
transfers: []
}
};
// Create digests for the start of the channel
for (let i = 0; i < TREE_DEPTH + 1; i++) {
// Create new digest
const digest = multisig.getDigest(
platformSeed,
oneFlash.index,
SECURITY
);
// Increment key index
oneFlash.index++;
oneFlash.partialDigests.push(digest);
}
console.log("Initial digests generated!");
// INITAL MULTISIG
// Make an array of digests
let allDigests = [];
allDigests[oneFlash.userIndex] = oneFlash.partialDigests;
// Generate the first addresses
var oneMultisigs = oneFlash.partialDigests.map((digest, index) => {
// Create address
let addy = multisig.composeAddress(
allDigests.map(userDigests => userDigests[index])
);
// Add key index in
addy.index = digest.index;
// Add the signing index to the object IMPORTANT
addy.signingIndex = oneFlash.userIndex * digest.security;
// Get the sum of all digest security to get address security sum
addy.securitySum = allDigests
.map(userDigests => userDigests[index])
.reduce((acc, v) => acc + v.security, 0)
// Add Security
addy.security = digest.security
return addy
});
console.log("Multisigs generated!");
var remainderAddress = oneMultisigs.shift();
oneFlash.flash.remainderAddress = remainderAddress;
// Nest trees
for (let i = 1; i < oneMultisigs.length; i++) {
oneMultisigs[i - 1].children.push(oneMultisigs[i])
}
// Set Flash root
var root = oneMultisigs.shift();
var depositAddress = iota.utils.addChecksum(oneMultisigs[0].address);
oneFlash.flash.root = root;
oneFlash.flash.depositAddress = depositAddress;
console.log("Waiting for funding...");
fundChannel(depositAddress);
function proceed() {
console.log("Resuming");
// Set digest/key index
var index = oneFlash.index = oneFlash.partialDigests.length;
console.log("Channel Setup!")
console.log(
"Transactable tokens: ",
oneFlash.flash.deposit.reduce((acc, v) => acc + v)
)
twoFlash = {
userIndex: channels["abc"].userIndex,
index: 0,
bundles: [],
settlementAddress: addresses[channels["abc"].userIndex],
flash: {
signersCount: 1,
balance: channels["abc"].balance,
deposit: channels["abc"].deposits.slice(),
settlementAddresses: addresses,
remainderAddress: remainderAddress,
root: root,
depositAddress: depositAddress,
outputs: {},
transfers: []
}
};
channels["abc"].userIndex++;
threeFlash = {
userIndex: channels["abc"].userIndex,
index: 0,
bundles: [],
settlementAddress: addresses[channels["abc"].userIndex],
flash: {
signersCount: 1,
balance: channels["abc"].balance,
deposit: channels["abc"].deposits.slice(),
settlementAddresses: addresses,
remainderAddress: remainderAddress,
root: root,
depositAddress:depositAddress,
outputs: {},
transfers: []
}
};
twoFlash.index = threeFlash.index = index;
console.log("Sending 5 tokens to twoFlash");
var transfers = [{value: 5, address: twoFlash.settlementAddress}];
//console.log(theChannel.participants[fromUid]);
// *** THIS IS WHERE CODE FAILS***
var bundles = Helpers.createTransaction(oneFlash, transfers, false);
//console.log("Then: ");
//console.log(theChannel.participants[fromUid]);
console.log(bundles.length);
var theSignatures = Helpers.signTransaction(oneFlash, bundles);
var signedBundles = transfer.appliedSignatures(bundles, theSignatures);
oneFlash = Helpers.applyTransfers(oneFlash, signedBundles);
twoFlash = Helpers.applyTransfers(twoFlash, signedBundles);
threeFlash = Helpers.applyTransfers(threeFlash, signedBundles);
oneFlash.bundles = signedBundles;
twoFlash.bundles = signedBundles;
threeFlash.bundles = signedBundles;
console.log("Transaction Applied!");
console.log(oneFlash.flash.deposit);
console.log("Transactable tokens: ", theChannel.participants[platform].flash.deposit.reduce((acc, v) => acc + v));
}
Thanks for any assistance! I've been playing with it for a few days now but haven't had any success.