add dispenser (#106)

* add dispenser


Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>
Co-authored-by: Jamie Hewitt <jamie.hewitt15@gmail.com>
This commit is contained in:
Alex Coseru 2021-05-13 09:19:21 +03:00 committed by GitHub
parent 07b02c2b5a
commit f47ec9bb09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 18298 additions and 206 deletions

3
.gitignore vendored
View File

@ -65,3 +65,6 @@ typings/
# next.js build output
.next
# auto generated barge yaml
subgraph.barge.yaml

View File

@ -133,6 +133,7 @@ export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json"
4. Generate the subgraph
```bash
npm run codegen
npm run bargesetup
```

17468
abis/Dispenser.json Normal file

File diff suppressed because one or more lines are too long

82
package-lock.json generated
View File

@ -399,17 +399,17 @@
}
},
"@oceanprotocol/contracts": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.5.16.tgz",
"integrity": "sha512-p7aFIUT8RVoMzdPP7ML8G08BnQ09syywKjOT16hqJm0GmofunEuVffUXbryG4EkQ+qRbf/zeoxSmesi79kQXlA=="
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.6.2.tgz",
"integrity": "sha512-J6amHsmVbdc2rAwbUYOaY7inLV13GxPIiqbsLF78nmdIvhhGDhT2LYMyfQtxkMwQzYDP6EzD4albCgOXlWM15g=="
},
"@oceanprotocol/lib": {
"version": "0.14.8",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.14.8.tgz",
"integrity": "sha512-eqab5iEgowyIM/LcDDs6xhZo/KToOmVw0betjXLG0+g70zS8R6XL2RHzCpFyutSdf/cH0w/ltPUfR8ZBElIyhQ==",
"version": "0.14.9",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.14.9.tgz",
"integrity": "sha512-PUNbsryrm4614CbvalP2CZS9LZjvWfqopTdb91Rz4vLbnqinioELSFXNq+hiSkyuFqAy0szG0wueBcW8mwFbSg==",
"requires": {
"@ethereum-navigator/navigator": "^0.5.2",
"@oceanprotocol/contracts": "0.5.16",
"@oceanprotocol/contracts": "^0.6.2",
"@types/crypto-js": "^4.0.1",
"cross-fetch": "^3.1.2",
"crypto-js": "^4.0.0",
@ -5163,9 +5163,9 @@
"integrity": "sha512-WRRyllsGXJM7ZN7gPTCCQ/6wNPTRDwiWdPK66l5sJzcU/oOzcIcRRf0Rux8bkpox/1yjt0F6VJRsQOIG2qz5sg=="
},
"is-bigint": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz",
"integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg=="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz",
"integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA=="
},
"is-binary-path": {
"version": "2.1.0",
@ -5182,11 +5182,32 @@
"integrity": "sha1-o9fZb+HD/wZex84nwsIea6ksGDI="
},
"is-boolean-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz",
"integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz",
"integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==",
"requires": {
"call-bind": "^1.0.0"
"call-bind": "^1.0.2"
},
"dependencies": {
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
}
}
},
"is-buffer": {
@ -5252,9 +5273,9 @@
"integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
},
"is-generator-function": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz",
"integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ=="
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.9.tgz",
"integrity": "sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A=="
},
"is-glob": {
"version": "4.0.1",
@ -5413,9 +5434,9 @@
"dev": true
},
"is-number-object": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz",
"integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw=="
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz",
"integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw=="
},
"is-obj": {
"version": "2.0.0",
@ -5566,12 +5587,19 @@
"integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ=="
},
"is-regex": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
"integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
"integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
"requires": {
"call-bind": "^1.0.2",
"has-symbols": "^1.0.1"
"has-symbols": "^1.0.2"
},
"dependencies": {
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
}
}
},
"string.prototype.trimend": {
@ -9818,9 +9846,9 @@
}
},
"utf-8-validate": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.4.tgz",
"integrity": "sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz",
"integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==",
"requires": {
"node-gyp-build": "^4.2.0"
}

View File

@ -54,7 +54,7 @@
"typescript": "^4.2.4"
},
"dependencies": {
"@oceanprotocol/lib": "^0.14.8",
"@oceanprotocol/lib": "^0.14.9",
"cross-fetch": "^3.1.4"
},
"repository": {

View File

@ -2,14 +2,11 @@ type PoolFactory @entity {
id: ID!
totalValueLocked: BigDecimal # total value from all pools expressed in OCEAN
totalOceanLiquidity: BigDecimal! # Total of OCEAN liquidity from all pools
totalSwapVolume: BigDecimal! # All the swap volume in Ocean
totalSwapFee: BigDecimal! # All the swap fee in Ocean
poolCount: Int! # Number of pools
finalizedPoolCount: Int! # Number of finalized pools
pools: [Pool!] @derivedFrom(field: "factoryID")
}
@ -24,12 +21,10 @@ type Pool @entity {
cap: BigInt # Maximum supply if any
active: Boolean! # isActive
swapFee: BigDecimal! # Swap Fees
totalWeight: BigDecimal!
totalShares: BigDecimal! # Total pool token shares
totalSwapVolume: BigDecimal! # Total swap volume in OCEAN
totalSwapFee: BigDecimal! # Total swap fee in OCEAN
valueLocked: BigDecimal! # value locked in pool expressed in OCEAN (captures both Ocean and Datatoken)
datatokenReserve: BigDecimal! # Total pool reserve of Datatoken
oceanReserve: BigDecimal! # Total pool reserve of OCEAN
@ -42,15 +37,14 @@ type Pool @entity {
exitCount: BigInt! # liquidity has been removed
swapCount: BigInt!
transactionCount: BigInt! # Number of transactions in this pool involving liquidity changes
datatokenAddress: String!
createTime: Int! # Block time pool was created
tx: Bytes # Pool creation transaction id
tokens: [PoolToken!] @derivedFrom(field: "poolId")
shares: [PoolShare!] @derivedFrom(field: "poolId")
transactions: [PoolTransaction!] @derivedFrom(field: "poolAddress")
transactionsTokenValues: [PoolTransactionTokenValues!] @derivedFrom(field: "poolAddress")
transactionsTokenValues: [PoolTransactionTokenValues!]
@derivedFrom(field: "poolAddress")
}
type PoolToken @entity {
@ -112,7 +106,6 @@ type DatatokenFactory @entity {
id: ID!
tokenCount: Int! # Number of datatokens
datatokens: [Datatoken!] @derivedFrom(field: "factoryID")
}
@ -135,7 +128,6 @@ type Datatoken @entity {
createTime: Int! # Block time datatoken was created
tx: Bytes # Datatoken creation transaction id
balances: [TokenBalance!] @derivedFrom(field: "datatokenId")
orders: [TokenOrder!] @derivedFrom(field: "datatokenId")
updates: [MetadataUpdate!] @derivedFrom(field: "datatokenId") # list of MetadataUpdate objects
@ -155,7 +147,6 @@ type MetadataUpdate @entity {
type TokenOrder @entity {
id: ID! # datatokenId + userAddress + tx
datatokenId: Datatoken!
consumer: User!
@ -179,7 +170,6 @@ type TokenBalance @entity {
type TokenTransaction @entity {
id: ID! # Log ID
event: String
datatokenAddress: Datatoken
userAddress: User
@ -198,7 +188,8 @@ type User @entity {
tokenBalancesOwned: [TokenBalance!] @derivedFrom(field: "userAddress")
tokensOwned: [Datatoken!] @derivedFrom(field: "minter")
poolTransactions: [PoolTransaction!] @derivedFrom(field: "userAddress")
poolTransactionsTokenValues: [PoolTransactionTokenValues!] @derivedFrom(field: "userAddress")
poolTransactionsTokenValues: [PoolTransactionTokenValues!]
@derivedFrom(field: "userAddress")
tokenTransactions: [TokenTransaction!] @derivedFrom(field: "userAddress")
orders: [TokenOrder!] @derivedFrom(field: "payer")
freSwaps: [FixedRateExchangeSwap!] @derivedFrom(field: "by")
@ -237,3 +228,28 @@ type FixedRateExchangeSwap @entity {
timestamp: Int!
tx: Bytes!
}
type Dispenser @entity {
id: ID! # dispenser datatoken
active: Boolean!
owner: User!
minterApproved: Boolean!
isTrueMinter: Boolean!
maxTokens: BigDecimal!
maxBalance: BigDecimal!
balance: BigDecimal!
datatoken: Datatoken!
dispenses: [DispenserTransaction!] @derivedFrom(field: "dispenserId")
}
type DispenserTransaction @entity {
id: ID!
dispenserId: Dispenser!
datatoken: Datatoken!
user: User!
amount: BigDecimal!
block: Int!
timestamp: Int!
tx: Bytes!
type: String!
}

View File

@ -12,7 +12,9 @@ async function replaceContractAddresses() {
// eslint-disable-next-line no-unused-vars
FixedRateExchange,
// eslint-disable-next-line no-unused-vars
Metadata
Metadata,
// eslint-disable-next-line no-unused-vars
Dispenser
} = data.development
let subgraph = fs.readFileSync('subgraph.yaml', 'utf8')
if (!data) {
@ -38,6 +40,11 @@ async function replaceContractAddresses() {
/0x608d05214E42722B94a54cF6114d4840FCfF84e1/g,
FixedRateExchange
)
// dispenser
subgraph = subgraph.replace(
/0xDEfD0018969cd2d4E648209F876ADe184815f038/g,
Dispenser
)
// network
subgraph = subgraph.replace(/network: mainnet/g, 'network: barge')

176
src/mappings/dispenser.ts Normal file
View File

@ -0,0 +1,176 @@
import { Address, BigInt, ethereum, log } from '@graphprotocol/graph-ts'
import {
Activated,
Deactivated,
AcceptedMinter,
RemovedMinter,
TokensDispensed,
OwnerWithdrawed,
Dispenser as DispenserEntity
} from '../@types/Dispenser/Dispenser'
import {
Dispenser,
DispenserTransaction,
User,
Datatoken
} from '../@types/schema'
import { tokenToDecimal, _debuglog } from '../helpers'
function _processDispenserUpdate(
event: ethereum.Event,
datatoken: string,
contractAddress: Address
): void {
_debuglog('Start processDispenserUpdate', null, [
datatoken,
contractAddress.toHexString()
])
const dt = Datatoken.load(datatoken)
if (!dt) {
return
}
let dispenser = Dispenser.load(datatoken)
if (!dispenser) {
_debuglog('Creating new dispenser', null, null)
dispenser = new Dispenser(datatoken)
}
const dispenserEntity = DispenserEntity.bind(contractAddress)
_debuglog('Bound dispenser entity', null, null)
const dispenserStatus = dispenserEntity.try_status(
Address.fromString(datatoken)
)
_debuglog('Got status', null, null)
if (dispenserStatus.reverted) return
dispenser.active = dispenserStatus.value.value0
let owner = User.load(dispenserStatus.value.value1.toHexString())
if (!owner) {
owner = new User(dispenserStatus.value.value1.toHexString())
owner.save()
}
dispenser.owner = owner.id
dispenser.minterApproved = dispenserStatus.value.value2
dispenser.isTrueMinter = dispenserStatus.value.value3
dispenser.maxTokens = tokenToDecimal(
dispenserStatus.value.value4.toBigDecimal(),
18
)
dispenser.maxBalance = tokenToDecimal(
dispenserStatus.value.value5.toBigDecimal(),
18
)
dispenser.balance = tokenToDecimal(
dispenserStatus.value.value6.toBigDecimal(),
18
)
dispenser.datatoken = dt.id
dispenser.save()
}
export function handleDispenserActivated(event: Activated): void {
_debuglog('Start handleDispenserActivated', event, [
event.params.datatokenAddress.toHexString()
])
_processDispenserUpdate(
event,
event.params.datatokenAddress.toHexString(),
event.address
)
}
export function handleDispenserDeactivated(event: Deactivated): void {
_processDispenserUpdate(
event,
event.params.datatokenAddress.toHexString(),
event.address
)
}
export function handleDispenserAcceptedMinter(event: AcceptedMinter): void {
_processDispenserUpdate(
event,
event.params.datatokenAddress.toHexString(),
event.address
)
}
export function handleDispenserRemovedMinter(event: RemovedMinter): void {
_processDispenserUpdate(
event,
event.params.datatokenAddress.toHexString(),
event.address
)
}
export function handleDispenserTokensDispensed(event: TokensDispensed): void {
_processDispenserUpdate(
event,
event.params.datatokenAddress.toHexString(),
event.address
)
const dt = Datatoken.load(event.params.datatokenAddress.toHexString())
if (!dt) {
log.warning('Tokens dispensed, but no datatoken ? ', [
event.params.datatokenAddress.toHexString()
])
return
}
const tx = event.transaction.hash
const id = tx
.toHexString()
.concat('-')
.concat(event.params.datatokenAddress.toHexString())
log.info('Created dispenser in handleDispenserTokensDispensed with id {}', [
id
])
const dispensers = new DispenserTransaction(id)
dispensers.dispenserId = event.params.datatokenAddress.toHexString()
dispensers.datatoken = event.params.datatokenAddress.toHexString()
dispensers.user = event.params.userAddress.toHexString()
dispensers.amount = tokenToDecimal(
event.params.amount.toBigDecimal(),
BigInt.fromI32(18).toI32()
)
dispensers.block = event.block.number.toI32()
dispensers.timestamp = event.block.timestamp.toI32()
dispensers.tx = tx
dispensers.type = 'dispense'
dispensers.save()
}
export function handleDispenserOwnerWithdrawed(event: OwnerWithdrawed): void {
_processDispenserUpdate(
event,
event.params.datatoken.toHexString(),
event.address
)
const dt = Datatoken.load(event.params.datatoken.toHexString())
if (!dt) {
log.warning('Tokens dispensed, but no datatoken ? ', [
event.params.datatoken.toHexString()
])
return
}
const tx = event.transaction.hash
const id = tx
.toHexString()
.concat('-')
.concat(event.params.datatoken.toHexString())
log.info('Created dispenser in handleDispenserOwnerWithdrawed with id {} ', [
id
])
const dispensers = new DispenserTransaction(id)
dispensers.dispenserId = event.params.datatoken.toHexString()
dispensers.datatoken = event.params.datatoken.toHexString()
dispensers.user = event.params.owner.toHexString()
dispensers.amount = tokenToDecimal(
event.params.amount.toBigDecimal(),
BigInt.fromI32(18).toI32()
)
dispensers.block = event.block.number.toI32()
dispensers.timestamp = event.block.timestamp.toI32()
dispensers.tx = tx
dispensers.type = 'withdraw'
dispensers.save()
}

View File

@ -94,6 +94,36 @@ dataSources:
handler: handleExchangeRateChanged
- event: Swapped(indexed bytes32,indexed address,uint256,uint256)
handler: handleSwapped
- kind: ethereum/contract
name: Dispenser
network: moonbeamalpha
source:
address: '0x042D709b72B437d7d387F2679bD4ac060e561c9f'
abi: Dispenser
startBlock: 260710
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/dispenser.ts
entities:
- Dispenser
abis:
- name: Dispenser
file: ./abis/Dispenser.json
eventHandlers:
- event: Activated(indexed address)
handler: handleDispenserActivated
- event: Deactivated(indexed address)
handler: handleDispenserDeactivated
- event: AcceptedMinter(indexed address)
handler: handleDispenserAcceptedMinter
- event: RemovedMinter(indexed address)
handler: handleDispenserRemovedMinter
- event: TokensDispensed(indexed address,indexed address,uint256)
handler: handleDispenserTokensDispensed
- event: OwnerWithdrawed(indexed address,indexed address,uint256)
handler: handleDispenserOwnerWithdrawed
templates:
- kind: ethereum/contract
name: Pool

View File

@ -94,6 +94,36 @@ dataSources:
handler: handleExchangeRateChanged
- event: Swapped(indexed bytes32,indexed address,uint256,uint256)
handler: handleSwapped
- kind: ethereum/contract
name: Dispenser
network: polygon
source:
address: '0x30E4CC2C7A9c6aA2b2Ce93586E3Df24a3A00bcDD'
abi: Dispenser
startBlock: 14275634
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/dispenser.ts
entities:
- Dispenser
abis:
- name: Dispenser
file: ./abis/Dispenser.json
eventHandlers:
- event: Activated(indexed address)
handler: handleDispenserActivated
- event: Deactivated(indexed address)
handler: handleDispenserDeactivated
- event: AcceptedMinter(indexed address)
handler: handleDispenserAcceptedMinter
- event: RemovedMinter(indexed address)
handler: handleDispenserRemovedMinter
- event: TokensDispensed(indexed address,indexed address,uint256)
handler: handleDispenserTokensDispensed
- event: OwnerWithdrawed(indexed address,indexed address,uint256)
handler: handleDispenserOwnerWithdrawed
templates:
- kind: ethereum/contract
name: Pool

View File

@ -94,6 +94,36 @@ dataSources:
handler: handleExchangeRateChanged
- event: Swapped(indexed bytes32,indexed address,uint256,uint256)
handler: handleSwapped
- kind: ethereum/contract
name: Dispenser
network: rinkeby
source:
address: '0x623744Cd25Ed553d3b4722667697F926cf99658B'
abi: Dispenser
startBlock: 8554110
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/dispenser.ts
entities:
- Dispenser
abis:
- name: Dispenser
file: ./abis/Dispenser.json
eventHandlers:
- event: Activated(indexed address)
handler: handleDispenserActivated
- event: Deactivated(indexed address)
handler: handleDispenserDeactivated
- event: AcceptedMinter(indexed address)
handler: handleDispenserAcceptedMinter
- event: RemovedMinter(indexed address)
handler: handleDispenserRemovedMinter
- event: TokensDispensed(indexed address,indexed address,uint256)
handler: handleDispenserTokensDispensed
- event: OwnerWithdrawed(indexed address,indexed address,uint256)
handler: handleDispenserOwnerWithdrawed
templates:
- kind: ethereum/contract
name: Pool

View File

@ -94,6 +94,36 @@ dataSources:
handler: handleExchangeRateChanged
- event: Swapped(indexed bytes32,indexed address,uint256,uint256)
handler: handleSwapped
- kind: ethereum/contract
name: Dispenser
network: ropsten
source:
address: '0xc37F8341Ac6e4a94538302bCd4d49Cf0852D30C0'
abi: Dispenser
startBlock: 10201082
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/dispenser.ts
entities:
- Dispenser
abis:
- name: Dispenser
file: ./abis/Dispenser.json
eventHandlers:
- event: Activated(indexed address)
handler: handleDispenserActivated
- event: Deactivated(indexed address)
handler: handleDispenserDeactivated
- event: AcceptedMinter(indexed address)
handler: handleDispenserAcceptedMinter
- event: RemovedMinter(indexed address)
handler: handleDispenserRemovedMinter
- event: TokensDispensed(indexed address,indexed address,uint256)
handler: handleDispenserTokensDispensed
- event: OwnerWithdrawed(indexed address,indexed address,uint256)
handler: handleDispenserOwnerWithdrawed
templates:
- kind: ethereum/contract
name: Pool

View File

@ -94,6 +94,36 @@ dataSources:
handler: handleExchangeRateChanged
- event: Swapped(indexed bytes32,indexed address,uint256,uint256)
handler: handleSwapped
- kind: ethereum/contract
name: Dispenser
network: mainnet
source:
address: '0xDEfD0018969cd2d4E648209F876ADe184815f038'
abi: Dispenser
startBlock: 12398958
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
file: ./src/mappings/dispenser.ts
entities:
- Dispenser
abis:
- name: Dispenser
file: ./abis/Dispenser.json
eventHandlers:
- event: Activated(indexed address)
handler: handleDispenserActivated
- event: Deactivated(indexed address)
handler: handleDispenserDeactivated
- event: AcceptedMinter(indexed address)
handler: handleDispenserAcceptedMinter
- event: RemovedMinter(indexed address)
handler: handleDispenserRemovedMinter
- event: TokensDispensed(indexed address,indexed address,uint256)
handler: handleDispenserTokensDispensed
- event: OwnerWithdrawed(indexed address,indexed address,uint256)
handler: handleDispenserOwnerWithdrawed
templates:
- kind: ethereum/contract
name: Pool

View File

@ -0,0 +1,235 @@
/* eslint-disable prefer-destructuring */
import { assert, use } from 'chai'
import spies from 'chai-spies'
import Web3 from 'web3'
import { Ocean, ConfigHelper, Account } from '@oceanprotocol/lib'
const fetch = require('cross-fetch')
const web3 = new Web3('http://127.0.0.1:8545')
const subgraphUrl =
'http://localhost:9000/subgraphs/name/oceanprotocol/ocean-subgraph'
function sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function getDispenserStatusFromGraph(datatoken: string) {
const id = datatoken.toLowerCase()
const query = {
query: `query {
dispenser(id:"${id}"){active,owner{id},minterApproved,isTrueMinter,maxTokens,maxBalance,balance,datatoken{id}}}`
}
const response = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(query)
})
const result = await response.json()
return result
}
use(spies)
describe('Dispenser test flow', () => {
let alice: Account
let bob: Account
let ocean: Ocean
let tokenAddress
let tokenAddress2
let tokenAddress3
const tokenAmount = '1000'
it('Initialize Ocean Library', async () => {
const config = new ConfigHelper().getConfig('development')
config.web3Provider = web3
ocean = await Ocean.getInstance(config)
alice = (await ocean.accounts.list())[0]
bob = (await ocean.accounts.list())[1]
})
it('should create some datatokens', async () => {
tokenAddress = await ocean.datatokens.create(
'',
alice.getId(),
'1000000000000000',
'AliceDT',
'DTA'
)
assert(tokenAddress !== null)
tokenAddress2 = await ocean.datatokens.create(
'',
alice.getId(),
'1000000000000000',
'AliceDT2',
'DTA2'
)
assert(tokenAddress2 !== null)
tokenAddress3 = await ocean.datatokens.create(
'',
alice.getId(),
'1000000000000000',
'AliceDT3',
'DTA3'
)
assert(tokenAddress3 !== null)
})
it('Alice mints 1000 tokens', async () => {
const txid = await ocean.datatokens.mint(
tokenAddress,
alice.getId(),
tokenAmount
)
assert(txid !== null)
})
it('Alice creates a dispenser', async () => {
const tx = await ocean.OceanDispenser.activate(
tokenAddress,
'1',
'1',
alice.getId()
)
assert(tx, 'Cannot activate dispenser')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress)
assert(status.data.dispenser.datatoken.id === tokenAddress.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.isTrueMinter === false)
assert(status.data.dispenser.minterApproved === false)
assert(status.data.dispenser.active === true)
assert(status.data.dispenser.balance === '0')
})
it('Alice should make the dispenser a minter', async () => {
const tx = await ocean.OceanDispenser.makeMinter(
tokenAddress,
alice.getId()
)
assert(tx, 'Cannot make dispenser a minter')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress)
assert(status.data.dispenser.datatoken.id === tokenAddress.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.isTrueMinter === true)
assert(status.data.dispenser.minterApproved === true)
})
it('Bob requests datatokens', async () => {
const tx = await ocean.OceanDispenser.dispense(
tokenAddress,
bob.getId(),
'1'
)
assert(tx, 'Bob failed to get 1DT')
await sleep(3000) // let graph ingest our transaction
const id = tx.transactionHash.toLowerCase()
const query = {
query: `query DispenserHistory {
dispenserTransactions(orderBy: timestamp, orderDirection: desc,
where: {tx: "${id}"}) {
datatoken{id},
user{id},
amount,
block,
timestamp,
tx,
type
}
}`
}
const response = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(query)
})
const result = await response.json()
assert(result.data.dispenserTransactions[0].type === 'dispense')
})
it('Alice calls removeMinter role and checks if she is the new minter', async () => {
const tx = await ocean.OceanDispenser.cancelMinter(
tokenAddress,
alice.getId()
)
assert(tx, 'Cannot cancel minter role')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress)
assert(status.data.dispenser.datatoken.id === tokenAddress.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.isTrueMinter === false)
assert(status.data.dispenser.minterApproved === false)
assert(status.data.dispenser.active === true)
})
it('Alice deactivates the dispenser', async () => {
const tx = await ocean.OceanDispenser.deactivate(
tokenAddress,
alice.getId()
)
assert(tx, 'Cannot make dispenser a minter')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress)
assert(status.data.dispenser.datatoken.id === tokenAddress.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.active === false)
})
it('Alice creates a dispenser without minter role', async () => {
const tx = await ocean.OceanDispenser.activate(
tokenAddress2,
'1',
'1',
alice.getId()
)
assert(tx, 'Cannot activate dispenser')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress2)
assert(status.data.dispenser.datatoken.id === tokenAddress2.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.isTrueMinter === false)
assert(status.data.dispenser.minterApproved === false)
assert(status.data.dispenser.active === true)
})
it('Alice withdraws all datatokens', async () => {
const mintTx = await ocean.datatokens.mint(
tokenAddress2,
alice.getId(),
'10',
ocean.OceanDispenser.dispenserAddress
)
assert(mintTx, 'Alice cannot mint tokens')
const tx = await ocean.OceanDispenser.ownerWithdraw(
tokenAddress2,
alice.getId()
)
assert(tx, 'Alice failed to withdraw all her tokens')
await sleep(3000) // let graph ingest our transaction
const status = await getDispenserStatusFromGraph(tokenAddress2)
assert(status.data.dispenser.datatoken.id === tokenAddress2.toLowerCase())
assert(status.data.dispenser.owner.id === alice.getId().toLowerCase())
assert(status.data.dispenser.isTrueMinter === false)
assert(status.data.dispenser.minterApproved === false)
assert(status.data.dispenser.active === true)
assert(status.data.dispenser.balance === '0')
const id = tx.transactionHash.toLowerCase()
const query = {
query: `query DispenserHistory {
dispenserTransactions(orderBy: timestamp, orderDirection: desc,
where: {tx: "${id}"}) {
datatoken{id},
user{id},
amount,
block,
timestamp,
tx,
type
}
}`
}
// console.log(query)
const response = await fetch(subgraphUrl, {
method: 'POST',
body: JSON.stringify(query)
})
const result = await response.json()
assert(result.data.dispenserTransactions[0].type === 'withdraw')
})
})

View File

@ -7,11 +7,20 @@ const web3 = new Web3('http://127.0.0.1:8545')
const subgraphUrl =
'http://localhost:9000/subgraphs/name/oceanprotocol/ocean-subgraph'
function sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
use(spies)
describe('Ending tests', () => {
let result: any
let lastblock
it('Get Graph status', async () => {
await sleep(1000) // let graph ingest our last transactions
lastblock = await web3.eth.getBlockNumber()
const query = {
query: `query {
_meta{hasIndexingErrors,
@ -31,7 +40,6 @@ describe('Ending tests', () => {
assert(result.data._meta.hasIndexingErrors == false)
})
it('Make sure that graph has synced to last block', async () => {
const lastblock = await web3.eth.getBlockNumber()
assert(result.data._meta.block.number === lastblock)
})
})