one-click-tangle icon indicating copy to clipboard operation
one-click-tangle copied to clipboard

Address generation should use a mnemonic

Open Thoralf-M opened this issue 3 years ago • 10 comments

Description

When a snapshot is generated the address for it should be derived from a mnemonic.

Motivation

Will be much easier to use because people can use Firefly, wallet.rs or any client library to send the funds, that's not possible with the private key alone.

Requirements

  1. Generate address using a mnemonic
  2. Store the mnemonic so the user can access it

Open questions (optional)

Instead of generating a random mnemonic, maybe the default should be the same? If the one from here would be used one doesn't need to generate anything and if it's by default the same one can just send this one if someone has issues finding it.

Are you planning to do it yourself in a pull request?

No.

Thoralf-M avatar Sep 06 '21 06:09 Thoralf-M

In the meantime this script can be used with iota.js

// tsc .\index.ts --lib "es2018, dom"; node index.js
import {
    Bech32Helper,
    Ed25519Address,
    ED25519_ADDRESS_TYPE,
    IKeyPair,
    ISigLockedSingleOutput,
    IUTXOInput,
    sendAdvanced,
    SIG_LOCKED_SINGLE_OUTPUT_TYPE,
    SingleNodeClient,
    UTXO_INPUT_TYPE
} from "@iota/iota.js";
import { Converter } from "@iota/util.js";

async function run() {
    const client = new SingleNodeClient("https://api.thin-hornet-0.h.chrysalis-devnet.iota.cafe/");
    const amountToSend = 1000000;
    const newAddress = "atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r";
    const privateKey = "7955f50024c663167e6f741a88a04c16cffd6b2cdef26635e851330fdeb041912842e5cc739fc27f363ff77cccc4226d0e793ada4dc364c9988fa616a32733d6";
    const publicKey = "2842e5cc739fc27f363ff77cccc4226d0e793ada4dc364c9988fa616a32733d6";

    let bech32Address = Bech32Helper.fromBech32(newAddress, "atoi");
    let newAddressHex = Converter.bytesToHex(bech32Address.addressBytes);

    const nodeInfo = await client.info();

    let walletKeyPair = {publicKey:new Uint8Array(publicKey.match(/.{1,2}/g).map(byte => parseInt(byte, 16))), privateKey: new Uint8Array(privateKey.match(/.{1,2}/g).map(byte => parseInt(byte, 16)))};
    const ed25519Address = new Ed25519Address(walletKeyPair.publicKey);
    const walletAddress = ed25519Address.toAddress();
    const walletAddressHex = Converter.bytesToHex(walletAddress);
    console.log("\tAddress Ed25519", walletAddressHex);
    console.log(
        "\tAddress Bech32",
        Bech32Helper.toBech32(ED25519_ADDRESS_TYPE, walletAddress, nodeInfo.bech32HRP)
    );
    const addressOutputs = await client.addressEd25519Outputs(walletAddressHex);

    const inputsWithKeyPairs: {
        input: IUTXOInput;
        addressKeyPair: IKeyPair;
    }[] = [];

    let availableBalance = 0;

    for (let i = 0; i < addressOutputs.outputIds.length; i++) {
        const output = await client.output(addressOutputs.outputIds[i]);
        if (!output.isSpent) {
            inputsWithKeyPairs.push({
                input: {
                    type: UTXO_INPUT_TYPE,
                    transactionId: output.transactionId,
                    transactionOutputIndex: output.outputIndex
                },
                addressKeyPair: walletKeyPair
            });
            if (output.output.type === SIG_LOCKED_SINGLE_OUTPUT_TYPE) {
                availableBalance += (output.output as ISigLockedSingleOutput).amount;
            }
        }
    }


    const outputs: {
        address: string;
        addressType: number;
        amount: number;
    }[] = [
        // This is the transfer to the new address
        {
            address: newAddressHex,
            addressType: ED25519_ADDRESS_TYPE,
            amount: amountToSend
        },
        // Sending remainder back to own address
        {
            address: walletAddressHex,
            addressType: ED25519_ADDRESS_TYPE,
            amount: availableBalance - amountToSend
        }
    ];

    const { messageId } = await sendAdvanced(client, inputsWithKeyPairs, outputs, {
        key: Converter.utf8ToBytes("WALLET"),
        data: Converter.utf8ToBytes("Not trinity")
    });

    console.log("Created Message Id", messageId);
}

run()
    .then(() => console.log("Done"))
    .catch((err) => console.error(err));

Thoralf-M avatar Nov 12 '21 18:11 Thoralf-M

@Thoralf-M could you describe what that script does and how to use it?

sikhness avatar Jan 12 '22 22:01 sikhness

@sikhness you have to install iota.js with npm install @iota/iota.js, then set these values with your node and the keys you got from the private tangle setup

   const client = new SingleNodeClient("https://api.thin-hornet-0.h.chrysalis-devnet.iota.cafe/");
   const amountToSend = 1000000;
   const newAddress = "atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r";
   const privateKey = "7955f50024c663167e6f741a88a04c16cffd6b2cdef26635e851330fdeb041912842e5cc739fc27f363ff77cccc4226d0e793ada4dc364c9988fa616a32733d6";
   const publicKey = "2842e5cc739fc27f363ff77cccc4226d0e793ada4dc364c9988fa616a32733d6";

and run it, then it will transfer the amountToSend to the newAddress you could generate with Firefly or a wallet/client library

Thoralf-M avatar Jan 13 '22 09:01 Thoralf-M

Hi @Thoralf-M, do you have that same script but created using the Java API? I've been trying to move funds using the Java API and using the Public Key that the one-click-tangle generates and it keeps saying I have a 0 balance for that seed.

sikhness avatar Jan 26 '22 23:01 sikhness

No, doesn't work with the Java library

Thoralf-M avatar Jan 27 '22 06:01 Thoralf-M

@Thoralf-M is there no way to transfer value from the Genesis account via Java (aka the IOTA rust API) at all? Is this a limitation?

sikhness avatar Jan 27 '22 14:01 sikhness

It depends on how the genesis is created, if the private key would be derived from a seed then it would work, but if it's not like now, then you need a library that supports signing with a private key directly

Thoralf-M avatar Jan 27 '22 15:01 Thoralf-M

@Thoralf-M, In this case I'm using the one-click-tangle directly, and just using the key-pair that it generates in the key-pair.txt file. Does that key generate from the seed itself?

sikhness avatar Jan 27 '22 15:01 sikhness

No, there is no seed, that's why I opened this issue

Thoralf-M avatar Jan 27 '22 16:01 Thoralf-M

With hornet v1.20 the mnemonic seed is displayed in the keypar.txt

image

One can use the script here https://github.com/iotaledger/iota.js/blob/dev/packages/iota/examples/transaction/src/index.ts adding the mnemonic and do a transaction with it

peterokwara avatar Jun 02 '22 10:06 peterokwara