## Content - [Contract Write Function](#contract-write-function) - [Contract Read Function](#contract-read-function) ## Contract Write function In this section, we briefly introduce some functions that Tangerine governance provides to write in. ### Register 1. In Tangerine wallet, switch to the `owner's account`. 2. Navigate to the `Write` tab of the governance contract and select `register` from the dropdown menu. 3. Fill in the information like below; currently, you need 1M TAN to run a BP node. - Node Public Key (you must hold the corresponding secret key) - Name of the node - Contact email - Node Location - Website URL 4. Click `Send` and `confirm` in Tangerine wallet. ### Pay Fine 1. In Tangerine wallet, switch to the account to pay the fine (it doesn't has to be the owner of that node) 2. Navigate to the `Write tab of the governance contract and select `payFine` from the dropdown menu. 3. Fill in the amount of fine to pay, and the address of that node. 4. Click `Send` and `confirm` in Tangerine wallet. > NOTE: Don't worry to over pay the fine, the transaction would succeed when the amount you pay matches the fine of that node. ### Stake/Unstake After registering, each node owner can continue depositing more stake into Tangerine governance contract. This is super easy to achieve in Tangerine governance contract. 1. Switch to the `owner account` in Tangerine wallet. 2. Navigate to the `Write` tab and select `stake` from the dropdown menu. 3. Fill the amount of stake in the contract. 4. Click `Send` and `confirm` in Tangerine wallet. On the other hand, each node owner can also unstake from Tangerine governance contract. This is almost identical to operating stake function. 1. Switch to the `owner account` in Tangerine wallet. 2. Navigate to the `Write` tab and select `unstake` from the dropdown menu. 3. Fill the amount of unstake in the contract. 4. Click `Send` and `confirm` in Tangerine wallet. To ensure the stability of Tangerine blockchain, the duration to withdraw the unstake coin is set 24 epochs, which corresponds around 1 day in real-world time. In the duration, the node can still propose block and earn the reward, but the node sill can be fined if violating any rule. Note that, each node can only unstake once until the unstake is withdrawn. ### Withdraw After unstaking and wait for 24 epochs, the node can withdraw the stake. 1. Switch to the `owner account` in Tangerine wallet. 2. Navigate to the `Write` tab and select `withdraw` from the dropdown menu. 3. Click `Send` and `confirm` in Tangerine wallet. ### Transfer Node Owner A node owner can also transfer the owner right to others. 1. Switch to the `owner account` in Tangerine wallet. 2. Navigate to the `Write` tab and select `TransferNodeOwnership` from the dropdown menu. 3. Fill the `address` of the new owner. 4. Click `Send` and `confirm` in Tangerine wallet. > WARNING: This is an IRREDUCIBLE operation. No one can recover if you transfer to a wrong address. Please double-check the address is correct. ## Contract Read function The latest system parameters can be found in the governance contract. We introduce some fruquently used functions. ### nodes `nodes` returns the status of a node, where the input is the order of the node. The order of a node can be query by the function `nodesOffsetByAddress`. ### nodeLength `nodeLength` returns the current size of the node set. ### nodesOffsetByAddress `nodesOffsetByAddress` returns the order of a node, where the input is the address of the node. ### minStake `minStake` returns the minimum stake required to join the node set.pendabot/npm_and_yarn/luxon-2.5.2'>dependabot/npm_and_yarn/luxon-2.5.2 Tangerine fork of MetaMask browser extension (https://github.com/tangerine-network/tangerine-wallet-browser)
aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components/token-list.js
blob: d2d83de26682d368897bd5cf86c25865f4adf1d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const TokenTracker = require('eth-token-tracker')
const TokenCell = require('./token-cell.js')
const contracts = require('eth-contract-metadata')
const normalizeAddress = require('eth-sig-util').normalize

const defaultTokens = []
for (const address in contracts) {
  const contract = contracts[address]
  if (contract.erc20) {
    contract.address = address
    defaultTokens.push(contract)
  }
}

module.exports = TokenList

inherits(TokenList, Component)
function TokenList () {
  this.state = {
    tokens: null,
    isLoading: true,
    network: null,
  }
  Component.call(this)
}

TokenList.prototype.render = function () {
  const state = this.state
  const { tokens, isLoading, error } = state
  const { userAddress, network } = this.props

  if (isLoading) {
    return this.message('Loading')
  }

  if (error) {
    log.error(error)
    return this.message('There was a problem loading your token balances.')
  }

  const tokenViews = tokens.map((tokenData) => {
    tokenData.network = network
    tokenData.userAddress = userAddress
    return h(TokenCell, tokenData)
  })

  return h('div', [
    h('ol', {
      style: {
        height: '260px',
        overflowY: 'auto',
        display: 'flex',
        flexDirection: 'column',
      },
    }, [
      h('style', `

        li.token-cell {
          display: flex;
          flex-direction: row;
          align-items: center;
          padding: 10px;
        }

        li.token-cell > h3 {
          margin-left: 12px;
        }

        li.token-cell:hover {
          background: white;
          cursor: pointer;
        }

      `),
      ...tokenViews,
      tokenViews.length ? null : this.message('No Tokens Found.'),
    ]),
    this.addTokenButtonElement(),
  ])
}

TokenList.prototype.addTokenButtonElement = function () {
  return h('div', [
    h('div.footer.hover-white.pointer', {
      key: 'reveal-account-bar',
      onClick: () => {
        this.props.addToken()
      },
      style: {
        display: 'flex',
        height: '40px',
        padding: '10px',
        justifyContent: 'center',
        alignItems: 'center',
      },
    }, [
      h('i.fa.fa-plus.fa-lg'),
    ]),
  ])
}

TokenList.prototype.message = function (body) {
  return h('div', {
    style: {
      display: 'flex',
      height: '250px',
      alignItems: 'center',
      justifyContent: 'center',
    },
  }, body)
}

TokenList.prototype.componentDidMount = function () {
  this.createFreshTokenTracker()
}

TokenList.prototype.createFreshTokenTracker = function () {
  if (this.tracker) {
    // Clean up old trackers when refreshing:
    this.tracker.stop()
    this.tracker.removeListener('update', this.balanceUpdater)
    this.tracker.removeListener('error', this.showError)
  }

  if (!global.ethereumProvider) return
  const { userAddress } = this.props
  this.tracker = new TokenTracker({
    userAddress,
    provider: global.ethereumProvider,
    tokens: uniqueMergeTokens(defaultTokens, this.props.tokens),
    pollingInterval: 8000,
  })


  // Set up listener instances for cleaning up
  this.balanceUpdater = this.updateBalances.bind(this)
  this.showError = (error) => {
    this.setState({ error, isLoading: false })
  }
  this.tracker.on('update', this.balanceUpdater)
  this.tracker.on('error', this.showError)

  this.tracker.updateBalances()
  .then(() => {
    this.updateBalances(this.tracker.serialize())
  })
  .catch((reason) => {
    log.error(`Problem updating balances`, reason)
    this.setState({ isLoading: false })
  })
}

TokenList.prototype.componentWillUpdate = function (nextProps) {
  if (nextProps.network === 'loading') return
  const oldNet = this.props.network
  const newNet = nextProps.network

  if (oldNet && newNet && newNet !== oldNet) {
    this.setState({ isLoading: true })
    this.createFreshTokenTracker()
  }
}

TokenList.prototype.updateBalances = function (tokenData) {
  const desired = this.props.tokens.map(token => token.address)
  const heldTokens = tokenData.filter(token => {
    const held = token.balance !== '0' && token.string !== '0.000'
    const preferred = desired.includes(normalizeAddress(token.address))
    return held || preferred
  })
  this.setState({ tokens: heldTokens, isLoading: false })
}

TokenList.prototype.componentWillUnmount = function () {
  if (!this.tracker) return
  this.tracker.stop()
}

function uniqueMergeTokens (tokensA, tokensB) {
  const uniqueAddresses = []
  const result = []
  tokensA.concat(tokensB).forEach((token) => {
    const normal = normalizeAddress(token.address)
    if (!uniqueAddresses.includes(normal)) {
      uniqueAddresses.push(normal)
      result.push(token)
    }
  })
  return result
}