Import Exodus (Shelley) Wallet to Eternl (for Midnight Glacier Drop claim)

@HeptaSean Do you happen to have any info on the Exodus master key derivation scheme?

With the glacier drop it would be nice to have an Exodus created account be restored in a CIP-30 compliant wallet such as Eternl.

1 Like

Does that help?

Oh, then maybe not. Or at least not easily. Eternl cannot import that.

Didn’t Exodus implement CIP-30? But maybe not with signData(). And most probably not with the possibility to get an unused address (which Midnight wants to require for some strange reason).

Eternl allows to import a “wallet” by address since V2, though. Would have to test if that somehow helps, but no guarantees at all. But will be rather complicated, surely involving downloading the unsigned message, somehow signing it on the command line, and then submitting it.

Seems they did at some point:
https://www.exodus.com/support/en/articles/8598983-explore-the-cardano-web3-ecosystem-with-exodus
Not sure how feature-complete, if kept up-to-date, and – most importantly – if Midnight claim portal will support it somehow.

The plan is

mnemonic → cardano tools to produce payment and staking (private and public keys) → verify base address → convert to an skey JSON file → Eternl can import private keys skey JSON (at least lately it does)

Your answer I will try it out. Still amazed how you got the info.

Not sure if their web3 is 100% functional, have experienced a few problems. As you said, not much feature-complete.

Ah, yeah, importing skeys should work. Totally forgot that they added that. Shame on me. I asked for it for years.

Back in the days, they claimed that that is a “standard” way of deriving keys. Because one other obscure wallet app did the same. And that other wallet app was open source. (It was gone last time I searched for it.)

The source was readable enough to reconstruct it by a bit of trial and error with bip_utils (which should hopefully give a more or less readable and maintained way of doing it).

Update:
I used my mnemonic and produced my receive base address!

Next step:
Extract skeys

Challenge:
Eternl can generate unused addresses?
I know Trezor suite is doing this very easily on other Ada accounts I have in cold storage.

In general, yes. They even added a function for the Midnight claim portal.

But: If you import with the skey file that corresponds to exactly one address. There is no account-level key from which to generate more, unused addresses.

So: I don’t see a way around this. Let’s just hope that the claim portal is flexible enough that you can just give another address in another wallet as that unused address. Then, you can just generate one in a non-Exodus wallet and use that.

If you generate an unused address changing the Address index m/44H/1815H/0H/0/0 to m/44H/1815/0/1 in command line generation

and use this one to produce a 2nd skey then you should have 2 wallets, one for each address in Eternl?

Then use these addresses to claim the drop on the midnight page, and sign with the first wallet. When you get the drop move the funds using the second wallet in Eternl?

Or are the unused addresses are something else?

Well, the skey import functionality only allows to import one combination of payment, stake, and governance key.
You cannot tell it to use another set of files and treat it as if it is a second address of the same wallet.

So, those would be two completely separate wallets from Eternl’s point of view.

And it will not report this address as unused address for the other, first wallet to the claim portal. So, you would still have to hope that you can just give an arbitrary address there.

But if you can, I would just use an address from a standard wallet. Much less hassle.

And Exodus would most probably also not recognise such a second address generated by hand.

I moved this conversation to a new topic since it had little to do with “Ledger Seed is different from Daedalus/Yoroi/Adalite seed” … and it could be quite interesting for other Exodus users on its own.

In case, you are still on it:

I managed to import my example wallet into Eternl with this:

from bip_utils import (Bip39SeedGenerator,
                       Bip32Slip10Secp256k1,
                       Cip1852, Cip1852Coins, Bip32KeyData,
                       CardanoShelley)
from bip_utils.cardano.bip32.cardano_byron_legacy_mst_key_generator import (
        CardanoByronLegacyMstKeyGenerator)

seed_phrase = ("abandon abandon abandon abandon abandon abandon "
               "abandon abandon abandon abandon abandon about")
# Derive root key according to BIP 39 and address key according to BIP 32:
bip39_seed_bytes = Bip39SeedGenerator(seed_phrase).Generate()
cardano_bip32_key = Bip32Slip10Secp256k1.FromSeedAndPath(bip39_seed_bytes,
                                                         "m/44'/1815'/0'/0/0")
cardano_bip32_private_bytes = cardano_bip32_key.PrivateKey().Raw().ToBytes()
# Used as seed bytes for legacy Byron master key derivation:
private_key, chain_code = (
        CardanoByronLegacyMstKeyGenerator.
        _CardanoByronLegacyMstKeyGenerator__HashRepeatedly(
            cardano_bip32_private_bytes, 1))
# Make Cip1852 object:
cip1852 = Cip1852.FromPrivateKey(private_key,
                                 Cip1852Coins.CARDANO_ICARUS,
                                 Bip32KeyData(5))
# Get the public key:
public_key = cip1852.PublicKey().RawCompressed().ToHex()
# Same key used for payment and stake key:
shelley_pair = CardanoShelley(cip1852, cip1852)
shelley_address = shelley_pair.PublicKeys().ToAddress()
print(f"Address: {shelley_address}")
# Create the key files:
cbor = f"5880{private_key.hex()}{public_key}{chain_code.hex()}"
with open('payment.skey', 'w') as payment_skey_file:
    payment_skey_file.write(
            '{\n'
            '    "type": "PaymentExtendedSigningKeyShelley_ed25519_bip32",\n'
            '    "description": "Exodus Signing Key",\n'
            f'    "cborHex": "{cbor}"\n'
            '}\n')
with open('stake.skey', 'w') as stake_skey_file:
    stake_skey_file.write(
            '{\n'
            '    "type": "StakeExtendedSigningKeyShelley_ed25519_bip32",\n'
            '    "description": "Exodus Signing Key",\n'
            f'    "cborHex": "{cbor}"\n'
            '}\n')

This produces two files – payment.skey and stake.skey – in the current directory. If I choose both of those files in Eternl’s “Import CLI Signing Keys”, Eternl derives the same address – addr1q9av2w6…m0pqxa – that is also shown in Exodus and derived by bip_utils:

This is not only useful for the Midnight claim (hopefully), but also in general when users want to import their Exodus wallets to Eternl.

1 Like

After importing it, it also works that it can be used as dApp account, but the function where the claim portal will expect an unused address gives a used address instead:


This is unavoidable: This account has only this single address. There is no possibility to create another one.

As said, hopefully, there will be a possibility to override that in the claim portal and send the tokens to another, actually unused address.

Lets hope

Also, I remember you had contacted Eternl devs to include ledger derivation. The optimal would be to have this done. For trezor especially.

Do you want Ledger or Trezor?

Trezor:

  • They just use the standard derivation if the seed phrase is shorter than 24 words.
  • For 24 words or longer, they had this bug (it was never intentional) that made the derivation different. Trezor Suite uses the correct standard derivation as the default for years, but most/all wallet apps still use the buggy version per default (presumably to not irritate users of old wallets). In Eternl, you can choose which root key derivation to use during pairing the Trezor – standard, legacy/buggy, or Ledger.

Both:

  • What we have done above for Exodus – deriving .skey files and importing them to Eternl – would also kind of work for Ledger and legacy/buggy Trezor wallets … as long as they are single address (multi-address would have to be imported as one wallet per address which is quite unusable).
  • Not sure if a more comfortable possibility is really what we should want: It is not a good idea to import hardware wallets by seed phrase. It should only be done in absolute emergencies. And no matter how many warnings you put around it, people will use it for years, anyway.

I am sorry,

I wanted to say if other wallets could include Exodus derivation.

  1. This would enable homogenising the wallet ownership, and making it immune to custom derivation algorithms.

This should increase trust in the chain. Your wallet is yours regardless of the software / app it was created with.

So it would be a very good thing to try having all wallets able to be derive addresses between them.

  1. On this particular case, it would solve the problem better as Eternl could restore the root key and have the full functionality with new addresses etc.