Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
17 changes: 11 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const { PollingBlockTracker } = require('@metamask/eth-block-tracker')
const Eth = require('@metamask/ethjs-query')
const EthContract = require('@metamask/ethjs-contract')
const { Contract, BrowserProvider } = require('ethers')
const Token = require('./token')
const abi = require('human-standard-token-abi')
const SafeEventEmitter = require('@metamask/safe-event-emitter').default
Expand All @@ -19,9 +18,7 @@ class TokenTracker extends SafeEventEmitter {
pollingInterval,
})

const eth = new Eth(opts.provider)
const contract = new EthContract(eth)
this.TokenContract = contract(abi)
this.provider = opts.provider

const tokens = opts.tokens || []
this.balanceDecimals = opts.balanceDecimals
Expand Down Expand Up @@ -52,6 +49,14 @@ class TokenTracker extends SafeEventEmitter {
return this.tokens.map(token => token.serialize())
}

getContractAtAddress(tokenAddress) {
return new Contract(
tokenAddress,
abi,
new BrowserProvider(this.provider),
)
}

async updateBalances() {
try {
await Promise.all(this.tokens.map((token) => {
Expand All @@ -68,7 +73,7 @@ class TokenTracker extends SafeEventEmitter {
createTokenFrom (opts, balanceDecimals) {
const owner = this.userAddress
const { address, symbol, balance, decimals } = opts
const contract = this.TokenContract.at(address)
const contract = this.getContractAtAddress(address)
return new Token({
address,
symbol,
Expand Down
15 changes: 14 additions & 1 deletion lib/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ function _isInvalidBnInput (input, base) {
)
}

/**
* Converts a BigInt value to a BN instance.
*
* @param {BigInt} bigIntValue - The BigInt value to convert.
* @returns {BN} The BN instance representing the BigInt value.
*/
function _bigIntToBN(bigIntValue) {
return new BN(bigIntValue.toString());
}

class Token {

constructor ({
Expand Down Expand Up @@ -137,7 +147,10 @@ class Token {
}

if (result) {
const val = result[0]
let val = result
if (typeof result === 'bigint') {
val = _bigIntToBN(result)
}
this[key] = val
return val
}
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@
],
"dependencies": {
"@metamask/eth-block-tracker": "^11.0.3",
"@metamask/ethjs-contract": "^0.4.1",
"@metamask/ethjs-query": "^0.7.1",
"@metamask/safe-event-emitter": "^3.0.0",
"bn.js": "^5.2.1",
"deep-equal": "^2.2.0",
"ethers": "^6.13.5",
"human-standard-token-abi": "^2.0.0"
},
"devDependencies": {
Expand All @@ -55,7 +54,7 @@
"@lavamoat/allow-scripts": "^2.3.1",
"@lavamoat/preinstall-always-fail": "^2.0.0",
"@metamask/auto-changelog": "^3.4.3",
"ganache": "7.3.1",
"ganache": "7.9.2",
"solc": "^0.4.26",
"tape": "^5.6.1"
},
Expand All @@ -71,7 +70,11 @@
"ganache>keccak": true,
"ganache>leveldown": true,
"ganache>secp256k1": true,
"ganache>utf-8-validate": true
"ganache>utf-8-validate": true,
"ganache>@trufflesuite/uws-js-unofficial>bufferutil": false,
"ganache>@trufflesuite/uws-js-unofficial>utf-8-validate": false,
"ethers>ws>bufferutil": false,
"ethers>ws>utf-8-validate": false
}
}
}
33 changes: 14 additions & 19 deletions test/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ const assert = require('assert').strict
const fs = require('fs')
const path = require('path')
const ganache = require('ganache')
const Eth = require('@metamask/ethjs-query')
const EthContract = require('@metamask/ethjs-contract')
const { ContractFactory, BrowserProvider } = require('ethers')
const solc = require('solc')

const source = fs.readFileSync(path.resolve(__dirname, 'contracts/Token.sol')).toString();
Expand All @@ -13,35 +12,31 @@ const SimpleTokenDeployer = compiled.contracts[':SimpleToken']
const defaultQuantity = '100000000000000000000' // 100 x 10 ^ 18
async function setupSimpleTokenEnvironment ({ qty = defaultQuantity } = {}) {
const provider = ganache.provider()
const eth = new Eth(provider)
const ethersProvider = new BrowserProvider(provider)

const addresses = await eth.accounts()
const accounts = await ethersProvider.listAccounts()
const addresses = accounts.map(account => account.address)
assert(addresses.length > 0, 'test network should be initialized with accounts')

const owner = addresses[0]
const contract = new EthContract(eth)
const abi = JSON.parse(SimpleTokenDeployer.interface)
const StandardToken = contract(abi, SimpleTokenDeployer.bytecode, {
from: owner,
gas: '3000000',
gasPrice: '875000000',
})
const signer = await ethersProvider.getSigner(owner)
const factory = new ContractFactory(abi, SimpleTokenDeployer.bytecode, signer)

const txHash = await StandardToken.new(qty)
assert.ok(txHash, 'should have published the token and returned a transaction hash')
const contract = await factory.deploy(qty)
const { hash } = contract.deploymentTransaction()
assert.ok(hash, 'should have published the token and returned a transaction hash')

await new Promise((resolve) => setTimeout(resolve, 300))
const receipt = await eth.getTransactionReceipt(txHash)
await contract.waitForDeployment()
Comment thread
cryptodev-2s marked this conversation as resolved.
Outdated
const receipt = await ethersProvider.getTransactionReceipt(hash)

const tokenAddress = receipt.contractAddress
assert.ok(tokenAddress, 'should have a token address')

const token = StandardToken.at(tokenAddress)
const result = await token.balanceOf(owner)
const balance = result[0]
assert.equal(balance.toString(10), qty, 'owner should have all')
const balance = await contract.balanceOf(owner)
assert.equal(balance.toString(), qty, 'owner should have all')

return { addresses, eth, provider, token, tokenAddress }
return { addresses, provider, contract, tokenAddress }
}

module.exports = { setupSimpleTokenEnvironment }
60 changes: 26 additions & 34 deletions test/integration/human-standard-token.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@ const fs = require('fs')
const path = require('path')
const test = require('tape')
const ganache = require('ganache')
const provider = ganache.provider()

const { ContractFactory, BrowserProvider } = require('ethers')
const solc = require('solc')
const TokenTracker = require('../../lib')
const BN = ('bn.js')
Comment thread
cryptodev-2s marked this conversation as resolved.

const Eth = require('@metamask/ethjs-query')
const EthContract = require('@metamask/ethjs-contract')
const eth = new Eth(provider)
const contract = new EthContract(eth)

const provider = ganache.provider()
const source = fs.readFileSync(path.resolve(__dirname, '..', 'contracts/Token.sol')).toString();
const compiled = solc.compile(source, 1)
const HumanStandardDeployer = compiled.contracts[':HumanStandardToken']
Expand All @@ -23,45 +18,42 @@ const EXPECTED_SYMBOL = 'EXP'
let addresses = []
let token, tokenAddress, tracked

const ethersProvider = new BrowserProvider(provider)

test('testrpc has addresses', function (t) {
eth.accounts()
ethersProvider.listAccounts()
.then((accounts) => {
addresses = accounts
addresses = accounts.map(account => account.address)
t.ok(accounts, 'loaded accounts')
t.end()
})
})

test('HumanStandardToken publishing token & checking balance', function (t) {
const abi = JSON.parse(HumanStandardDeployer.interface)
const HumanStandardToken = contract(abi, HumanStandardDeployer.bytecode, {
from: addresses[0],
gas: '3000000',
gasPrice: '875000000',
})
const humanStandardToken = HumanStandardToken.new('1000',
'DanBucks',
'2', // decimals
SET_SYMBOL)
.then((txHash) => {
t.ok(txHash, 'publishes a txHash')

return new Promise((res, rej) => {
setTimeout(() => res(txHash), 200)
ethersProvider.getSigner(addresses[0])
.then((signer) => {
const factory = new ContractFactory(abi, HumanStandardDeployer.bytecode, signer)
return factory.deploy('1000', 'DanBucks', '2', SET_SYMBOL, {
gasLimit: '3000000',
gasPrice: '875000000',
})
})
.then((txHash) => {
return eth.getTransactionReceipt(txHash)
.then((contract) => {
t.ok(contract.deploymentTransaction().hash, 'publishes a txHash')
return contract.waitForDeployment()
})
.then((receipt) => {
const addr = receipt.contractAddress
tokenAddress = addr
token = HumanStandardToken.at(addr)
.then((deployedContract) => {
token = deployedContract
return deployedContract.getAddress()
})
.then((address) => {
t.ok(address, 'should have an address')
tokenAddress = address
return token.balanceOf(addresses[0])
})
.then((res) => {
const balance = res[0]
t.equal(balance.toString(10), '1000', 'owner should have all')
.then((balance) => {
t.equal(balance.toString(), '1000', 'owner should have all')
t.end()
})
.catch((reason) => {
Expand Down Expand Up @@ -90,8 +82,8 @@ test('HumanStandardToken balances are tracked', function (t) {
t.equal(tracked.balance.toString(10), '1000', 'initial balance loaded')
return token.transfer(addresses[1], '110')
})
.then((txHash) => {
return eth.getTransactionReceipt(txHash)
.then((tx) => {
return ethersProvider.getTransactionReceipt(tx.hash)
})
.then((receipt) => {
var a = new Promise((res, rej) => { setTimeout(res, 200) })
Expand Down
30 changes: 16 additions & 14 deletions test/integration/simple-token.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ const less = '10000000000000000000' // 100 x 10 ^ 17

test('StandardToken balances are tracked', function (t) {
let addresses
let eth
let token
let contract
let tokenAddress
let tokenTracker
let provider
setupSimpleTokenEnvironment()
.then((environment) => {
addresses = environment.addresses
eth = environment.eth
token = environment.token
contract = environment.contract
tokenAddress = environment.tokenAddress
const { provider } = environment
provider = environment.provider
tokenTracker = new TokenTracker({
userAddress: addresses[0],
provider,
Expand All @@ -41,10 +40,13 @@ test('StandardToken balances are tracked', function (t) {
.then(() => {
tracked = tokenTracker.serialize()[0]
t.equal(tracked.balance.toString(10), qty, 'initial balance loaded')
return token.transfer(addresses[1], less)
return contract.transfer(addresses[1], less)
})
.then((txHash) => {
return eth.getTransactionReceipt(txHash)
.then((tx) => {
return provider.request({
method: 'eth_getTransactionReceipt',
params: [tx.hash],
})
})
.then((receipt) => {
var a = new Promise((res, rej) => { setTimeout(res, 200) })
Expand Down Expand Up @@ -77,11 +79,11 @@ test('StandardToken balances are tracked', function (t) {

test('StandardToken balance changes are emitted and symbol fetched', function (t) {
let addresses
let token
let contract
setupSimpleTokenEnvironment()
.then((environment) => {
addresses = environment.addresses
token = environment.token
contract = environment.contract
const { provider, tokenAddress } = environment
var tokenTracker = new TokenTracker({
userAddress: addresses[0],
Expand Down Expand Up @@ -112,7 +114,7 @@ test('StandardToken balance changes are emitted and symbol fetched', function (t
return new Promise((res, rej) => { setTimeout(res, 200) })
})
.then(() => {
return token.transfer(addresses[1], '100')
return contract.transfer(addresses[1], '100')
})
.catch((reason) => {
t.notOk(reason, 'should not throw an error')
Expand All @@ -123,12 +125,12 @@ test('StandardToken balance changes are emitted and symbol fetched', function (t

test('StandardToken non balance changes are not emitted', function (t) {
let addresses
let token
let contract
let tokenTracker
setupSimpleTokenEnvironment()
.then((environment) => {
addresses = environment.addresses
token = environment.token
contract = environment.contract
const { provider, tokenAddress } = environment
tokenTracker = new TokenTracker({
userAddress: addresses[0],
Expand Down Expand Up @@ -156,7 +158,7 @@ test('StandardToken non balance changes are not emitted', function (t) {
return new Promise((res, rej) => { setTimeout(res, 200) })
})
.then(() => {
return token.transfer(addresses[1], '0')
return contract.transfer(addresses[1], '0')
})
.then(() => {
var a = new Promise((res, rej) => { setTimeout(res, 200) })
Expand Down
Loading