quasvel
Version:
Access and interact with Aragon Organizations and their apps.
233 lines (192 loc) • 8.34 kB
text/typescript
import { Contract, utils } from 'ethers'
import { SubscriptionCallback, SubscriptionResult } from '@aragon/connect-types'
import { subscription, App, ForwardingPath, arbitratorAbi } from '@aragon/connect-core'
import { bn } from '../helpers'
import Action from './Action'
import Signer from './Signer'
import Version from './Version'
import DisputableApp from './DisputableApp'
import Staking from './Staking'
import StakingMovement from './StakingMovement'
import { IAgreementConnector } from '../types'
export default class Agreement {
#app: App
#connector: IAgreementConnector
readonly address: string
constructor(connector: IAgreementConnector, app: App) {
this.#connector = connector
this.#app = app
this.address = app.address
}
async disconnect() {
await this.#connector.disconnect()
}
async id(): Promise<string> {
const data = await this.#connector.agreement(this.address)
return data.id
}
async dao(): Promise<string> {
const data = await this.#connector.agreement(this.address)
return data.dao
}
async stakingFactory(): Promise<string> {
const data = await this.#connector.agreement(this.address)
return data.stakingFactory
}
async currentVersion(): Promise<Version> {
return this.#connector.currentVersion(this.address)
}
onCurrentVersion(
callback?: SubscriptionCallback<Version>
): SubscriptionResult<Version> {
return subscription<Version>(callback, (callback) =>
this.#connector.onCurrentVersion(this.address, callback)
)
}
versionId(versionNumber: string): string {
return `${this.address}-version-${versionNumber}`
}
async version(versionNumber: string): Promise<Version> {
return this.#connector.version(this.versionId(versionNumber))
}
onVersion(
versionNumber: string,
callback?: SubscriptionCallback<Version>
): SubscriptionResult<Version> {
return subscription<Version>(callback, (callback) =>
this.#connector.onVersion(this.versionId(versionNumber), callback)
)
}
async disputeFees(versionId: string): Promise<any> {
const version = await this.#connector.version(versionId)
const arbitrator = new Contract(version.arbitrator, arbitratorAbi, this.#app.provider)
return arbitrator.getDisputeFees()
}
async versions({ first = 1000, skip = 0 } = {}): Promise<Version[]> {
return this.#connector.versions(this.address, first, skip)
}
onVersions(
{ first = 1000, skip = 0 } = {},
callback?: SubscriptionCallback<Version[]>
): SubscriptionResult<Version[]> {
return subscription<Version[]>(callback, (callback) =>
this.#connector.onVersions(this.address, first, skip, callback)
)
}
async disputableApps({ first = 1000, skip = 0 } = {}): Promise<DisputableApp[]> {
return this.#connector.disputableApps(this.address, first, skip)
}
onDisputableApps(
{ first = 1000, skip = 0 } = {},
callback?: SubscriptionCallback<DisputableApp[]>
): SubscriptionResult<DisputableApp[]> {
return subscription<DisputableApp[]>(callback, (callback) =>
this.#connector.onDisputableApps(this.address, first, skip, callback)
)
}
signerId(signerAddress: string): string {
return `${this.address}-signer-${signerAddress.toLowerCase()}`
}
async signer(signerAddress: string): Promise<Signer | null> {
return this.#connector.signer(this.signerId(signerAddress))
}
onSigner(
signerAddress: string,
callback?: SubscriptionCallback<Signer | null>
): SubscriptionResult<Signer | null> {
return subscription<Signer | null>(callback, (callback) =>
this.#connector.onSigner(this.signerId(signerAddress), callback)
)
}
stakingId(tokenAddress: string, userAddress: string): string {
return `${tokenAddress.toLowerCase()}-staking-${userAddress.toLowerCase()}`
}
async staking(tokenAddress: string, userAddress: string): Promise<Staking> {
return this.#connector.staking(this.stakingId(tokenAddress, userAddress))
}
onStaking(
tokenAddress: string,
userAddress: string,
callback?: SubscriptionCallback<Staking>
): SubscriptionResult<Staking> {
return subscription<Staking>(callback, (callback) =>
this.#connector.onStaking(this.stakingId(tokenAddress, userAddress), callback)
)
}
async stakingMovements(
tokenAddress: string,
userAddress: string,
{ first = 1000, skip = 0 } = {},
): Promise<StakingMovement[]> {
return this.#connector.stakingMovements(this.stakingId(tokenAddress, userAddress), this.address, first, skip)
}
onStakingMovements(
tokenAddress: string,
userAddress: string,
{ first = 1000, skip = 0 } = {},
callback?: SubscriptionCallback<StakingMovement[]>
): SubscriptionResult<StakingMovement[]> {
return subscription<StakingMovement[]>(callback, (callback) =>
this.#connector.onStakingMovements(this.stakingId(tokenAddress, userAddress), this.address, first, skip, callback)
)
}
actionId(actionNumber: string): string {
return `${this.address.toLowerCase()}-action-${actionNumber}`
}
async action(actionNumber: string): Promise<Action> {
const action = await this.tryAction(actionNumber)
if (!action) {
throw Error(`Could not find given action number ${actionNumber}`)
}
return action as Action
}
async tryAction(actionNumber: string): Promise<Action | null> {
return this.#connector.action(this.actionId(actionNumber))
}
onAction(actionNumber: string, callback?: SubscriptionCallback<Action | null>): SubscriptionResult<Action | null> {
return subscription<Action | null>(callback, (callback) =>
this.#connector.onAction(this.actionId(actionNumber), callback)
)
}
async sign(signerAddress: string, versionNumber?: string): Promise<ForwardingPath> {
if (!versionNumber) {
versionNumber = (await this.currentVersion()).versionId
}
return this.#app.intent('sign', [versionNumber], { actAs: signerAddress })
}
async challenge(actionNumber: string, settlementOffer: string, finishedEvidence: boolean, context: string, signerAddress: string): Promise<ForwardingPath> {
const intent = await this.#app.intent('challengeAction', [actionNumber, settlementOffer, finishedEvidence, utils.toUtf8Bytes(context)], { actAs: signerAddress })
const action = await this.action(actionNumber)
const { feeToken, feeAmount } = await this.disputeFees(action.versionId)
const { tokenId: collateralToken, challengeAmount } = await action.collateralRequirement()
const challengeCollateral = bn(challengeAmount)
// approve challenge collateral and dispute fees
const preTransactions = []
if (feeToken.toLowerCase() == collateralToken.toLowerCase()) {
const approvalAmount = challengeCollateral.add(feeAmount)
const approvePreTransactions = await intent.buildApprovePreTransactions({ address: feeToken, value: approvalAmount })
preTransactions.push(...approvePreTransactions)
} else {
const feesPreTransactions = await intent.buildApprovePreTransactions({ address: feeToken, value: feeAmount })
const collateralPreTransactions = await intent.buildApprovePreTransactions({ address: collateralToken, value: challengeCollateral })
preTransactions.push(...feesPreTransactions, ...collateralPreTransactions)
}
intent.applyPreTransactions(preTransactions)
return intent
}
async dispute(actionNumber: string, finishedEvidence: boolean, signerAddress: string): Promise<ForwardingPath> {
const intent = await this.#app.intent('disputeAction', [actionNumber, finishedEvidence], { actAs: signerAddress })
const action = await this.action(actionNumber)
const { feeToken, feeAmount } = await this.disputeFees(action.versionId)
// approve dispute fees
const preTransactions = await intent.buildApprovePreTransactions({ address: feeToken, value: feeAmount })
intent.applyPreTransactions(preTransactions)
return intent
}
settle(actionNumber: string, signerAddress: string): Promise<ForwardingPath> {
return this.#app.intent('settleAction', [actionNumber], { actAs: signerAddress })
}
close(actionNumber: string, signerAddress: string): Promise<ForwardingPath> {
return this.#app.intent('closeAction', [actionNumber], { actAs: signerAddress })
}
}