Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.
Draft
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
1 change: 1 addition & 0 deletions both/i18n/en-us.i18n.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ chainStatus:
outOfValidators: 'out of {$totalValidators} validators'
onlineVotingPower: 'Online Voting Power'
fromTotalStakes: '{$percent} from {$totalStakes} {$denomPlural}'
totalAccounts: 'Cosmos Accounts (Total)'
analytics:
blockTimeHistory: 'Block Time History'
averageBlockTime: 'Average Block Time'
Expand Down
2 changes: 2 additions & 0 deletions client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import App from '/imports/ui/App.jsx';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom'
// import ReactDOM from 'react-dom';
import { getCosmosAccountsNumber } from '../imports/ui/home/CosmosAccounts'

import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
Expand All @@ -31,4 +32,5 @@ Meteor.startup(() => {
// </Router>, document.getElementById('app')
// );
// });
setTimeout(getCosmosAccountsNumber, 60000);
});
24 changes: 24 additions & 0 deletions imports/api/chain/server/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,28 @@ Meteor.methods({
this.unblock();
Chain.find().sort({created:-1}).limit(1);
},
'chain.shouldUpdateCosmosAccountsNumber': function () {
this.unblock();
let date = new Date();
let chain = Chain.find().fetch();
let lastUpdated = chain?.lastUpdated ? new Date(chain?.lastUpdated) : new Date();
let timeDifference = moment(date).diff(moment(lastUpdated), 'hours');
let shouldUpdate = timeDifference >= 24 ? true : false;
return shouldUpdate;
},
'chain.getCosmosAccountsNumber': function (totalNumberOfAccountsIndex) {
this.unblock();
let date = new Date();
let dateUTC = date.toUTCString();
let totalNumberOfCosmosAccounts = {
total: totalNumberOfAccountsIndex,
lastUpdated: dateUTC
}
try {
Chain.upsert({ chainId: Meteor.settings.public.chainId }, { $set: { "totalNumberOfCosmosAccounts": totalNumberOfCosmosAccounts } });
}
catch (e) {
console.log(e);
}
},
})
27 changes: 17 additions & 10 deletions imports/ui/home/ChainStatus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export default class ChainStatus extends React.Component {
numValidators: this.props.status.validators,
totalNumValidators: this.props.status.totalValidators,
bondedTokens: this.props.states.bondedTokens,
totalSupply: this.props.states.totalSupply
totalSupply: this.props.states.totalSupply,
totalNumberOfCosmosAccounts: this.props.status.totalNumberOfCosmosAccounts
})

switch (this.state.avgBlockTimeType){
Expand Down Expand Up @@ -153,16 +154,13 @@ export default class ChainStatus extends React.Component {
if (this.props.statusExist && this.props.status.prevotes){
return(
<Row className="status text-center">
<Col lg={3} md={6}>
<Col lg={4} md={6}>
<Card body>
<CardTitle><T>chainStatus.latestHeight</T></CardTitle>
<CardText>
<span className="display-4 value text-primary">{this.state.blockHeight}</span>
{this.state.blockTime}
</CardText>
<CardTitle><T>chainStatus.totalAccounts</T></CardTitle>
<CardText><span className="display-4 value text-primary">{this.state.totalNumberOfCosmosAccounts?.total ?? 0}</span>{this.state.totalNumberOfCosmosAccounts?.lastUpdated ?? new Date().toUTCString()}</CardText>
</Card>
</Col>
<Col lg={3} md={6}>
<Col lg={4} md={6}>
<Card body>
<UncontrolledDropdown size="sm" className="more">
<DropdownToggle>
Expand All @@ -181,13 +179,22 @@ export default class ChainStatus extends React.Component {
</CardText>
</Card>
</Col>
<Col lg={3} md={6}>
<Col lg={4} md={6}>
<Card body>
<CardTitle><T>chainStatus.activeValidators</T></CardTitle>
<CardText><span className="display-4 value text-primary">{this.state.numValidators}</span><T totalValidators={this.state.totalNumValidators}>chainStatus.outOfValidators</T></CardText>
</Card>
</Col>
<Col lg={3} md={6}>
<Col lg={6} md={6}>
<Card body>
<CardTitle><T>chainStatus.latestHeight</T></CardTitle>
<CardText>
<span className="display-4 value text-primary">{this.state.blockHeight}</span>
{this.state.blockTime}
</CardText>
</Card>
</Col>
<Col lg={6} md={6}>
<Card body>
<UncontrolledDropdown size="sm" className="more">
<DropdownToggle>
Expand Down
208 changes: 208 additions & 0 deletions imports/ui/home/CosmosAccounts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/* eslint-disable camelcase */
import { Meteor } from 'meteor/meteor';
import 'babel-polyfill';
import { getNewWalletFromSeed } from "@lunie/cosmos-keys"
import { SigningStargateClient, assertIsBroadcastTxSuccess } from "@cosmjs/stargate"
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";

export const DEFAULT_GAS_PRICE = parseFloat(Meteor.settings.public.ledger.gasPrice) || 0.025;
export const DEFAULT_MEMO = 'Sent via Big Dipper'
const RPC = Meteor?.settings?.public?.remote?.rpc
const COINTYPE = Meteor?.settings?.public?.ledger?.coinType
const seed = Meteor?.settings?.private?.seed;
const options = { prefix: 'cosmos' };
const bech32prefix = 'cosmos';

getFromAddress = () => {
let hdpath = `m/44'/${COINTYPE}'/0'/0/0`
const { cosmosAddress, privateKey, publicKey } = getNewWalletFromSeed(seed, bech32prefix, hdpath)
return { cosmosAddress, privateKey, publicKey }
}

getToAddress = (accountIndex) => {
let hdpath = `m/44'/${COINTYPE}'/${accountIndex}'/0/0`
const { cosmosAddress, privateKey, publicKey } = getNewWalletFromSeed(seed, bech32prefix, hdpath)
return { cosmosAddress, privateKey, publicKey }
}

async function fetchCosmosAccountsNumber(accountIndex){
let sendFromAddress = this.getFromAddress();
let sendToAddress = this.getToAddress(accountIndex);
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(seed);
const client = await SigningStargateClient.connectWithSigner(RPC, wallet, options);
const amount = [{ amount: "1", denom: "uatom" }]
const fee = {
amount: [{ amount: "100", denom: "uatom" }],
gas: "100000",
}
const sendMsg = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: {
fromAddress: sendFromAddress.cosmosAddress,
toAddress: sendToAddress.cosmosAddress,
amount: [...amount],
},
};
try {
let signMessage = await client.signAndBroadcast(sendFromAddress.cosmosAddress, [sendMsg], fee, DEFAULT_MEMO);
assertIsBroadcastTxSuccess(signMessage);
}
catch (e) {
console.log(e)
}
try {
const accountNumber = await client.getSequence(sendToAddress.cosmosAddress);
const latestAccountNumber = accountNumber.accountNumber || 0;
try{
Meteor.call('chain.getCosmosAccountsNumber', latestAccountNumber)
}
catch(e){
console.log("chain.getCosmosAccountsNumber error " + e)
}
return latestAccountNumber
}
catch (e) {
console.log(e)
}
}

export function getCosmosAccountsNumber() {
Meteor.call('chain.shouldUpdateCosmosAccountsNumber', async (error, result) => {
if (error) {
console.log("chain.shouldUpdateCosmosAccountsNumber error ", error);
}
else {
let accountIndex;
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(seed);
const client = await SigningStargateClient.connectWithSigner(RPC, wallet, options);
for (let c = 1; c < 100; c++) {
let accIndex = this.getToAddress(c);
try {
// eslint-disable-next-line no-await-in-loop
await client.getSequence(accIndex.cosmosAddress)
}
catch (e) {
accountIndex = c
break;
}

}
return fetchCosmosAccountsNumber(accountIndex)
}
})
}

Meteor.methods({
'cosmosAccounts.getToAddress': function (accountIndex) {
this.unblock();
let hdpath = `m/44'/${COINTYPE}'/${accountIndex}'/0/0`
const { cosmosAddress, privateKey, publicKey } = getNewWalletFromSeed(seed, bech32prefix, hdpath)
return { cosmosAddress, privateKey, publicKey }
},
'cosmosAccounts.getFromAddress': function () {
this.unblock();
let hdpath = `m/44'/${COINTYPE}'/0'/0/0`
const { cosmosAddress, privateKey, publicKey } = getNewWalletFromSeed(seed, bech32prefix, hdpath)
return { cosmosAddress, privateKey, publicKey }
},
'cosmosAccounts.fetchCosmosAccountsNumber': async function (accountIndex) {
this.unblock();
let sendFromAddress, sendToAddress;
Meteor.call('cosmosAccounts.getFromAddress', (error, result) => {
if (error) {
console.log("cosmosAccounts.getFromAddress error ", error);
}
else if(result){
sendFromAddress = result;
}
})
Meteor.call('cosmosAccounts.getToAddress', accountIndex, (error, result) => {
if (error) {
console.log("cosmosAccounts.getToAddress error ", error);
}
else if (result) {
sendToAddress = result;
}
})

const wallet = await DirectSecp256k1HdWallet.fromMnemonic(seed);
const client = await SigningStargateClient.connectWithSigner(RPC, wallet, options);
const amount = [{ amount: "1", denom: "uatom" }]
const fee = {
amount: [{ amount: "100", denom: "uatom" }],
gas: "100000",
}
const sendMsg = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: {
fromAddress: sendFromAddress.cosmosAddress,
toAddress: sendToAddress.cosmosAddress,
amount: [...amount],
},
};

try {
let signMessage = await client.signAndBroadcast(sendFromAddress.cosmosAddress, [sendMsg], fee, DEFAULT_MEMO);
assertIsBroadcastTxSuccess(signMessage);
}
catch (e) {
console.log(e)
}
try {
const accountNumber = await client.getSequence(sendToAddress.cosmosAddress);
const latestAccountNumber = accountNumber.accountNumber || 0;
try {
Meteor.call('chain.getCosmosAccountsNumber', latestAccountNumber)
}
catch (e) {
console.log("chain.getCosmosAccountsNumber error " + e)
}
return latestAccountNumber
}
catch (e) {
console.log(e)
}
},

'cosmosAccounts.getTotal': function () {
this.unblock();
Meteor.call('chain.shouldUpdateCosmosAccountsNumber', async (error, result) => {
if (error) {
console.log("chain.shouldUpdateCosmosAccountsNumber error ", error);
}
else {
let accountIndex;
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(seed);
const client = await SigningStargateClient.connectWithSigner(RPC, wallet, options);
for (let c = 1; c < 100; c++) {
let accIndex;
// eslint-disable-next-line no-loop-func
Meteor.call('cosmosAccounts.getToAddress', c, async (error, result) => {
if (error) {
console.log("cosmosAccounts.getToAddress error ", error);
}
else if (result) {
accIndex = result;
try {
// eslint-disable-next-line no-await-in-loop
await client.getSequence(accIndex.cosmosAddress)
}
catch (e) {
accountIndex = c
// break;
}
}
})
}
try {
Meteor.call('cosmosAccounts.fetchCosmosAccountsNumber', latestAccountNumber)
}
catch (e) {
console.log("cosmosAccounts.fetchCosmosAccountsNumber error ", error);

}
}
})
},

})
Loading