Skip to content

Commit

Permalink
post multisig run through updates
Browse files Browse the repository at this point in the history
  • Loading branch information
kaladinlight committed Jul 24, 2024
1 parent a9faad7 commit 26d2b22
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 55 deletions.
28 changes: 18 additions & 10 deletions cli/MultiSig.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
## Prerequisites

- Install golang: https://go.dev/doc/install
- Install golang (v1.22): https://go.dev/doc/install

## Clone and Build

```bash
git clone https://gitlab.com/thorchain/thornode.git
cd thornode/cmd/thornode
cd thornode
git checkout develop
git pull
cd cmd/thornode
go build --tags cgo,ledger
```

Expand All @@ -22,8 +25,12 @@ go build --tags cgo,ledger
```
- Import signer pubkeys:
```bash
./thornode keys add {person2} --pubkey {pubkey}
./thornode keys add {person3} --pubkey {pubkey}
./thornode keys add {person2} --pubkey '{person2_pubkey}'
./thornode keys add {person3} --pubkey '{person3_pubkey}'
```
- View keys to validate:
```bash
./thornode keys list
```
- Add multisig key:
```bash
Expand All @@ -38,29 +45,30 @@ go build --tags cgo,ledger

- Person 1 signs:
```bash
./thornode tx sign --from {person1} --multisig multisig {unsignedTx_epoch-N.json} --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --from ledger --ledger --sign-mode amino-json > signedTx_{person1}.json
./thornode tx sign --from {person1} --multisig multisig ~/rfox/unsignedTx_epoch-{N}.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --ledger --sign-mode amino-json > ~/rfox/signedTx_epoch-{N}_{person1}.json
```
- Person 2 signs:
```bash
./thornode tx sign --from {person2} --multisig multisig {unsignedTx_epoch-N.json} --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --from ledger --ledger --sign-mode amino-json > signedTx_{person2}.json
./thornode tx sign --from {person2} --multisig multisig ~/rfox/unsignedTx_epoch-{N}.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --ledger --sign-mode amino-json > ~/rfox/signedTx_epoch-{N}_{person2}.json
```
- Multisign:
```bash
./thornode tx multisign {unsignedTx_epoch-N.json} multisig signedTx_{person1}.json signedTx_{person2}.json --from multisig --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc > signedTx_multisig.json
./thornode tx multisign ~/rfox/unsignedTx_epoch-{N}.json multisig ~/rfox/signedTx_epoch-{N}_{person1}.json ~/rfox/signedTx_epoch-{N}_{person2}.json --from multisig --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc > ~/rfox/signedTx_epoch-{N}_multisig.json
```

## Send Transaction

- Simulate transaction:

```bash
./thornode tx broadcast signedTx_multisig.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --gas auto --dry-run > simulatedTx.json
./thornode tx broadcast ~/rfox/signedTx_epoch-{N}_multisig.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --dry-run > ~/rfox/simulatedTx_epoch-{N}.json
```

- Validate contents of `simulatedTx.json` for accuracy before broadcasting

- Broadcast transaction:
```bash
./thornode tx broadcast signedTx_multisig.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --gas auto > tx.json
./thornode tx broadcast ~/rfox/signedTx_epoch-{N}_multisig.json --chain-id thorchain-mainnet-v1 --node https://daemon.thorchain.shapeshift.com:443/rpc --gas auto > tx.json
```
- Copy the `txhash` value from `tx.json` to supply to the cli in order to continue

At this point, the cli should pick up the funding transaction and continue running the distribution from the hot wallet.
37 changes: 22 additions & 15 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { isEpochDistributionStarted } from './file'
import { IPFS } from './ipfs'
import { error, info, success, warn } from './logging'
import { create, recoverKeystore } from './mnemonic'
import { EpochWithHash } from './types'
import { Epoch, RFOXMetadata } from './types'
import { Wallet } from './wallet'

const processEpoch = async () => {
Expand Down Expand Up @@ -109,14 +109,15 @@ const processEpoch = async () => {
const run = async () => {
const ipfs = await IPFS.new()

const epoch = await ipfs.getEpochFromMetadata()
const metadata = await ipfs.getMetadata('process')
const epoch = await ipfs.getEpochFromMetadata(metadata)

if (isEpochDistributionStarted(epoch.number)) {
const confirmed = await prompts.confirm({
message: 'It looks like you have already started a distribution for this epoch. Do you want to continue? ',
})

if (confirmed) return recover(epoch)
if (confirmed) return recover(metadata)

info(`Please move or delete all existing files for epoch-${epoch.number} from ${RFOX_DIR} before re-running.`)
warn('This action should never be taken unless you are absolutely sure you know what you are doing!!!')
Expand All @@ -137,22 +138,24 @@ const run = async () => {

const wallet = await Wallet.new(mnemonic)

await processDistribution(epoch, wallet, ipfs)
await processDistribution(metadata, epoch, wallet, ipfs)
}

const recover = async (epoch?: EpochWithHash) => {
const recover = async (metadata?: RFOXMetadata) => {
const ipfs = await IPFS.new()

if (!epoch) {
epoch = await ipfs.getEpochFromMetadata()
if (!metadata) {
metadata = await ipfs.getMetadata('process')
}

const epoch = await ipfs.getEpochFromMetadata(metadata)

const keystoreFile = path.join(RFOX_DIR, `keystore_epoch-${epoch.number}.txt`)
const mnemonic = await recoverKeystore(keystoreFile)

const wallet = await Wallet.new(mnemonic)

await processDistribution(epoch, wallet, ipfs)
await processDistribution(metadata, epoch, wallet, ipfs)
}

const update = async () => {
Expand All @@ -170,18 +173,22 @@ const update = async () => {
)
}

const processDistribution = async (epoch: EpochWithHash, wallet: Wallet, ipfs: IPFS) => {
await wallet.fund(epoch)
const processedEpoch = await wallet.distribute(epoch)
const processDistribution = async (metadata: RFOXMetadata, epoch: Epoch, wallet: Wallet, ipfs: IPFS) => {
const epochHash = metadata.ipfsHashByEpoch[epoch.number]

const processedEpochHash = await ipfs.addEpoch(processedEpoch)
const metadata = await ipfs.getMetadata('process')
await wallet.fund(epoch, epochHash)
const processedEpoch = await wallet.distribute(epoch, epochHash)

const hash = await ipfs.updateMetadata(metadata, {
const processedEpochHash = await ipfs.addEpoch({
...processedEpoch,
distributionStatus: 'complete',
})

const metadataHash = await ipfs.updateMetadata(metadata, {
epoch: { number: processedEpoch.number, hash: processedEpochHash },
})

if (!hash) return
if (!metadataHash) return

success(`rFOX reward distribution for Epoch #${processedEpoch.number} has been completed!`)

Expand Down
22 changes: 4 additions & 18 deletions cli/src/ipfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PinataClient from '@pinata/sdk'
import axios from 'axios'
import BigNumber from 'bignumber.js'
import { error, info } from './logging'
import { Epoch, EpochWithHash, RFOXMetadata, RewardDistribution } from './types'
import { Epoch, RFOXMetadata, RewardDistribution } from './types'
import { MONTHS } from './constants'

const PINATA_API_KEY = process.env['PINATA_API_KEY']
Expand Down Expand Up @@ -99,7 +99,7 @@ export class IPFS {
}
}

async getEpoch(hash?: string): Promise<EpochWithHash> {
async getEpoch(hash?: string): Promise<Epoch> {
if (!hash) {
hash = await prompts.input({
message: 'What is the IPFS hash for the rFOX epoch you want to process? ',
Expand Down Expand Up @@ -127,7 +127,7 @@ export class IPFS {
`Running ${month} rFOX reward distribution for Epoch #${data.number}:\n - Total Rewards: ${totalRewards} RUNE\n - Total Addresses: ${totalAddresses}`,
)

return { ...data, hash }
return data
} else {
error(`The contents of IPFS hash (${hash}) are not valid epoch contents, exiting.`)
process.exit(1)
Expand All @@ -153,18 +153,6 @@ export class IPFS {
metadata.epochEndTimestamp = overrides.metadata.epochEndTimestamp

if (overrides.epoch) {
const hash = metadata.ipfsHashByEpoch[overrides.epoch.number]

if (hash) {
info(`The metadata already contains an IPFS hash for this epoch: ${hash}`)

const confirmed = await prompts.confirm({
message: `Do you want to update the metadata with the new IPFS hash: ${overrides.epoch.hash}?`,
})

if (!confirmed) return
}

metadata.ipfsHashByEpoch[overrides.epoch.number] = overrides.epoch.hash

const { IpfsHash } = await this.client.pinJSONToIPFS(metadata, {
Expand Down Expand Up @@ -308,9 +296,7 @@ export class IPFS {
}
}

async getEpochFromMetadata(): Promise<EpochWithHash> {
const metadata = await this.getMetadata('process')

async getEpochFromMetadata(metadata: RFOXMetadata): Promise<Epoch> {
const hash = metadata.ipfsHashByEpoch[metadata.epoch - 1]

if (!hash) {
Expand Down
2 changes: 0 additions & 2 deletions cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,3 @@ export type Epoch = {
/** A record of staking address to reward distribution for this epoch */
distributionsByStakingAddress: Record<string, RewardDistribution>
}

export type EpochWithHash = Epoch & { hash: string }
20 changes: 10 additions & 10 deletions cli/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ora, { Ora } from 'ora'
import { RFOX_DIR } from './constants'
import { read, write } from './file'
import { error, info, success } from './logging'
import { EpochWithHash } from './types'
import { Epoch } from './types'

const BIP32_PATH = `m/44'/931'/0'/0/0`
const SHAPESHIFT_MULTISIG_ADDRESS = 'thor1xmaggkcln5m5fnha2780xrdrulmplvfrz6wj3l'
Expand Down Expand Up @@ -70,7 +70,7 @@ export class Wallet {
}
}

private async buildFundingTransaction(amount: string, epoch: EpochWithHash) {
private async buildFundingTransaction(amount: string, epoch: Epoch, hash: string) {
const { address } = await this.getAddress()

return {
Expand All @@ -88,7 +88,7 @@ export class Wallet {
],
},
],
memo: `Fund rFOX rewards distribution - Epoch #${epoch.number} (IPFS Hash: ${epoch.hash})`,
memo: `Fund rFOX rewards distribution - Epoch #${epoch.number} (IPFS Hash: ${hash})`,
timeout_height: '0',
extension_options: [],
non_critical_extension_options: [],
Expand All @@ -106,7 +106,7 @@ export class Wallet {
}
}

async fund(epoch: EpochWithHash) {
async fund(epoch: Epoch, epochHash: string) {
const { address } = await this.getAddress()

const distributions = Object.values(epoch.distributionsByStakingAddress)
Expand Down Expand Up @@ -152,7 +152,7 @@ export class Wallet {

if (await isFunded()) return

const unsignedTx = await this.buildFundingTransaction(totalAmount, epoch)
const unsignedTx = await this.buildFundingTransaction(totalAmount, epoch, epochHash)
const unsignedTxFile = path.join(RFOX_DIR, `unsignedTx_epoch-${epoch.number}.json`)

write(unsignedTxFile, JSON.stringify(unsignedTx, null, 2))
Expand All @@ -173,7 +173,7 @@ export class Wallet {
})()
}

private async signTransactions(epoch: EpochWithHash): Promise<TxsByStakingAddress> {
private async signTransactions(epoch: Epoch, epochHash: string): Promise<TxsByStakingAddress> {
const txsFile = path.join(RFOX_DIR, `txs_epoch-${epoch.number}.json`)
const txs = read(txsFile)

Expand Down Expand Up @@ -230,7 +230,7 @@ export class Wallet {
amount: [],
gas: '0',
},
memo: `rFOX reward (Staking Address: ${stakingAddress}) - Epoch #${epoch.number} (IPFS Hash: ${epoch.hash})`,
memo: `rFOX reward (Staking Address: ${stakingAddress}) - Epoch #${epoch.number} (IPFS Hash: ${epochHash})`,
signatures: [],
},
}
Expand Down Expand Up @@ -273,7 +273,7 @@ export class Wallet {
return txsByStakingAddress
}

async broadcastTransactions(epoch: EpochWithHash, txsByStakingAddress: TxsByStakingAddress): Promise<EpochWithHash> {
async broadcastTransactions(epoch: Epoch, txsByStakingAddress: TxsByStakingAddress): Promise<Epoch> {
const totalTxs = Object.values(epoch.distributionsByStakingAddress).length
const spinner = ora(`Broadcasting ${totalTxs} transactions...`).start()

Expand Down Expand Up @@ -330,8 +330,8 @@ export class Wallet {
return epoch
}

async distribute(epoch: EpochWithHash): Promise<EpochWithHash> {
const txsByStakingAddress = await this.signTransactions(epoch)
async distribute(epoch: Epoch, epochHash: string): Promise<Epoch> {
const txsByStakingAddress = await this.signTransactions(epoch, epochHash)
return this.broadcastTransactions(epoch, txsByStakingAddress)
}
}

0 comments on commit 26d2b22

Please sign in to comment.