Skip to content

Commit

Permalink
Place multiple bids on a name in same block (#477)
Browse files Browse the repository at this point in the history
  • Loading branch information
rithvikvibhu authored Jun 29, 2022
1 parent 6ac75bb commit 6b284e0
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 101 deletions.
1 change: 1 addition & 0 deletions app/background/wallet/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const clientStub = ipcRendererInjector => makeClient(ipcRendererInjector,
'getTransactionHistory',
'getPendingTransactions',
'getBids',
'getBlind',
'getMasterHDKey',
'hasAddress',
'setPassphrase',
Expand Down
6 changes: 6 additions & 0 deletions app/background/wallet/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,11 @@ class WalletService {
return {bids, filter};
};

getBlind = async (blind) => {
const wallet = await this.node.wdb.get(this.name);
return wallet.getBlind(Buffer.from(blind, 'hex'));
};

getMasterHDKey = () => this._ledgerDisabled(
'cannot get HD key for watch-only wallet',
() => this.client.getMaster(this.name),
Expand Down Expand Up @@ -1615,6 +1620,7 @@ const methods = {
getTransactionHistory: service.getTransactionHistory,
getPendingTransactions: service.getPendingTransactions,
getBids: service.getBids,
getBlind: service.getBlind,
getMasterHDKey: service.getMasterHDKey,
hasAddress: service.hasAddress,
setPassphrase: service.setPassphrase,
Expand Down
14 changes: 9 additions & 5 deletions app/components/SuccessModal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import Blocktime from '../Blocktime';
import './SuccessModal.scss';
import {I18nContext} from "../../utils/i18n";

const modalRoot = document.querySelector('#modal-root');

Expand All @@ -22,7 +23,10 @@ class SuccessModal extends Component {
revealStartBlock: '0',
};

static contextType = I18nContext;

render() {
const {t} = this.context;
const { className, onClose, bidAmount, maskAmount, revealStartBlock } = this.props;

return ReactDOM.createPortal(
Expand All @@ -31,15 +35,15 @@ class SuccessModal extends Component {
<div className='success_modal__close_icon' onClick={onClose} />
<div className='success_modal__headline'>
<div className='success_modal__success_icon' />
<div className='success_modal__headline__title'>Bid Placed</div>
<div className='success_modal__description'>Your Bid</div>
<div className='success_modal__headline__title'>{t('bidPlaced')}</div>
<div className='success_modal__description'>{t('yourBid')}</div>
<div className='success_modal__value'>{`${bidAmount} HNS`}</div>
<div className='success_modal__description'>Your Mask</div>
<div className='success_modal__description'>{t('lockup')}</div>
<div className='success_modal__value'>{maskAmount? `${maskAmount} HNS` : ' - '}</div>
<div className='success_modal__reveal_wrapper'>
<div className='success_modal__description'>Reveal Start:</div>
<div className='success_modal__description'>{t('revealStart')}:</div>
<div className='success_modal__value'><Blocktime height={revealStartBlock} fromNow /></div>
<div className='success_modal__value--date'>Block # {revealStartBlock}</div>
<div className='success_modal__value--date'>{t('block')} #{revealStartBlock}</div>
</div>
</div>
</div>
Expand Down
61 changes: 1 addition & 60 deletions app/ducks/namesReducer.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import { SET_PENDING_TRANSACTIONS } from './walletReducer';
import { hashName } from 'hsd/lib/covenants/rules';

const ALLOWED_COVENANTS = new Set([
'OPEN',
'BID',
'REVEAL',
'UPDATE',
'REGISTER',
'RENEW',
'REDEEM',
'TRANSFER',
'FINALIZE',
]);

export const SET_NAME = 'app/names/setName';


Expand All @@ -33,53 +21,6 @@ function reduceSetName(state, action) {
};
}

function reducePendingTransactions(state, action) {
const pendingOperationsByHash = {};
const pendingOpMetasByHash = {};
const pendingOutputByHash = {};

for (const {tx} of action.payload) {
for (const output of tx.outputs) {
if (ALLOWED_COVENANTS.has(output.covenant.action)) {
pendingOperationsByHash[output.covenant.items[0]] = output.covenant.action;
pendingOpMetasByHash[output.covenant.items[0]] = output.covenant;
pendingOutputByHash[output.covenant.items[0]] = output;
break;
}
}
}

const names = Object.keys(state);
const newNames = {};
for (const name of names) {
const data = state[name];
const hash = data.hash;
const pendingOp = pendingOperationsByHash[hash];
const pendingCovenant = pendingOpMetasByHash[hash];
const pendingOutput = pendingOutputByHash[hash];
const pendingOperationMeta = {};

if (pendingOp === 'UPDATE' || pendingOp === 'REGISTER') {
pendingOperationMeta.data = pendingCovenant.items[2];
}

if (pendingOp === 'REVEAL') {
pendingOperationMeta.output = pendingOutput;
}

newNames[name] = {
...data,
pendingOperation: pendingOp || null,
pendingOperationMeta: pendingOperationMeta,
};
}

return {
...state,
...newNames
};
}

function getInitialState() {
return {}
}
Expand All @@ -89,7 +30,7 @@ export default function namesReducer(state = getInitialState(), action) {
case SET_NAME:
return reduceSetName(state, action);
case SET_PENDING_TRANSACTIONS:
return reducePendingTransactions(state, action);
return action.payload;
default:
return state;
}
Expand Down
111 changes: 109 additions & 2 deletions app/ducks/walletActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,16 @@ export const fetchTransactions = () => async (dispatch, getState) => {
};

export const fetchPendingTransactions = () => async (dispatch, getState) => {
if (!getState().wallet.initialized) {
const state = getState();

if (!state.wallet.initialized) {
return;
}

const payload = await walletClient.getPendingTransactions();
const pendingTxs = await walletClient.getPendingTransactions();
const payload = await processPendingTransactions(state.names, pendingTxs);

// SET_PENDING_TRANSACTIONS takes payload to replace `state.names`
dispatch({
type: SET_PENDING_TRANSACTIONS,
payload: payload || [],
Expand Down Expand Up @@ -607,3 +612,105 @@ async function nameByHash(net, covenant) {

return name;
}

// For processPendingTransactions
const ALLOWED_COVENANTS = new Set([
'OPEN',
'BID',
'REVEAL',
'UPDATE',
'REGISTER',
'RENEW',
'REDEEM',
'TRANSFER',
'FINALIZE',
]);

/**
* Process Pending Transactions
* Parse covenant values as needed and add `pendingOperation[Meta]` to state.names
* @param {Object} names state.names
* @param {TX[]} pendingTxs result of walletClient.getPendingTransactions()
* @returns {Object} state.names
*/
async function processPendingTransactions(names, pendingTxs) {
const pendingOperationsByHash = {};
const pendingOpMetasByHash = {};
const pendingOutputByHash = {};

for (const {tx} of pendingTxs) {
for (const output of tx.outputs) {
if (ALLOWED_COVENANTS.has(output.covenant.action)) {
const hash = output.covenant.items[0];

// Store multiple bids
if (output.covenant.action === 'BID') {
pendingOperationsByHash[hash] = output.covenant.action;
pendingOpMetasByHash[hash] = [...(pendingOpMetasByHash[hash] || []), output.covenant];
pendingOutputByHash[hash] = [...(pendingOutputByHash[hash] || []), output];
} else {
pendingOperationsByHash[hash] = output.covenant.action;
pendingOpMetasByHash[hash] = output.covenant;
pendingOutputByHash[hash] = output;
}

break;
}
}
}

const oldNames = Object.keys(names);
const newNames = {};
for (const name of oldNames) {
const data = names[name];
const hash = data.hash;
const pendingOp = pendingOperationsByHash[hash];
const pendingCovenant = pendingOpMetasByHash[hash];
const pendingOutput = pendingOutputByHash[hash];
const pendingOperationMeta = {};

if (pendingOp === 'UPDATE' || pendingOp === 'REGISTER') {
pendingOperationMeta.data = pendingCovenant.items[2];
}

if (pendingOp === 'REVEAL') {
pendingOperationMeta.output = pendingOutput;
}

if (pendingOp === 'BID') {
const promises = pendingOutput.map(async output => {
const blind = output.covenant.items[3];
const bv = await walletClient.getBlind(blind);

return {
value: output.value,
height: -1,
from: output.address,
date: null,
bid: {
value: bv?.value || null,
prevout: null,
own: true,
namehash: hash,
name: name,
lockup: output.value,
blind: blind,
},
}
});

pendingOperationMeta.bids = await Promise.all(promises);
}

newNames[name] = {
...data,
pendingOperation: pendingOp || null,
pendingOperationMeta: pendingOperationMeta,
};
}

return {
...names,
...newNames,
};
}
Loading

0 comments on commit 6b284e0

Please sign in to comment.