import { Injectable } from '@angular/core' ; import { Store } from '@ngrx/store' ; import { Observable } from 'rxjs/Observable' ; import { Subject } from 'rxjs/Subject' ; import 'rxjs/add/observable/fromPromise' ; import 'rxjs/add/operator/filter' ; import 'rxjs/add/operator/first' ; import 'rxjs/add/operator/map' ; import 'rxjs/add/operator/mergeMap' ; import 'rxjs/add/operator/shareReplay' ; import 'rxjs/add/operator/toPromise' ; import * as KudosTokenDefinition from '../../../../build/contracts/KudosToken.json' ; import { SmartContract } from './smart-contract.abstract' ; import { Contract , TruffleContract , TruffleContractActionMethods , TruffleContractEventMethods } from './truffle.interface' ; import { Web3Service , ConnectionStatus } from '../web3.service' ; import { SmartContractExtender , OwnableMixin , BasicTokenMixin , MembershipMixin } from './mixins' ; import { KudosPollFactoryService } from '../kudos-poll-factory.service' ; import { KudosPollService } from './kudos-poll.service' ; interface KudosTokenConstants { version : string ; organisationName : string ; isActivePoll : boolean ; activePoll : string ; getPolls : string [ ] ; getPollsSize : number ; getContact : string ; } type KudosTokenConstantsIteratiors = { getBalances : { member : string ; balance : number ; name : string ; } [ ] ; } ; interface KudosTokenActions { newPoll : boolean ; closePoll : boolean ; editContact : boolean ; } interface KudosTokenEvents { NewPoll : { poll : string ; } ; ClosePoll : { poll : string ; } ; } export type KudosToken = KudosTokenActions & KudosTokenConstantsIteratiors & KudosTokenConstants & KudosTokenEvents ; Web3Service . addABI ( KudosTokenDefinition . abi ) ; class KudosTokenSmartContract extends SmartContract < KudosTokenConstants , KudosTokenConstantsIteratiors , KudosTokenActions , KudosTokenEvents > { } @ Injectable ( ) export class KudosTokenService extends SmartContractExtender ( KudosTokenSmartContract , OwnableMixin , BasicTokenMixin , MembershipMixin ) { isValid : boolean ; private readonly _onIsValid = new Subject < boolean > ( ) ; readonly onIsValid = this . _onIsValid . shareReplay ( ) ; readonly NewPoll$ = this . generateEventObservable ( 'NewPoll' ) ; readonly ClosePoll$ = this . generateEventObservable ( 'ClosePoll' ) ; readonly version = ( ) => this . generateConstant ( 'version' ) ( ) ; readonly organisationName = ( ) => this . generateConstant ( 'organisationName' ) ( ) ; readonly isActivePoll = ( ) => this . generateConstant ( 'isActivePoll' ) ( ) ; readonly activePoll = ( ) => this . generateConstant ( 'activePoll' ) ( ) ; readonly getPolls = ( ) => this . generateConstant ( 'getPolls' ) ( ) ; readonly getPollsSize = ( ) => this . generateConstant ( 'getPollsSize' ) ( ) ; readonly getContact = ( address ) => this . generateConstant ( 'getContact' ) ( address ) ; readonly getBalances = ( ) => this . generateConstantIteration < 'getBalances' > ( ( ) => this . membersNumber ( ) , async ( i ) => { const member = await this . getMember ( i ) ; const name = await this . getContact ( member ) ; return { member , name , balance : + await this . balanceOf ( member ) } ; } ) ; readonly newPoll = ( kudosByMember , maxKudosToMember , minDurationInMinutes ) => this . generateAction ( 'newPoll' ) ( kudosByMember , maxKudosToMember , minDurationInMinutes ) ; readonly closePoll = ( ) => this . generateAction ( 'closePoll' ) ( ) ; readonly editContact = ( address , name ) => this . generateAction ( 'editContact' ) ( address , name ) ; constructor ( protected web3Service , protected store , private kudosPollFactoryService ) { super ( web3Service , store ) ; } initAt ( address ) { this . web3Service . status$ . filter ( status => status === ConnectionStatus . Total ) . first ( ) . subscribe ( ( ) => { if ( ! this . web3Service . web3 . utils . isAddress ( address ) ) { this . _onIsValid . next ( this . isValid = false ) ; return ; } this . web3Contract = this . getWeb3Contract ( KudosTokenDefinition . abi , address ) ; const kudosToken = this . getContract ( KudosTokenDefinition ) ; kudosToken . at ( address ) . then ( contract => { this . contract = < any > contract ; this . initialized = true ; } ) . catch ( ( ) => this . _onIsValid . next ( this . isValid = false ) ) ; this . checkIsValid ( ) . then ( _ => this . _onIsValid . next ( this . isValid = _ ) ) . catch ( ( ) => this . _onIsValid . next ( this . isValid = false ) ) ; setTimeout ( ( ) => this . _onIsValid . next ( this . isValid = this . isValid || false ) , 20 * 1000 ) ; } ) ; } async getContactsOf ( members ) { const contacts = members . map ( async ( member ) => ( { member , name : await this . getContact ( member ) } ) ) ; return await Promise . all ( contacts ) ; } async getContacts ( ) { const members = await this . getMembers ( ) ; const contacts = members . map ( async ( member ) => ( { member , name : await this . getContact ( member ) } ) ) ; return await Promise . all ( contacts ) ; } async myContact ( ) { const myAccount = await this . web3Service . getAccount ( ) . toPromise ( ) ; return await this . getContact ( myAccount ) ; } getPollContractByAddress ( address ) { return this . kudosPollFactoryService . getKudosPollServiceAt ( address ) ; } async getPollContract ( index ) { const polls = await this . getPolls ( ) ; return this . getPollContractByAddress ( polls [ index ] ) ; } async getPollsContracts ( ) { const polls = await this . getPolls ( ) ; return polls . map ( address => this . getPollContractByAddress ( address ) ) ; } async getActivePollContract ( ) { const activePoll = await this . activePoll ( ) ; return activePoll ? this . getPollContractByAddress ( activePoll ) : undefined ; } async getPreviousPollsContracts ( ) { const polls = ( await this . getPolls ( ) ) || [ ] ; if ( await this . isActivePoll ( ) ) { polls . pop ( ) ; } return polls . map ( address => this . getPollContractByAddress ( address ) ) ; } async getPreviousPolls ( ) { const polls = await this . getPolls ( ) ; if ( await this . isActivePoll ( ) ) { polls . pop ( ) ; } return polls ; } private checkIsValid ( ) { return this . onInitialized . map ( async ( ) => { try { switch ( false ) { case this . initialized : case ! ! ( await this . version ( ) ) . match ( /^\d+\.\d+$/ ) : case ! isNaN ( await this . getPollsSize ( ) ) : return false ; default : return true ; } } catch ( e ) { return false ; } } ) . mergeMap ( _ => Observable . fromPromise ( _ ) ) . first ( ) . toPromise ( ) ; } }