Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add metadata update flow and final tweaks #81

Merged
merged 2 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions cli/MultiSig.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
## Prerequisites

- Install golang: https://go.dev/doc/install
- Install golang (v1.22): https://go.dev/doc/install
- Create common rfox directory in your home directory. This is where all output files from the script will be stored and where shared files (unsigned transactions, signatures, signed transactions, etc.) should be saved.
```bash
mkdir ~/rfox
```

## 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 +29,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:
```bash
./thornode keys list
```
- Add multisig key:
```bash
Expand All @@ -38,29 +49,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.
79 changes: 58 additions & 21 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 { Epoch } from './types'
import { Epoch, RFOXMetadata } from './types'
import { Wallet } from './wallet'

const processEpoch = async () => {
Expand All @@ -21,7 +21,7 @@ const processEpoch = async () => {

const month = MONTHS[new Date(metadata.epochStartTimestamp).getUTCMonth()]

info(`Processing Epoch #${metadata.epoch} for ${month} distribution.`)
info(`Processing rFOX Epoch #${metadata.epoch} for ${month} distribution.`)

const now = Date.now()
if (metadata.epochEndTimestamp > now) {
Expand Down Expand Up @@ -88,7 +88,7 @@ const processEpoch = async () => {

const nextEpochStartDate = new Date(metadata.epochEndTimestamp + 1)

await ipfs.updateMetadata(metadata, {
const hash = await ipfs.updateMetadata(metadata, {
epoch: { number: metadata.epoch, hash: epochHash },
metadata: {
epoch: metadata.epoch + 1,
Expand All @@ -97,6 +97,8 @@ const processEpoch = async () => {
},
})

if (!hash) return

success(`rFOX Epoch #${metadata.epoch} has been processed!`)

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

const epoch = await ipfs.getEpoch()
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 @@ -135,30 +138,57 @@ const run = async () => {

const wallet = await Wallet.new(mnemonic)

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

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

if (!epoch) epoch = await ipfs.getEpoch()
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 processDistribution = async (epoch: Epoch, wallet: Wallet, ipfs: IPFS) => {
await wallet.fund(epoch)
const processedEpoch = await wallet.distribute(epoch)
const update = async () => {
const ipfs = await IPFS.new()

const processedEpochHash = await ipfs.addEpoch(processedEpoch)
const metadata = await ipfs.getMetadata('update')
const hash = await ipfs.updateMetadata(metadata)

if (!hash) return

success(`rFOX metadata has been updated!`)

info(
'Please update the rFOX Wiki (https://github.com/shapeshift/rFOX/wiki/rFOX-Metadata) and notify the DAO accordingly. Thanks!',
)
}

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

await wallet.fund(epoch, epochHash)
const processedEpoch = await wallet.distribute(epoch, epochHash)

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

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

await ipfs.updateMetadata(metadata, { epoch: { number: processedEpoch.number, hash: processedEpochHash } })
if (!metadataHash) return

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

Expand All @@ -183,23 +213,28 @@ const main = async () => {
}
}

const choice = await prompts.select<'process' | 'run' | 'recover'>({
const choice = await prompts.select<'process' | 'run' | 'recover' | 'update'>({
message: 'What do you want to do?',
choices: [
{
name: 'Process rFox epoch',
name: 'Process rFOX epoch',
value: 'process',
description: 'Start here to process a completed rFox epoch',
description: 'Start here to process an rFOX epoch.',
},
{
name: 'Run rFox distribution',
name: 'Run rFOX distribution',
value: 'run',
description: 'Start here to begin running a new rFox rewards distribution',
description: 'Start here to run an rFOX rewards distribution.',
},
{
name: 'Recover rFox distribution',
name: 'Recover rFOX distribution',
value: 'recover',
description: 'Start here to recover an in progress rFox rewards distribution',
description: 'Start here to recover an rFOX rewards distribution.',
},
{
name: 'Update rFOX metadata',
value: 'update',
description: 'Start here to update an rFOX metadata.',
},
],
})
Expand All @@ -211,6 +246,8 @@ const main = async () => {
return run()
case 'recover':
return recover()
case 'update':
return update()
default:
error(`Invalid choice: ${choice}, exiting.`)
process.exit(1)
Expand Down
Loading