All files / src/chain authority.ts

97.43% Statements 38/39
83.33% Branches 5/6
100% Functions 11/11
97.05% Lines 33/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                            1x 1x   1x 1x 1x 1x     1x 1x 1x 1x     1x 1x 1x 1x                       1x 1x 1x 1x 1x 1x     38x     38x           38x 38x         3x         3x         9x 5x                   5x   5x             38x 38x 38x      
import {
    PermissionLevel,
    PermissionLevelType,
    PublicKey,
    PublicKeyType,
    Struct,
    TypeAlias,
    UInt16,
    UInt16Type,
    UInt32,
    UInt32Type,
} from '../'
import {isInstanceOf} from '../utils'
 
@TypeAlias('weight_type')
export class Weight extends UInt16 {}
 
@Struct.type('key_weight')
export class KeyWeight extends Struct {
    @Struct.field(PublicKey) key!: PublicKey
    @Struct.field(Weight) weight!: Weight
}
 
@Struct.type('permission_level_weight')
export class PermissionLevelWeight extends Struct {
    @Struct.field(PermissionLevel) permission!: PermissionLevel
    @Struct.field(Weight) weight!: Weight
}
 
@Struct.type('wait_weight')
export class WaitWeight extends Struct {
    @Struct.field(UInt32) wait_sec!: UInt32
    @Struct.field(Weight) weight!: Weight
}
 
export type AuthorityType =
    | Authority
    | {
          threshold: UInt32Type
          keys?: {key: PublicKeyType; weight: UInt16Type}[]
          accounts?: {permission: PermissionLevelType; weight: UInt16Type}[]
          waits?: {wait_sec: UInt32Type; weight: UInt16Type}[]
      }
 
@Struct.type('authority')
export class Authority extends Struct {
    @Struct.field(UInt32) threshold!: UInt32
    @Struct.field(KeyWeight, {array: true}) keys!: KeyWeight[]
    @Struct.field(PermissionLevelWeight, {array: true}) accounts!: PermissionLevelWeight[]
    @Struct.field(WaitWeight, {array: true}) waits!: WaitWeight[]
 
    static from(value: AuthorityType): Authority {
        Iif (isInstanceOf(value, Authority)) {
            return value
        }
        const rv = super.from({
            keys: [],
            accounts: [],
            waits: [],
            ...value,
        }) as Authority
        rv.sort()
        return rv
    }
 
    /** Total weight of all waits. */
    get waitThreshold(): number {
        return this.waits.reduce((val, wait) => val + wait.weight.toNumber(), 0)
    }
 
    /** Weight a key needs to sign for this authority. */
    get keyThreshold(): number {
        return this.threshold.toNumber() - this.waitThreshold
    }
 
    /** Return the weight for given public key, or zero if it is not included in this authority. */
    keyWeight(publicKey: PublicKeyType): number {
        const weight = this.keys.find(({key}) => key.equals(publicKey))
        return weight ? weight.weight.toNumber() : 0
    }
 
    /**
     * Check if given public key has permission in this authority,
     * @attention Does not take indirect permissions for the key via account weights into account.
     * @param publicKey The key to check.
     * @param includePartial Whether to consider auths where the key is included but can't be reached alone (e.g. multisig).
     */
    hasPermission(publicKey: PublicKeyType, includePartial = false): boolean {
        const threshold = includePartial ? 1 : this.keyThreshold
        const weight = this.keyWeight(publicKey)
        return weight >= threshold
    }
 
    /**
     * Sorts the authority weights in place, should be called before including the authority in a `updateauth` action or it might be rejected.
     */
    sort() {
        this.keys.sort((a, b) => a.key.compare(b.key))
        this.accounts.sort((a, b) => a.permission.compare(b.permission))
        this.waits.sort((a, b) => a.wait_sec.value.cmp(b.wait_sec.value))
    }
}