6

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.

  • We can probably help you best if you can tell us what you already tried or didn't try already. – Helmar Dec 11 '17 at 12:49
1

After digging through a lot of code in the Flash API, it seems like creating a channel with deposits of [2000, 0, 0] was the issue. I'm assuming every party MUST deposit some amount of tokens then. When I changed the deposit amounts to [1000, 500, 500], the transactions are being applied properly. The problem was that the stake for a party is 0 if their deposit into the channel is 0, and this was causing issues and giving "undefined" where there shouldn't have been undefined.

After I changed the balances, I was getting another error: invalid transfers object. This error was caused by the value field in the transfers object being a float instead of integer, so in iota.flash.js/node_modules/iota.crypto.js/lib/utils/inputValidator.js, I changed the isValue function to this: var isValue = function(value) {

// check if correct number
//return Number.isInteger(value) (OLD CODE)
return !isNaN(parseInt(value)) //modification

}

This way, stakes of 7.5 and 2.5--when sending 5 Iota from the party with 1000 Iota to the party with 500 Iota-- are accepted (as I'm assuming they should be?)

I wanted to post this here since this question got some up votes.

So, the guide is a little misleading on this since it mentions a channel of [100, 0] being a valid setup. Can someone shed light on this?

  • It's probably a good idea to comment on the issue github.com/iotaledger/iota.flash.js/issues/23 with your findings. (or even better : make a pull request with your fix) (don't link to here because we are still in private beta) – ben75 Dec 12 '17 at 14:44
0

I think the error happens in before transfer.prepare, because other parties have zero stakes in the channel. This leads to a division by zero in the mentioned function.

Fixed it and opened a pull request (https://github.com/iotaledger/iota.flash.js/pull/27). Let's hope it is going to be merged soon :)

  • 1
    Awesome, thanks for the PR and fix. I agree, hopefully they'll merge it soon! – Munawar Jan 14 '18 at 7:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.