Skip to content

If I control my planet in bridge with a Hardware Wallet and I lose my master ticket can I regenerate it?

Answer

Azimuth has 5 separate public keys that are set. The Ownership address is set to the address inside your hardware wallet. If you rekey the master key you will

Answering

I logged into bridge with my Ethereum Wallet and learned I can transfer my master ticket. This text was pulled from bridge UI

Reticketing is the process of generating a completely fresh wallet and transferring ownership of your point to that wallet.

Beware, this resets your proxy addresses; if you're using smart contracts, this might break them! It will also change your networking keys!

This rekey's the entire planet, let's find what this does in the smart contracts. Let's find what the code is doing

  // configure management proxy

  const managementTx = azimuth.ecliptic.setManagementProxy(
    contracts,
    point,
    toWallet.management.keys.address
  );
  managementTx.gas = GAS_LIMITS.SET_PROXY;

  // set spawn & voting proxies situationally

  // skip this step if reticketing an L1 point with L2-migrated spawn proxy
  let txs = [transferTmpTx, keysTx, managementTx];
  if (!isPlanet(point) && doSetSpawnProxy) {
    const spawnTx = azimuth.ecliptic.setSpawnProxy(
      contracts,
      point,
      toWallet.spawn.keys.address
    );
    spawnTx.gas = GAS_LIMITS.SET_PROXY;
    txs.push(spawnTx);
  }

  if (isGalaxy(point)) {
    const votingTx = azimuth.ecliptic.setVotingProxy(
      contracts,
      point,
      toWallet.voting.keys.address
    );
    votingTx.gas = GAS_LIMITS.SET_PROXY;
    txs.push(votingTx);
  }

  // transfer configured point to user's new wallet

  const transferFinalTx = azimuth.ecliptic.transferPoint(
    contracts,
    point,
    toWallet.ownership.keys.address,
    false
  );
  transferFinalTx.gas = GAS_LIMITS.TRANSFER;
  txs.push(transferFinalTx);

  //
  // finalizing & signing transactions
  //

  progress(TRANSACTION_PROGRESS.SIGNING);

Seems like 3 transactions here

Performing Transfer for ~tartem-milteb

Why did we get 4 transactions?

transferPoint is called twice, I wonder if we actually needed to call it?

  //TODO no harm done if we already owned it, but should still get a bool arg
  //     for skipping this, if it isn't too big a burden for callers
  const transferTmpTx = azimuth.ecliptic.transferPoint(
    contracts,
    point,
    fromWallet.address,
    false
  );
  transferTmpTx.gas = GAS_LIMITS.TRANSFER;

  ...
  // transfer configured point to user's new wallet

  const transferFinalTx = azimuth.ecliptic.transferPoint(
    contracts,
    point,
    toWallet.ownership.keys.address,
    false
  );
  transferFinalTx.gas = GAS_LIMITS.TRANSFER;
  txs.push(transferFinalTx);

  //
  // finalizing & signing transactions
  //

What is this fromWallet and toWallet?

bridge/src/views/UrbitID/ResetKeys/ResetExecute.tsx at d49bb352dfd3219f6d7934530c6dc2cb3adc3f55 · urbit/bridge

      } else {
        await reticketPointBetweenWallets({
          fromWallet: need.wallet(wallet),
          fromWalletType: walletType,
          fromWalletHdPath: walletHdPath,
          toWallet: newWallet.value.wallet,
          point: point,
          web3: need.web3(web3),
          contracts: need.contracts(contracts),
          networkType,
          onUpdate: handleUpdate,
          nextRevision: networkRevision + 1,
          txnSigner,
          txnSender,
        });
      }
    } catch (err) {
      console.error(err);
      setGeneralError(err);

I just went and generated the public key from the Management Proxy, that is the management address

You can use this script with ethers@5.3 to generate the address

const ethers = require('ethers');

async function main() {
  // Load the mnemonic from the .env file
  let mnemonic = "MNEMONIC GOES HERE"
  let mnemonic_path = process.env.MNEMONIC_PATH
  if (mnemonic_path == ''){
    mnemonic_path = "m/44'/60'/0'/0"
  }
  if (!mnemonic) {
    throw new Error('MNEMONIC not found in .env file');
  }

  const wallet = ethers.Wallet.fromMnemonic(mnemonic, mnemonic_path);
  console.log('Wallet address:', wallet.address);
}

main().catch((error) => {
  console.error('Error:', error);
  process.exit(1);
});

Alright so why do we have a MASTER TICKET and a MANAGEMENT PROXY

I just realized that the ethereum is inside both the MASTER TICKET and MANAGEMENT PROXY

It is pretty clear what transactions in the Bridge code set the Master Ticket and Management Ticket,

It appears I can change ownership and management keys without having to reset network keys, interesting.

What does this azimuth.ecliptic.setSpawnProxy do

Gotta check azimuth-js

Code search results

Seems that setSpawnProxy just calls the smart contract, let's take a look at the source code

azimuth/contracts/Azimuth.sol at bcf1d7bcf64cd73a3688434feb786be39a116819 · urbit/azimuth

Oh this makes sense now take a look at this

azimuth/contracts/Azimuth.sol at bcf1d7bcf64cd73a3688434feb786be39a116819 · urbit/azimuth

  struct Deed
  {
    //  owner: address that owns this point
    //
    address owner;

    //  managementProxy: 0, or another address with the right to perform
    //                   low-impact, managerial operations on this point
    //
    address managementProxy;

    //  spawnProxy: 0, or another address with the right to spawn children
    //              of this point
    //
    address spawnProxy;

    //  votingProxy: 0, or another address with the right to vote as this point
    //
    address votingProxy;

    //  transferProxy: 0, or another address with the right to transfer
    //                 ownership of this point
    //
    address transferProxy;
  }

Urbit HD Wallet Source: Urbit HD Wallet • Reference • developers.urbit.org

There are 5 Wallets, now why do we 5 keys.

Owner, Transfer, Spawn, Management, Voting

I feel like we only need

Owner, Management, and Voting

I reset my master ticket, so that reset everything

Ownership and Management are the only keys accessible from Bridge

So what does this Transfer key do, what does this Voting key do, what does this Spawn key do?

Wait so how do I reset networking keys?

Oh SPAWN is used to MOONS

So what is the difference between MANAGEMENT and TRANSFER

You want a backup key, if OWNERSHIP seed is lost TRANSFER seed can allow the point to be reset. THE OWNERSHIP seed can CHANGE the TRANSFER address but not vice versa.

Okay I understand the 5 different keys now

2023-07-15T02:09:42-04:00

So Tlon, why does bridge set the spawn address when we are not going to be generating any moons any time soon!?!?!?!

Wait what is the Spawn address actually set to?

        await reticketPointBetweenWallets({
          fromWallet: need.wallet(wallet),
          fromWalletType: walletType,
          fromWalletHdPath: walletHdPath,
          toWallet: f.value.wallet,
          point: point,
          web3: need.web3(web3),
          contracts: need.contracts(contracts),
          networkType,
          onUpdate: handleUpdate,
          nextRevision: networkRevision + 1,
          txnSigner,
          txnSender,
        });

well this toWallet thing generates a wallet for it

What is this toWallet!?!?!

bridge/src/views/UrbitID/ResetKeys/ResetExecute.tsx at d49bb352dfd3219f6d7934530c6dc2cb3adc3f55 · urbit/bridge

interface ResetExecuteProps {
  // a Maybe<UrbitWallet>
  newWallet: any;
  // a useState setter, accepts Maybe<UrbitWallet>
  setNewWallet: (args: any) => {};
}

ResetExecute is called in bridge/src/views/UrbitID/ResetKeys.jsx at d49bb352dfd3219f6d7934530c6dc2cb3adc3f55 · urbit/bridge ResetKeys.jsx has a setNewWallet function _setNewWallet seems to be something We have a provider managing state

import { LocalRouterProvider } from 'lib/LocalRouter';

bridge/src/lib/LocalRouter.ts at d49bb352dfd3219f6d7934530c6dc2cb3adc3f55 · urbit/bridge Shit it is empty Remember providers have functions to update state

Finally found how the EVM addresses are generated bridge/src/lib/walletgen.ts at d49bb352dfd3219f6d7934530c6dc2cb3adc3f55 · urbit/bridge

Oh the wallet generation is all in a separate repo, urbit/urbit-key-generation: Key derivation and HD wallet generation functions for Urbit