|
| 1 | +import { Lovelace, ByName } from '@cardano-ogmios/schema'; |
| 2 | +import { CardanoSerializationLib, CSL, NotImplementedError } from '@cardano-sdk/core'; |
| 3 | +import { KeyManager } from '../KeyManagement'; |
| 4 | + |
| 5 | +export type Ed25519KeyHashBech32 = string; |
| 6 | +export type VrfKeyHashBech32 = string; |
| 7 | +export type AddressBech32 = string; |
| 8 | +export type PoolMetadataHashBech32 = string; |
| 9 | + |
| 10 | +interface Ratio { |
| 11 | + numerator: number; |
| 12 | + denominator: number; |
| 13 | +} |
| 14 | + |
| 15 | +interface MultiHostNameRelay { |
| 16 | + relayType: 'multihost-name'; |
| 17 | + dnsName: string; |
| 18 | +} |
| 19 | + |
| 20 | +type SingleHostAddrRelay = { |
| 21 | + relayType: 'singlehost-addr'; |
| 22 | + ipv4?: string; |
| 23 | + ipv6?: string; |
| 24 | + port?: number; |
| 25 | +}; |
| 26 | + |
| 27 | +type SingleHostNameRelay = { |
| 28 | + relayType: 'singlehost-name'; |
| 29 | +} & ByName; |
| 30 | + |
| 31 | +type Relay = MultiHostNameRelay | SingleHostAddrRelay | SingleHostNameRelay; |
| 32 | + |
| 33 | +interface PoolMetadata { |
| 34 | + hash: PoolMetadataHashBech32; |
| 35 | + url: string; |
| 36 | +} |
| 37 | + |
| 38 | +interface PoolParameters { |
| 39 | + poolKeyHash: Ed25519KeyHashBech32; |
| 40 | + vrfKeyHash: VrfKeyHashBech32; |
| 41 | + pledge: Lovelace; |
| 42 | + cost: Lovelace; |
| 43 | + margin: Ratio; |
| 44 | + rewardAddress: AddressBech32; |
| 45 | + owners: Ed25519KeyHashBech32[]; |
| 46 | + relays: Relay[]; |
| 47 | + poolMetadata?: PoolMetadata; |
| 48 | +} |
| 49 | + |
| 50 | +export class CertificateFactory { |
| 51 | + readonly #stakeCredential: CSL.StakeCredential; |
| 52 | + readonly #csl: CardanoSerializationLib; |
| 53 | + |
| 54 | + constructor(csl: CardanoSerializationLib, keyManager: KeyManager) { |
| 55 | + this.#csl = csl; |
| 56 | + this.#stakeCredential = csl.StakeCredential.from_keyhash(keyManager.stakeKey.hash()); |
| 57 | + } |
| 58 | + |
| 59 | + stakeKeyRegistration() { |
| 60 | + return this.#csl.Certificate.new_stake_registration(this.#csl.StakeRegistration.new(this.#stakeCredential)); |
| 61 | + } |
| 62 | + |
| 63 | + stakeKeyDeregistration() { |
| 64 | + return this.#csl.Certificate.new_stake_deregistration(this.#csl.StakeDeregistration.new(this.#stakeCredential)); |
| 65 | + } |
| 66 | + |
| 67 | + poolRegistration({ |
| 68 | + poolKeyHash, |
| 69 | + vrfKeyHash, |
| 70 | + pledge, |
| 71 | + cost, |
| 72 | + margin, |
| 73 | + rewardAddress, |
| 74 | + owners, |
| 75 | + relays, |
| 76 | + poolMetadata |
| 77 | + }: PoolParameters) { |
| 78 | + const cslOwners = this.#csl.Ed25519KeyHashes.new(); |
| 79 | + for (const owner of owners) { |
| 80 | + cslOwners.add(this.#csl.Ed25519KeyHash.from_bech32(owner)); |
| 81 | + } |
| 82 | + const cslRelays = this.#createCslRelays(relays); |
| 83 | + const poolParams = this.#csl.PoolParams.new( |
| 84 | + this.#csl.Ed25519KeyHash.from_bech32(poolKeyHash), |
| 85 | + this.#csl.VRFKeyHash.from_bech32(vrfKeyHash), |
| 86 | + this.#csl.BigNum.from_str(pledge.toString()), |
| 87 | + this.#csl.BigNum.from_str(cost.toString()), |
| 88 | + this.#csl.UnitInterval.new( |
| 89 | + this.#csl.BigNum.from_str(margin.numerator.toString()), |
| 90 | + this.#csl.BigNum.from_str(margin.denominator.toString()) |
| 91 | + ), |
| 92 | + this.#csl.RewardAddress.from_address(this.#csl.Address.from_bech32(rewardAddress))!, |
| 93 | + cslOwners, |
| 94 | + cslRelays, |
| 95 | + poolMetadata |
| 96 | + ? this.#csl.PoolMetadata.new( |
| 97 | + this.#csl.URL.new(poolMetadata.url), |
| 98 | + this.#csl.PoolMetadataHash.from_bech32(poolMetadata.hash) |
| 99 | + ) |
| 100 | + : undefined |
| 101 | + ); |
| 102 | + return this.#csl.Certificate.new_pool_registration(this.#csl.PoolRegistration.new(poolParams)); |
| 103 | + } |
| 104 | + |
| 105 | + poolRetirement(poolKeyHash: Ed25519KeyHashBech32, epoch: number) { |
| 106 | + return this.#csl.Certificate.new_pool_retirement( |
| 107 | + this.#csl.PoolRetirement.new(this.#csl.Ed25519KeyHash.from_bech32(poolKeyHash), epoch) |
| 108 | + ); |
| 109 | + } |
| 110 | + |
| 111 | + stakeDelegation(delegatee: Ed25519KeyHashBech32) { |
| 112 | + return this.#csl.Certificate.new_stake_delegation( |
| 113 | + this.#csl.StakeDelegation.new(this.#stakeCredential, this.#csl.Ed25519KeyHash.from_bech32(delegatee)) |
| 114 | + ); |
| 115 | + } |
| 116 | + |
| 117 | + #createCslRelays(relays: Relay[]) { |
| 118 | + const cslRelays = this.#csl.Relays.new(); |
| 119 | + for (const relay of relays) { |
| 120 | + switch (relay.relayType) { |
| 121 | + case 'singlehost-addr': |
| 122 | + if (relay.ipv6) { |
| 123 | + throw new NotImplementedError('Parse IPv6 to byte array'); |
| 124 | + } |
| 125 | + cslRelays.add( |
| 126 | + this.#csl.Relay.new_single_host_addr( |
| 127 | + this.#csl.SingleHostAddr.new( |
| 128 | + relay.port, |
| 129 | + relay.ipv4 |
| 130 | + ? this.#csl.Ipv4.new(new Uint8Array(relay.ipv4.split('.').map((segment) => Number.parseInt(segment)))) |
| 131 | + : undefined |
| 132 | + ) |
| 133 | + ) |
| 134 | + ); |
| 135 | + break; |
| 136 | + case 'singlehost-name': |
| 137 | + cslRelays.add( |
| 138 | + this.#csl.Relay.new_single_host_name( |
| 139 | + this.#csl.SingleHostName.new(relay.port || undefined, this.#csl.DNSRecordAorAAAA.new(relay.hostname)) |
| 140 | + ) |
| 141 | + ); |
| 142 | + break; |
| 143 | + case 'multihost-name': |
| 144 | + cslRelays.add( |
| 145 | + this.#csl.Relay.new_multi_host_name(this.#csl.MultiHostName.new(this.#csl.DNSRecordSRV.new(relay.dnsName))) |
| 146 | + ); |
| 147 | + break; |
| 148 | + default: |
| 149 | + throw new NotImplementedError('Relay type'); |
| 150 | + } |
| 151 | + } |
| 152 | + return cslRelays; |
| 153 | + } |
| 154 | +} |
0 commit comments