diff --git a/templates/reset_epoch.cdc b/templates/reset_epoch.cdc index 226a83d0..f3489565 100644 --- a/templates/reset_epoch.cdc +++ b/templates/reset_epoch.cdc @@ -3,7 +3,6 @@ import FlowIDTableStaking from 0x8624b52f9ddcd04a transaction(currentEpochCounter: UInt64, randomSource: String, - newPayout: UFix64?, startView: UInt64, endView: UInt64) { @@ -13,7 +12,6 @@ transaction(currentEpochCounter: UInt64, heartbeat.resetEpoch(currentEpochCounter: currentEpochCounter, randomSource: randomSource, - newPayout: newPayout, startView: startView, endView: endView, collectorClusters: [], diff --git a/templates/reset_epoch_with_end_staking_auction.cdc b/templates/reset_epoch_with_end_staking_auction.cdc index dd8754c7..78bcbc92 100644 --- a/templates/reset_epoch_with_end_staking_auction.cdc +++ b/templates/reset_epoch_with_end_staking_auction.cdc @@ -3,7 +3,6 @@ import FlowIDTableStaking from 0x8624b52f9ddcd04a transaction(currentEpochCounter: UInt64, randomSource: String, - newPayout: UFix64?, startView: UInt64, stakingEndView: UInt64, endView: UInt64) { @@ -19,7 +18,6 @@ transaction(currentEpochCounter: UInt64, heartbeat.resetEpoch(currentEpochCounter: currentEpochCounter, randomSource: randomSource, - newPayout: newPayout, startView: startView, stakingEndView: stakingEndView, endView: endView, diff --git a/transactions/update-contract/2023/may-3-rewards/FlowEpoch.cdc b/transactions/update-contract/2023/may-3-rewards/FlowEpoch.cdc new file mode 100644 index 00000000..d13294a4 --- /dev/null +++ b/transactions/update-contract/2023/may-3-rewards/FlowEpoch.cdc @@ -0,0 +1,875 @@ +import FungibleToken from 0xf233dcee88fe0abe +import FlowToken from 0x1654653399040a61 +import FlowIDTableStaking from 0x8624b52f9ddcd04a +import FlowClusterQC from 0x8624b52f9ddcd04a +import FlowDKG from 0x8624b52f9ddcd04a +import FlowFees from 0xf919ee77447b7497 + +// The top-level smart contract managing the lifecycle of epochs. In Flow, +// epochs are the smallest unit of time where the identity table (the set of +// network operators) is static. Operators may only leave or join the network +// at epoch boundaries. Operators may be ejected during an epoch for various +// misdemeanours, but they remain in the identity table until the epoch ends. +// +// Epochs are split into 3 phases: +// |========================================================== +// | EPOCH N || EPOCH N+1 ... +// |----- Staking -----|- Setup -|- Committed -|| ... +// |========================================================== +// +// 1) STAKING PHASE +// Node operators are able to submit staking requests for the NEXT epoch during +// this phase. At the end of this phase, the Epoch smart contract resolves the +// outstanding staking requests and determines the identity table for the next +// epoch. The Epoch smart contract emits the EpochSetup service event containing +// the identity table for the next epoch, which initiates the transition to the +// Epoch Setup Phase. +// +// 2) SETUP PHASE +// When this phase begins the participants in the next epoch are set. During this +// phase, these participants prepare for the next epoch. In particular, collection +// nodes submit votes for their cluster's root quorum certificate and consensus +// nodes run the distributed key generation protocol (DKG) to set up the random +// beacon. When these preparations are complete, the Epoch smart contract emits the +// EpochCommit service event containing the artifacts of the set process, which +// initiates the transition to the Epoch Commit Phase. +// +// 3) COMMITTED PHASE +// When this phase begins, the network is fully prepared to transition to the next +// epoch. A failure to enter this phase before transitioning to the next epoch +// indicates that the participants in the next epoch failed to complete the set up +// procedure, which is a critical failure and will cause the chain to halt. + +pub contract FlowEpoch { + + pub enum EpochPhase: UInt8 { + pub case STAKINGAUCTION + pub case EPOCHSETUP + pub case EPOCHCOMMIT + } + + pub enum NodeRole: UInt8 { + pub case NONE + pub case Collector + pub case Consensus + pub case Execution + pub case Verification + pub case Access + } + + /// The Epoch Setup service event is emitted when we transition to the Epoch Setup + /// phase. It contains the finalized identity table for the upcoming epoch. + pub event EpochSetup( + + /// The counter for the upcoming epoch. Must be one greater than the + /// counter for the current epoch. + counter: UInt64, + + /// Identity table for the upcoming epoch with all node information. + /// Includes: + /// nodeID, staking key, networking key, networking address, role, + /// staking information, weight, and more. + nodeInfo: [FlowIDTableStaking.NodeInfo], + + /// The first view (inclusive) of the upcoming epoch. + firstView: UInt64, + + /// The last view (inclusive) of the upcoming epoch. + finalView: UInt64, + + /// The cluster assignment for the upcoming epoch. Each element in the list + /// represents one cluster and contains all the node IDs assigned to that + /// cluster, with their weights and votes + collectorClusters: [FlowClusterQC.Cluster], + + /// The source of randomness to seed the leader selection algorithm with + /// for the upcoming epoch. + randomSource: String, + + /// The deadlines of each phase in the DKG protocol to be completed in the upcoming + /// EpochSetup phase. Deadlines are specified in terms of a consensus view number. + /// When a DKG participant observes a finalized and sealed block with view greater + /// than the given deadline, it can safely transition to the next phase. + DKGPhase1FinalView: UInt64, + DKGPhase2FinalView: UInt64, + DKGPhase3FinalView: UInt64 + ) + + /// The EpochCommit service event is emitted when we transition from the Epoch + /// Committed phase. It is emitted only when all preparation for the upcoming epoch + /// has been completed + pub event EpochCommit( + + /// The counter for the upcoming epoch. Must be equal to the counter in the + /// previous EpochSetup event. + counter: UInt64, + + /// The result of the QC aggregation process. Each element contains + /// all the nodes and votes received for a particular cluster + /// QC stands for quorum certificate that each cluster generates. + clusterQCs: [FlowClusterQC.ClusterQC], + + /// The resulting public keys from the DKG process, encoded as by the flow-go + /// crypto library, then hex-encoded. + /// Group public key is the first element, followed by the individual keys + dkgPubKeys: [String], + ) + + /// Contains specific metadata about a particular epoch + /// All historical epoch metadata is stored permanently + pub struct EpochMetadata { + + /// The identifier for the epoch + pub let counter: UInt64 + + /// The seed used for generating the epoch setup + pub let seed: String + + /// The first view of this epoch + pub let startView: UInt64 + + /// The last view of this epoch + pub let endView: UInt64 + + /// The last view of the staking auction + pub let stakingEndView: UInt64 + + /// The total rewards that are paid out for the epoch + pub var totalRewards: UFix64 + + /// The reward amounts that are paid to each individual node and its delegators + pub var rewardAmounts: [FlowIDTableStaking.RewardsBreakdown] + + /// Tracks if rewards have been paid for this epoch + pub var rewardsPaid: Bool + + /// The organization of collector node IDs into clusters + /// determined by a round robin sorting algorithm + pub let collectorClusters: [FlowClusterQC.Cluster] + + /// The Quorum Certificates from the ClusterQC contract + pub var clusterQCs: [FlowClusterQC.ClusterQC] + + /// The public keys associated with the Distributed Key Generation + /// process that consensus nodes participate in + /// Group key is the last element at index: length - 1 + pub var dkgKeys: [String] + + init(counter: UInt64, + seed: String, + startView: UInt64, + endView: UInt64, + stakingEndView: UInt64, + totalRewards: UFix64, + collectorClusters: [FlowClusterQC.Cluster], + clusterQCs: [FlowClusterQC.ClusterQC], + dkgKeys: [String]) { + + self.counter = counter + self.seed = seed + self.startView = startView + self.endView = endView + self.stakingEndView = stakingEndView + self.totalRewards = totalRewards + self.rewardAmounts = [] + self.rewardsPaid = false + self.collectorClusters = collectorClusters + self.clusterQCs = clusterQCs + self.dkgKeys = dkgKeys + } + + access(account) fun setTotalRewards(_ newRewards: UFix64) { + self.totalRewards = newRewards + } + + access(account) fun setRewardAmounts(_ rewardBreakdown: [FlowIDTableStaking.RewardsBreakdown]) { + self.rewardAmounts = rewardBreakdown + } + + access(account) fun setRewardsPaid(_ rewardsPaid: Bool) { + self.rewardsPaid = rewardsPaid + } + + access(account) fun setClusterQCs(qcs: [FlowClusterQC.ClusterQC]) { + self.clusterQCs = qcs + } + + access(account) fun setDKGGroupKey(keys: [String]) { + self.dkgKeys = keys + } + } + + /// Metadata that is managed and can be changed by the Admin/// + pub struct Config { + /// The number of views in an entire epoch + pub(set) var numViewsInEpoch: UInt64 + + /// The number of views in the staking auction + pub(set) var numViewsInStakingAuction: UInt64 + + /// The number of views in each dkg phase + pub(set) var numViewsInDKGPhase: UInt64 + + /// The number of collector clusters in each epoch + pub(set) var numCollectorClusters: UInt16 + + /// Tracks the rate at which the rewards payout increases every epoch + /// This value is multiplied by the FLOW total supply to get the next payout + pub(set) var FLOWsupplyIncreasePercentage: UFix64 + + init(numViewsInEpoch: UInt64, numViewsInStakingAuction: UInt64, numViewsInDKGPhase: UInt64, numCollectorClusters: UInt16, FLOWsupplyIncreasePercentage: UFix64) { + self.numViewsInEpoch = numViewsInEpoch + self.numViewsInStakingAuction = numViewsInStakingAuction + self.numViewsInDKGPhase = numViewsInDKGPhase + self.numCollectorClusters = numCollectorClusters + self.FLOWsupplyIncreasePercentage = FLOWsupplyIncreasePercentage + } + } + + /// Holds the `FlowEpoch.Config` struct with the configurable metadata + access(contract) let configurableMetadata: Config + + /// Metadata that is managed by the smart contract + /// and cannot be changed by the Admin + + /// Contains a historical record of the metadata from all previous epochs + /// indexed by epoch number + + /// Returns the metadata from the specified epoch + /// or nil if it isn't found + /// Epoch Metadata is stored in account storage so the growing dictionary + /// does not have to be loaded every time the contract is loaded + pub fun getEpochMetadata(_ epochCounter: UInt64): EpochMetadata? { + if let metadataDictionary = self.account.borrow<&{UInt64: EpochMetadata}>(from: self.metadataStoragePath) { + return metadataDictionary[epochCounter] + } + return nil + } + + /// Saves a modified EpochMetadata struct to the metadata in account storage + /// + access(contract) fun saveEpochMetadata(_ newMetadata: EpochMetadata) { + pre { + self.currentEpochCounter == (0 as UInt64) || + (newMetadata.counter >= self.currentEpochCounter - (1 as UInt64) && + newMetadata.counter <= self.proposedEpochCounter()): + "Cannot modify epoch metadata from epochs after the proposed epoch or before the previous epoch" + } + if let metadataDictionary = self.account.borrow<&{UInt64: EpochMetadata}>(from: self.metadataStoragePath) { + if let metadata = metadataDictionary[newMetadata.counter] { + assert ( + metadata.counter == newMetadata.counter, + message: "Cannot save metadata with mismatching epoch counters" + ) + } + metadataDictionary[newMetadata.counter] = newMetadata + } + } + + /// The counter, or ID, of the current epoch + pub var currentEpochCounter: UInt64 + + /// The current phase that the epoch is in + pub var currentEpochPhase: EpochPhase + + /// Path where the `FlowEpoch.Admin` resource is stored + pub let adminStoragePath: StoragePath + + /// Path where the `FlowEpoch.Heartbeat` resource is stored + pub let heartbeatStoragePath: StoragePath + + /// Path where the `{UInt64: EpochMetadata}` dictionary is stored + pub let metadataStoragePath: StoragePath + + /// Resource that can update some of the contract fields + pub resource Admin { + pub fun updateEpochViews(_ newEpochViews: UInt64) { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only update fields during the staking auction" + FlowEpoch.isValidPhaseConfiguration(FlowEpoch.configurableMetadata.numViewsInStakingAuction, + FlowEpoch.configurableMetadata.numViewsInDKGPhase, + newEpochViews): "New Epoch Views must be greater than the sum of staking and DKG Phase views" + } + + FlowEpoch.configurableMetadata.numViewsInEpoch = newEpochViews + } + + pub fun updateAuctionViews(_ newAuctionViews: UInt64) { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only update fields during the staking auction" + FlowEpoch.isValidPhaseConfiguration(newAuctionViews, + FlowEpoch.configurableMetadata.numViewsInDKGPhase, + FlowEpoch.configurableMetadata.numViewsInEpoch): "Epoch Views must be greater than the sum of new staking and DKG Phase views" + } + + FlowEpoch.configurableMetadata.numViewsInStakingAuction = newAuctionViews + } + + pub fun updateDKGPhaseViews(_ newPhaseViews: UInt64) { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only update fields during the staking auction" + FlowEpoch.isValidPhaseConfiguration(FlowEpoch.configurableMetadata.numViewsInStakingAuction, + newPhaseViews, + FlowEpoch.configurableMetadata.numViewsInEpoch): "Epoch Views must be greater than the sum of staking and new DKG Phase views" + } + + FlowEpoch.configurableMetadata.numViewsInDKGPhase = newPhaseViews + } + + pub fun updateNumCollectorClusters(_ newNumClusters: UInt16) { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only update fields during the staking auction" + } + + FlowEpoch.configurableMetadata.numCollectorClusters = newNumClusters + } + + pub fun updateFLOWSupplyIncreasePercentage(_ newPercentage: UFix64) { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only update fields during the staking auction" + newPercentage <= 1.0 as UFix64: "New value must be between zero and one" + } + + FlowEpoch.configurableMetadata.FLOWsupplyIncreasePercentage = newPercentage + } + + // Enable or disable automatic rewards calculations and payments + pub fun updateAutomaticRewardsEnabled(_ enabled: Bool) { + FlowEpoch.account.load(from: /storage/flowAutomaticRewardsEnabled) + FlowEpoch.account.save(enabled, to: /storage/flowAutomaticRewardsEnabled) + } + } + + /// Resource that is controlled by the protocol and is used + /// to change the current phase of the epoch or reset the epoch if needed + /// + pub resource Heartbeat { + + /// Function that is called every block to advance the epoch + /// and change phase if the required conditions have been met + pub fun advanceBlock() { + + switch FlowEpoch.currentEpochPhase { + case EpochPhase.STAKINGAUCTION: + let currentBlock = getCurrentBlock() + let currentEpochMetadata = FlowEpoch.getEpochMetadata(FlowEpoch.currentEpochCounter)! + // Pay rewards only if automatic rewards are enabled + // This will only actually happen once immediately after the epoch begins + // because `payRewardsForPreviousEpoch()` will only pay rewards once + if FlowEpoch.automaticRewardsEnabled() { + self.payRewardsForPreviousEpoch() + } + if currentBlock.view >= currentEpochMetadata.stakingEndView { + self.endStakingAuction() + } + case EpochPhase.EPOCHSETUP: + if FlowClusterQC.votingCompleted() && (FlowDKG.dkgCompleted() != nil) { + self.startEpochCommit() + } + case EpochPhase.EPOCHCOMMIT: + let currentBlock = getCurrentBlock() + let currentEpochMetadata = FlowEpoch.getEpochMetadata(FlowEpoch.currentEpochCounter)! + if currentBlock.view >= currentEpochMetadata.endView { + self.calculateAndSetRewards() + self.endEpoch() + } + default: + return + } + } + + /// Calls `FlowEpoch` functions to end the staking auction phase + /// and start the Epoch Setup phase + pub fun endStakingAuction() { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION: "Can only end staking auction during the staking auction" + } + + FlowEpoch.endStakingAuction() + + FlowEpoch.startEpochSetup(randomSource: unsafeRandom().toString()) + } + + /// Calls `FlowEpoch` functions to end the Epoch Setup phase + /// and start the Epoch Setup Phase + pub fun startEpochCommit() { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.EPOCHSETUP: "Can only end Epoch Setup during Epoch Setup" + } + + FlowEpoch.startEpochCommit() + } + + /// Calls `FlowEpoch` functions to end the Epoch Commit phase + /// and start the Staking Auction phase of a new epoch + pub fun endEpoch() { + pre { + FlowEpoch.currentEpochPhase == EpochPhase.EPOCHCOMMIT: "Can only end epoch during Epoch Commit" + } + + FlowEpoch.startNewEpoch() + } + + /// Needs to be called before the epoch is over + /// Calculates rewards for the current epoch and stores them in epoch metadata + pub fun calculateAndSetRewards() { + FlowEpoch.calculateAndSetRewards() + } + + pub fun payRewardsForPreviousEpoch() { + FlowEpoch.payRewardsForPreviousEpoch() + } + + /// Protocol can use this to reboot the epoch with a new genesis + /// in case the epoch setup phase did not complete properly + /// before the end of an epoch + pub fun resetEpoch( + currentEpochCounter: UInt64, + randomSource: String, + startView: UInt64, + stakingEndView: UInt64, + endView: UInt64, + collectorClusters: [FlowClusterQC.Cluster], + clusterQCs: [FlowClusterQC.ClusterQC], + dkgPubKeys: [String]) + { + pre { + currentEpochCounter == FlowEpoch.currentEpochCounter: + "Cannot submit a current Epoch counter that does not match the current counter stored in the smart contract" + FlowEpoch.isValidPhaseConfiguration(stakingEndView-startView+1, FlowEpoch.configurableMetadata.numViewsInDKGPhase, endView-startView+1): + "Invalid startView, stakingEndView, and endView configuration" + } + + if FlowEpoch.currentEpochPhase == EpochPhase.STAKINGAUCTION { + // Since we are resetting the epoch, we do not need to + // start epoch setup also. We only need to end the staking auction + FlowEpoch.borrowStakingAdmin().endStakingAuction() + } else { + // force reset the QC and DKG + FlowEpoch.borrowClusterQCAdmin().forceStopVoting() + FlowEpoch.borrowDKGAdmin().forceEndDKG() + } + + // Create new Epoch metadata for the next epoch + // with the new values + let newEpochMetadata = EpochMetadata( + counter: currentEpochCounter + 1, + seed: randomSource, + startView: startView, + endView: endView, + stakingEndView: stakingEndView, + // This will be overwritten in `calculateAndSetRewards` below + totalRewards: UFix64(0.0), + collectorClusters: collectorClusters, + clusterQCs: clusterQCs, + dkgKeys: dkgPubKeys) + + FlowEpoch.saveEpochMetadata(newEpochMetadata) + + // Calculate rewards for the current epoch + // and set the payout for the next epoch + self.calculateAndSetRewards() + + // Start a new Epoch, which increments the current epoch counter + FlowEpoch.startNewEpoch() + } + } + + /// Calculates a new token payout for the current epoch + /// and sets the new payout for the next epoch + access(account) fun calculateAndSetRewards() { + + let stakingAdmin = self.borrowStakingAdmin() + + // Calculate rewards for the current epoch that is about to end + // and save that reward breakdown in the epoch metadata for the current epoch + let rewardsSummary = stakingAdmin.calculateRewards() + let currentMetadata = self.getEpochMetadata(self.currentEpochCounter)! + currentMetadata.setRewardAmounts(rewardsSummary.breakdown) + currentMetadata.setTotalRewards(rewardsSummary.totalRewards) + self.saveEpochMetadata(currentMetadata) + + if FlowEpoch.automaticRewardsEnabled() { + // Calculate the total supply of FLOW after the current epoch's payout + // the calculation includes the tokens that haven't been minted for the current epoch yet + let currentPayout = FlowIDTableStaking.getEpochTokenPayout() + let feeAmount = FlowFees.getFeeBalance() + var flowTotalSupplyAfterPayout = 0.0 + if feeAmount >= currentPayout { + flowTotalSupplyAfterPayout = FlowToken.totalSupply + } else { + flowTotalSupplyAfterPayout = FlowToken.totalSupply + (currentPayout - feeAmount) + } + + // Load the amount of bonus tokens from storage + let bonusTokens = FlowEpoch.getBonusTokens() + + // Subtract bonus tokens from the total supply to get the real supply + if bonusTokens < flowTotalSupplyAfterPayout { + flowTotalSupplyAfterPayout = flowTotalSupplyAfterPayout - bonusTokens + } + + // Calculate the payout for the next epoch + let proposedPayout = flowTotalSupplyAfterPayout * FlowEpoch.configurableMetadata.FLOWsupplyIncreasePercentage + + // Set the new payout in the staking contract and proposed Epoch Metadata + self.borrowStakingAdmin().setEpochTokenPayout(proposedPayout) + let proposedMetadata = self.getEpochMetadata(self.proposedEpochCounter()) + ?? panic("Cannot set rewards for the next epoch becuase it hasn't been proposed yet") + proposedMetadata.setTotalRewards(proposedPayout) + self.saveEpochMetadata(proposedMetadata) + } + } + + /// Pays rewards to the nodes and delegators of the previous epoch + access(account) fun payRewardsForPreviousEpoch() { + if let previousEpochMetadata = self.getEpochMetadata(self.currentEpochCounter - (1 as UInt64)) { + if !previousEpochMetadata.rewardsPaid { + let summary = FlowIDTableStaking.EpochRewardsSummary(totalRewards: previousEpochMetadata.totalRewards, breakdown: previousEpochMetadata.rewardAmounts) + self.borrowStakingAdmin().payRewards(summary) + previousEpochMetadata.setRewardsPaid(true) + self.saveEpochMetadata(previousEpochMetadata) + } + } + } + + /// Moves staking tokens between buckets, + /// and starts the new epoch staking auction + access(account) fun startNewEpoch() { + + // End QC and DKG if they are still enabled + if FlowClusterQC.inProgress { + self.borrowClusterQCAdmin().stopVoting() + } + if FlowDKG.dkgEnabled { + self.borrowDKGAdmin().endDKG() + } + + self.borrowStakingAdmin().moveTokens() + + self.currentEpochPhase = EpochPhase.STAKINGAUCTION + + // Update the epoch counters + self.currentEpochCounter = self.proposedEpochCounter() + } + + /// Ends the staking Auction with all the proposed nodes approved + access(account) fun endStakingAuction() { + self.borrowStakingAdmin().endStakingAuction() + } + + /// Starts the EpochSetup phase and emits the epoch setup event + /// This has to be called directly after `endStakingAuction` + access(account) fun startEpochSetup(randomSource: String) { + + // Get all the nodes that are proposed for the next epoch + let ids = FlowIDTableStaking.getProposedNodeIDs() + + // Holds the node Information of all the approved nodes + var nodeInfoArray: [FlowIDTableStaking.NodeInfo] = [] + + // Holds node IDs of only collector nodes for QC + var collectorNodeIDs: [String] = [] + + // Holds node IDs of only consensus nodes for DKG + var consensusNodeIDs: [String] = [] + + // Get NodeInfo for all the nodes + // Get all the collector and consensus nodes + // to initialize the QC and DKG + for id in ids { + let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: id) + + nodeInfoArray.append(nodeInfo) + + if nodeInfo.role == NodeRole.Collector.rawValue { + collectorNodeIDs.append(nodeInfo.id) + } + + if nodeInfo.role == NodeRole.Consensus.rawValue { + consensusNodeIDs.append(nodeInfo.id) + } + } + + // Organize the collector nodes into clusters + let collectorClusters = self.createCollectorClusters(nodeIDs: collectorNodeIDs) + + // Start QC Voting with the supplied clusters + self.borrowClusterQCAdmin().startVoting(clusters: collectorClusters) + + // Start DKG with the consensus nodes + self.borrowDKGAdmin().startDKG(nodeIDs: consensusNodeIDs) + + let currentEpochMetadata = self.getEpochMetadata(self.currentEpochCounter)! + + // Initialze the metadata for the next epoch + // QC and DKG metadata will be filled in later + let proposedEpochMetadata = EpochMetadata(counter: self.proposedEpochCounter(), + seed: randomSource, + startView: currentEpochMetadata.endView + UInt64(1), + endView: currentEpochMetadata.endView + self.configurableMetadata.numViewsInEpoch, + stakingEndView: currentEpochMetadata.endView + self.configurableMetadata.numViewsInStakingAuction, + totalRewards: 0.0 as UFix64, + collectorClusters: collectorClusters, + clusterQCs: [], + dkgKeys: []) + + self.saveEpochMetadata(proposedEpochMetadata) + + self.currentEpochPhase = EpochPhase.EPOCHSETUP + + emit EpochSetup(counter: proposedEpochMetadata.counter, + nodeInfo: nodeInfoArray, + firstView: proposedEpochMetadata.startView, + finalView: proposedEpochMetadata.endView, + collectorClusters: collectorClusters, + randomSource: randomSource, + DKGPhase1FinalView: proposedEpochMetadata.startView + self.configurableMetadata.numViewsInStakingAuction + self.configurableMetadata.numViewsInDKGPhase - 1 as UInt64, + DKGPhase2FinalView: proposedEpochMetadata.startView + self.configurableMetadata.numViewsInStakingAuction + (2 as UInt64 * self.configurableMetadata.numViewsInDKGPhase) - 1 as UInt64, + DKGPhase3FinalView: proposedEpochMetadata.startView + self.configurableMetadata.numViewsInStakingAuction + (3 as UInt64 * self.configurableMetadata.numViewsInDKGPhase) - 1 as UInt64) + } + + /// Ends the EpochSetup phase when the QC and DKG are completed + /// and emits the EpochCommit event with the results + access(account) fun startEpochCommit() { + if !FlowClusterQC.votingCompleted() || FlowDKG.dkgCompleted() == nil { + return + } + + let clusters = FlowClusterQC.getClusters() + + // Holds the quorum certificates for each cluster + var clusterQCs: [FlowClusterQC.ClusterQC] = [] + + // iterate through all the clusters and create their certificate arrays + for cluster in clusters { + var certificate = cluster.generateQuorumCertificate() + ?? panic("Could not generate the quorum certificate for this cluster") + + clusterQCs.append(certificate) + } + + // Set cluster QCs in the proposed epoch metadata + // and stop QC voting + let proposedEpochMetadata = self.getEpochMetadata(self.proposedEpochCounter())! + proposedEpochMetadata.setClusterQCs(qcs: clusterQCs) + + // Set DKG result keys in the proposed epoch metadata + // and stop DKG + let dkgKeys = FlowDKG.dkgCompleted()! + let unwrappedKeys: [String] = [] + for key in dkgKeys { + unwrappedKeys.append(key!) + } + proposedEpochMetadata.setDKGGroupKey(keys: unwrappedKeys) + + self.saveEpochMetadata(proposedEpochMetadata) + + self.currentEpochPhase = EpochPhase.EPOCHCOMMIT + + emit EpochCommit(counter: self.proposedEpochCounter(), + clusterQCs: clusterQCs, + dkgPubKeys: unwrappedKeys) + } + + /// Borrow a reference to the FlowIDTableStaking Admin resource + access(contract) fun borrowStakingAdmin(): &FlowIDTableStaking.Admin { + let adminRef = self.account.borrow<&FlowIDTableStaking.Admin>(from: FlowIDTableStaking.StakingAdminStoragePath) + ?? panic("Could not borrow staking admin") + + return adminRef + } + + /// Borrow a reference to the ClusterQCs Admin resource + access(contract) fun borrowClusterQCAdmin(): &FlowClusterQC.Admin { + let adminRef = self.account.borrow<&FlowClusterQC.Admin>(from: FlowClusterQC.AdminStoragePath) + ?? panic("Could not borrow qc admin") + + return adminRef + } + + /// Borrow a reference to the DKG Admin resource + access(contract) fun borrowDKGAdmin(): &FlowDKG.Admin { + let adminRef = self.account.borrow<&FlowDKG.Admin>(from: FlowDKG.AdminStoragePath) + ?? panic("Could not borrow dkg admin") + + return adminRef + } + + /// Makes sure the set of phase lengths (in views) are valid. + /// Sub-phases cannot be greater than the full epoch length. + pub fun isValidPhaseConfiguration(_ auctionLen: UInt64, _ dkgPhaseLen: UInt64, _ epochLen: UInt64): Bool { + return (auctionLen + ((3 as UInt64)*dkgPhaseLen)) < epochLen + } + + /// Randomizes the list of collector node ID and uses a round robin algorithm + /// to assign all collector nodes to equal sized clusters + pub fun createCollectorClusters(nodeIDs: [String]): [FlowClusterQC.Cluster] { + pre { + UInt16(nodeIDs.length) >= self.configurableMetadata.numCollectorClusters: "Cannot have less collector nodes than clusters" + } + var shuffledIDs = self.randomize(nodeIDs) + + // Holds cluster assignments for collector nodes + let clusters: [FlowClusterQC.Cluster] = [] + var clusterIndex: UInt16 = 0 + let nodeWeightsDictionary: [{String: UInt64}] = [] + while clusterIndex < self.configurableMetadata.numCollectorClusters { + nodeWeightsDictionary.append({}) + clusterIndex = clusterIndex + 1 as UInt16 + } + clusterIndex = 0 + + for id in shuffledIDs { + + let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: id) + + nodeWeightsDictionary[clusterIndex][id] = nodeInfo.initialWeight + + // Advance to the next cluster, or back to the first if we have gotten to the last one + clusterIndex = clusterIndex + 1 as UInt16 + if clusterIndex == self.configurableMetadata.numCollectorClusters { + clusterIndex = 0 + } + } + + // Create the clusters Array that is sent to the QC contract + // and emitted in the EpochSetup event + clusterIndex = 0 + while clusterIndex < self.configurableMetadata.numCollectorClusters { + clusters.append(FlowClusterQC.Cluster(index: clusterIndex, nodeWeights: nodeWeightsDictionary[clusterIndex]!)) + clusterIndex = clusterIndex + 1 as UInt16 + } + + return clusters + } + + /// A function to generate a random permutation of arr[] + /// using the fisher yates shuffling algorithm + pub fun randomize(_ array: [String]): [String] { + + var i = array.length - 1 + + // Start from the last element and swap one by one. We don't + // need to run for the first element that's why i > 0 + while i > 0 + { + // Pick a random index from 0 to i + var randomNum = unsafeRandom() + var randomIndex = randomNum % UInt64(i + 1) + + // Swap arr[i] with the element at random index + var temp = array[i] + array[i] = array[randomIndex] + array[randomIndex] = temp + + i = i - 1 + } + + return array + } + + /// Collector nodes call this function to get their QC Voter resource + /// in order to participate the the QC generation for their cluster + pub fun getClusterQCVoter(nodeStaker: &FlowIDTableStaking.NodeStaker): @FlowClusterQC.Voter { + let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: nodeStaker.id) + + assert ( + nodeInfo.role == NodeRole.Collector.rawValue, + message: "Node operator must be a collector node to get a QC Voter object" + ) + + let clusterQCAdmin = self.borrowClusterQCAdmin() + return <-clusterQCAdmin.createVoter(nodeID: nodeStaker.id, stakingKey: nodeInfo.stakingKey) + } + + /// Consensus nodes call this function to get their DKG Participant resource + /// in order to participate in the DKG for the next epoch + pub fun getDKGParticipant(nodeStaker: &FlowIDTableStaking.NodeStaker): @FlowDKG.Participant { + let nodeInfo = FlowIDTableStaking.NodeInfo(nodeID: nodeStaker.id) + + assert ( + nodeInfo.role == NodeRole.Consensus.rawValue, + message: "Node operator must be a consensus node to get a DKG Participant object" + ) + + let dkgAdmin = self.borrowDKGAdmin() + return <-dkgAdmin.createParticipant(nodeID: nodeStaker.id) + } + + /// Returns the metadata that is able to be configured by the admin + pub fun getConfigMetadata(): Config { + return self.configurableMetadata + } + + /// The proposed Epoch counter is always the current counter plus 1 + pub fun proposedEpochCounter(): UInt64 { + return self.currentEpochCounter + 1 as UInt64 + } + + pub fun automaticRewardsEnabled(): Bool { + return self.account.copy(from: /storage/flowAutomaticRewardsEnabled) ?? false + } + + /// Gets the current amount of bonus tokens left to be destroyed + /// Bonus tokens are tokens that were allocated as a decentralization incentive + /// that are currently in the process of being destroyed. The presence of bonus + /// tokens throws off the intended calculation for the FLOW inflation rate + /// so they are not included in that calculation + /// Eventually, all the bonus tokens will be destroyed and + /// this will not be needed anymore + pub fun getBonusTokens(): UFix64 { + return self.account.copy(from: /storage/FlowBonusTokenAmount) + ?? 0.0 + } + + init (currentEpochCounter: UInt64, + numViewsInEpoch: UInt64, + numViewsInStakingAuction: UInt64, + numViewsInDKGPhase: UInt64, + numCollectorClusters: UInt16, + FLOWsupplyIncreasePercentage: UFix64, + randomSource: String, + collectorClusters: [FlowClusterQC.Cluster], + clusterQCs: [FlowClusterQC.ClusterQC], + dkgPubKeys: [String]) { + pre { + FlowEpoch.isValidPhaseConfiguration(numViewsInStakingAuction, numViewsInDKGPhase, numViewsInEpoch): + "Invalid startView and endView configuration" + } + + self.configurableMetadata = Config(numViewsInEpoch: numViewsInEpoch, + numViewsInStakingAuction: numViewsInStakingAuction, + numViewsInDKGPhase: numViewsInDKGPhase, + numCollectorClusters: numCollectorClusters, + FLOWsupplyIncreasePercentage: FLOWsupplyIncreasePercentage) + + self.currentEpochCounter = currentEpochCounter + self.currentEpochPhase = EpochPhase.STAKINGAUCTION + self.adminStoragePath = /storage/flowEpochAdmin + self.heartbeatStoragePath = /storage/flowEpochHeartbeat + self.metadataStoragePath = /storage/flowEpochMetadata + + let epochMetadata: {UInt64: EpochMetadata} = {} + self.account.save(epochMetadata, to: self.metadataStoragePath) + + self.account.save(<-create Admin(), to: self.adminStoragePath) + self.account.save(<-create Heartbeat(), to: self.heartbeatStoragePath) + + self.borrowStakingAdmin().startStakingAuction() + + let currentBlock = getCurrentBlock() + + let firstEpochMetadata = EpochMetadata(counter: self.currentEpochCounter, + seed: randomSource, + startView: currentBlock.view, + endView: currentBlock.view + self.configurableMetadata.numViewsInEpoch - (1 as UInt64), + stakingEndView: currentBlock.view + self.configurableMetadata.numViewsInStakingAuction - (1 as UInt64), + totalRewards: FlowIDTableStaking.getEpochTokenPayout(), + collectorClusters: collectorClusters, + clusterQCs: clusterQCs, + dkgKeys: dkgPubKeys) + self.saveEpochMetadata(firstEpochMetadata) + } +} + \ No newline at end of file diff --git a/transactions/update-contract/2023/may-3-rewards/README.md b/transactions/update-contract/2023/may-3-rewards/README.md new file mode 100644 index 00000000..326ff299 --- /dev/null +++ b/transactions/update-contract/2023/may-3-rewards/README.md @@ -0,0 +1,47 @@ +# Update FlowIDTableStaking Contract + +> May 3, 2023 + +Upgrade to the `FlowEpoch` contract as per these pull requests: + +- https://github.com/onflow/flow-core-contracts/pull/352 +- https://github.com/onflow/flow-core-contracts/pull/365 + +These include changes to enable automated staking rewards. + +## Transaction + +[upgrade_and_enable_rewards.cdc](./upgrade_and_enable_rewards.cdc) + +Used this to generate the contract code argument: + +`cat "./FlowEpoch.cdc" | xxd -p | tr -d '\n'` + +Verified using: +``` +$ cat arguments-update-contract-FlowEpoch-mainnet.json | jq '.[1] | .value' | xxd -r -p > /tmp/temp.txt +$ diff /tmp/temp.txt FlowEpoch.cdc +(Should produce no difference) +``` + +For the bonus tokens argument, this is where the number came from: + +- Original - 65M bonus tokens +- ~44.1M+ burned in total so far +- ~20.9M left to be burned +Of which ~9.6M are in the queue to be burned (sitting in genesis wallet - will never go in circulation) +11.1M are left to be brought back to the service account +180,000 were never disbursed (were always in genesis wallet - will never go in circulation) + +## Sequence of signing: + +1. DapperLabs generates the Signature Request ID on the [site]() for the `upgrade_and_enable_rewards.cdc` transaction with the given args. + +2. Signers sign with flow cli specifying the Signature Request ID +`bash multisig.sh -f flow.json ` + +3. [Site](https://flow-multisig-git-service-account-onflow.vercel.app/mainnet) submits the transaction + +## Results + +https://flowscan.org/transaction/ diff --git a/transactions/update-contract/2023/may-3-rewards/arguments-update-contract-FlowEpoch-mainnet.json b/transactions/update-contract/2023/may-3-rewards/arguments-update-contract-FlowEpoch-mainnet.json new file mode 100644 index 00000000..b84437b2 --- /dev/null +++ b/transactions/update-contract/2023/may-3-rewards/arguments-update-contract-FlowEpoch-mainnet.json @@ -0,0 +1,10 @@ +[ + { + "type": "UFix64", + "value": "20896124.2981226" + }, + { + "type": "String", + "value": "696d706f72742046756e6769626c65546f6b656e2066726f6d203078663233336463656538386665306162650a696d706f727420466c6f77546f6b656e2066726f6d203078313635343635333339393034306136310a696d706f727420466c6f7749445461626c655374616b696e672066726f6d203078383632346235326639646463643034610a696d706f727420466c6f77436c757374657251432066726f6d203078383632346235326639646463643034610a696d706f727420466c6f77444b472066726f6d203078383632346235326639646463643034610a696d706f727420466c6f77466565732066726f6d203078663931396565373734343762373439370a0a2f2f2054686520746f702d6c6576656c20736d61727420636f6e7472616374206d616e6167696e6720746865206c6966656379636c65206f662065706f6368732e20496e20466c6f772c0a2f2f2065706f636873206172652074686520736d616c6c65737420756e6974206f662074696d6520776865726520746865206964656e74697479207461626c65202874686520736574206f66200a2f2f206e6574776f726b206f70657261746f727329206973207374617469632e204f70657261746f7273206d6179206f6e6c79206c65617665206f72206a6f696e20746865206e6574776f726b200a2f2f2061742065706f636820626f756e6461726965732e204f70657261746f7273206d617920626520656a656374656420647572696e6720616e2065706f636820666f7220766172696f75730a2f2f206d697364656d65616e6f7572732c2062757420746865792072656d61696e20696e20746865206964656e74697479207461626c6520756e74696c207468652065706f636820656e64732e0a2f2f0a2f2f2045706f636873206172652073706c697420696e746f2033207068617365733a0a2f2f207c3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d0a2f2f207c2045504f4348204e20202020202020202020202020202020202020202020202020202020202020202020207c7c2045504f4348204e2b31202e2e2e0a2f2f207c2d2d2d2d2d205374616b696e67202d2d2d2d2d7c2d205365747570202d7c2d20436f6d6d6974746564202d7c7c202e2e2e0a2f2f207c3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d0a2f2f0a2f2f20312920205354414b494e472050484153450a2f2f204e6f6465206f70657261746f7273206172652061626c6520746f207375626d6974207374616b696e6720726571756573747320666f7220746865204e4558542065706f636820647572696e670a2f2f20746869732070686173652e2041742074686520656e64206f6620746869732070686173652c207468652045706f636820736d61727420636f6e7472616374207265736f6c76657320746865200a2f2f206f75747374616e64696e67207374616b696e6720726571756573747320616e642064657465726d696e657320746865206964656e74697479207461626c6520666f7220746865206e657874200a2f2f2065706f63682e205468652045706f636820736d61727420636f6e747261637420656d697473207468652045706f636853657475702073657276696365206576656e7420636f6e7461696e696e67200a2f2f20746865206964656e74697479207461626c6520666f7220746865206e6578742065706f63682c20776869636820696e6974696174657320746865207472616e736974696f6e20746f20746865200a2f2f2045706f63682053657475702050686173652e0a2f2f0a2f2f2032292053455455502050484153450a2f2f205768656e207468697320706861736520626567696e7320746865207061727469636970616e747320696e20746865206e6578742065706f636820617265207365742e20447572696e6720746869730a2f2f2070686173652c207468657365207061727469636970616e7473207072657061726520666f7220746865206e6578742065706f63682e20496e20706172746963756c61722c20636f6c6c656374696f6e0a2f2f206e6f646573207375626d697420766f74657320666f7220746865697220636c7573746572277320726f6f742071756f72756d20636572746966696361746520616e6420636f6e73656e7375730a2f2f206e6f6465732072756e20746865206469737472696275746564206b65792067656e65726174696f6e2070726f746f636f6c2028444b472920746f20736574207570207468652072616e646f6d0a2f2f20626561636f6e2e205768656e207468657365207072657061726174696f6e732061726520636f6d706c6574652c207468652045706f636820736d61727420636f6e747261637420656d697473207468650a2f2f2045706f6368436f6d6d69742073657276696365206576656e7420636f6e7461696e696e672074686520617274696661637473206f6620746865207365742070726f636573732c2077686963680a2f2f20696e6974696174657320746865207472616e736974696f6e20746f207468652045706f636820436f6d6d69742050686173652e0a2f2f0a2f2f20332920434f4d4d49545445442050484153450a2f2f205768656e207468697320706861736520626567696e732c20746865206e6574776f726b2069732066756c6c7920707265706172656420746f207472616e736974696f6e20746f20746865206e6578740a2f2f2065706f63682e2041206661696c75726520746f20656e7465722074686973207068617365206265666f7265207472616e736974696f6e696e6720746f20746865206e6578742065706f63680a2f2f20696e64696361746573207468617420746865207061727469636970616e747320696e20746865206e6578742065706f6368206661696c656420746f20636f6d706c65746520746865207365742075700a2f2f2070726f6365647572652c207768696368206973206120637269746963616c206661696c75726520616e642077696c6c2063617573652074686520636861696e20746f2068616c742e0a0a70756220636f6e747261637420466c6f7745706f6368207b0a0a2020202070756220656e756d2045706f636850686173653a2055496e7438207b0a20202020202020207075622063617365205354414b494e4741554354494f4e0a202020202020202070756220636173652045504f434853455455500a202020202020202070756220636173652045504f4348434f4d4d49540a202020207d0a0a2020202070756220656e756d204e6f6465526f6c653a2055496e7438207b0a20202020202020207075622063617365204e4f4e450a2020202020202020707562206361736520436f6c6c6563746f720a2020202020202020707562206361736520436f6e73656e7375730a2020202020202020707562206361736520457865637574696f6e0a2020202020202020707562206361736520566572696669636174696f6e0a20202020202020207075622063617365204163636573730a202020207d0a0a202020202f2f2f205468652045706f63682053657475702073657276696365206576656e7420697320656d6974746564207768656e207765207472616e736974696f6e20746f207468652045706f63682053657475700a202020202f2f2f2070686173652e20497420636f6e7461696e73207468652066696e616c697a6564206964656e74697479207461626c6520666f7220746865207570636f6d696e672065706f63682e0a20202020707562206576656e742045706f63685365747570280a20202020202020200a20202020202020202f2f2f2054686520636f756e74657220666f7220746865207570636f6d696e672065706f63682e204d757374206265206f6e652067726561746572207468616e207468650a20202020202020202f2f2f20636f756e74657220666f72207468652063757272656e742065706f63682e0a2020202020202020636f756e7465723a2055496e7436342c0a0a20202020202020202f2f2f204964656e74697479207461626c6520666f7220746865207570636f6d696e672065706f6368207769746820616c6c206e6f646520696e666f726d6174696f6e2e0a20202020202020202f2f2f20496e636c756465733a0a20202020202020202f2f2f206e6f646549442c207374616b696e67206b65792c206e6574776f726b696e67206b65792c206e6574776f726b696e6720616464726573732c20726f6c652c0a20202020202020202f2f2f207374616b696e6720696e666f726d6174696f6e2c207765696768742c20616e64206d6f72652e0a20202020202020206e6f6465496e666f3a205b466c6f7749445461626c655374616b696e672e4e6f6465496e666f5d2c0a0a20202020202020202f2f2f2054686520666972737420766965772028696e636c757369766529206f6620746865207570636f6d696e672065706f63682e0a20202020202020206669727374566965773a2055496e7436342c0a0a20202020202020202f2f2f20546865206c61737420766965772028696e636c757369766529206f6620746865207570636f6d696e672065706f63682e0a202020202020202066696e616c566965773a2055496e7436342c0a0a20202020202020202f2f2f2054686520636c75737465722061737369676e6d656e7420666f7220746865207570636f6d696e672065706f63682e204561636820656c656d656e7420696e20746865206c6973740a20202020202020202f2f2f20726570726573656e7473206f6e6520636c757374657220616e6420636f6e7461696e7320616c6c20746865206e6f6465204944732061737369676e656420746f20746861740a20202020202020202f2f2f20636c75737465722c2077697468207468656972207765696768747320616e6420766f7465730a2020202020202020636f6c6c6563746f72436c7573746572733a205b466c6f77436c757374657251432e436c75737465725d2c0a0a20202020202020202f2f2f2054686520736f75726365206f662072616e646f6d6e65737320746f207365656420746865206c65616465722073656c656374696f6e20616c676f726974686d2077697468200a20202020202020202f2f2f20666f7220746865207570636f6d696e672065706f63682e0a202020202020202072616e646f6d536f757263653a20537472696e672c0a0a20202020202020202f2f2f2054686520646561646c696e6573206f66206561636820706861736520696e2074686520444b472070726f746f636f6c20746f20626520636f6d706c6574656420696e20746865207570636f6d696e670a20202020202020202f2f2f2045706f636853657475702070686173652e20446561646c696e6573206172652073706563696669656420696e207465726d73206f66206120636f6e73656e7375732076696577206e756d6265722e200a20202020202020202f2f2f205768656e206120444b47207061727469636970616e74206f6273657276657320612066696e616c697a656420616e64207365616c656420626c6f636b207769746820766965772067726561746572200a20202020202020202f2f2f207468616e2074686520676976656e20646561646c696e652c2069742063616e20736166656c79207472616e736974696f6e20746f20746865206e6578742070686173652e200a2020202020202020444b4750686173653146696e616c566965773a2055496e7436342c0a2020202020202020444b4750686173653246696e616c566965773a2055496e7436342c0a2020202020202020444b4750686173653346696e616c566965773a2055496e7436340a20202020290a0a202020202f2f2f205468652045706f6368436f6d6d69742073657276696365206576656e7420697320656d6974746564207768656e207765207472616e736974696f6e2066726f6d207468652045706f63680a202020202f2f2f20436f6d6d69747465642070686173652e20497420697320656d6974746564206f6e6c79207768656e20616c6c207072657061726174696f6e20666f7220746865207570636f6d696e672065706f63680a202020202f2f2f20686173206265656e20636f6d706c657465640a20202020707562206576656e742045706f6368436f6d6d6974280a0a20202020202020202f2f2f2054686520636f756e74657220666f7220746865207570636f6d696e672065706f63682e204d75737420626520657175616c20746f2074686520636f756e74657220696e207468650a20202020202020202f2f2f2070726576696f75732045706f63685365747570206576656e742e0a2020202020202020636f756e7465723a2055496e7436342c0a0a20202020202020202f2f2f2054686520726573756c74206f6620746865205143206167677265676174696f6e2070726f636573732e204561636820656c656d656e7420636f6e7461696e73200a20202020202020202f2f2f20616c6c20746865206e6f64657320616e6420766f74657320726563656976656420666f72206120706172746963756c617220636c75737465720a20202020202020202f2f2f205143207374616e647320666f722071756f72756d2063657274696669636174652074686174206561636820636c75737465722067656e6572617465732e0a2020202020202020636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d2c0a0a20202020202020202f2f2f2054686520726573756c74696e67207075626c6963206b6579732066726f6d2074686520444b472070726f636573732c20656e636f6465642061732062792074686520666c6f772d676f0a20202020202020202f2f2f2063727970746f206c6962726172792c207468656e206865782d656e636f6465642e0a20202020202020202f2f2f2047726f7570207075626c6963206b65792069732074686520666972737420656c656d656e742c20666f6c6c6f7765642062792074686520696e646976696475616c206b6579730a2020202020202020646b675075624b6579733a205b537472696e675d2c0a20202020290a0a202020202f2f2f20436f6e7461696e73207370656369666963206d657461646174612061626f7574206120706172746963756c61722065706f63680a202020202f2f2f20416c6c20686973746f726963616c2065706f6368206d657461646174612069732073746f726564207065726d616e656e746c790a20202020707562207374727563742045706f63684d65746164617461207b0a0a20202020202020202f2f2f20546865206964656e74696669657220666f72207468652065706f63680a2020202020202020707562206c657420636f756e7465723a2055496e7436340a0a20202020202020202f2f2f205468652073656564207573656420666f722067656e65726174696e67207468652065706f63682073657475700a2020202020202020707562206c657420736565643a20537472696e670a0a20202020202020202f2f2f205468652066697273742076696577206f6620746869732065706f63680a2020202020202020707562206c6574207374617274566965773a2055496e7436340a0a20202020202020202f2f2f20546865206c6173742076696577206f6620746869732065706f63680a2020202020202020707562206c657420656e64566965773a2055496e7436340a0a20202020202020202f2f2f20546865206c6173742076696577206f6620746865207374616b696e672061756374696f6e0a2020202020202020707562206c6574207374616b696e67456e64566965773a2055496e7436340a0a20202020202020202f2f2f2054686520746f74616c20726577617264732074686174206172652070616964206f757420666f72207468652065706f63680a20202020202020207075622076617220746f74616c526577617264733a205546697836340a0a20202020202020202f2f2f205468652072657761726420616d6f756e7473207468617420617265207061696420746f206561636820696e646976696475616c206e6f646520616e64206974732064656c656761746f72730a20202020202020207075622076617220726577617264416d6f756e74733a205b466c6f7749445461626c655374616b696e672e52657761726473427265616b646f776e5d0a0a20202020202020202f2f2f20547261636b7320696620726577617264732068617665206265656e207061696420666f7220746869732065706f63680a2020202020202020707562207661722072657761726473506169643a20426f6f6c0a0a20202020202020202f2f2f20546865206f7267616e697a6174696f6e206f6620636f6c6c6563746f72206e6f64652049447320696e746f20636c7573746572730a20202020202020202f2f2f2064657465726d696e6564206279206120726f756e6420726f62696e20736f7274696e6720616c676f726974686d0a2020202020202020707562206c657420636f6c6c6563746f72436c7573746572733a205b466c6f77436c757374657251432e436c75737465725d0a0a20202020202020202f2f2f205468652051756f72756d204365727469666963617465732066726f6d2074686520436c7573746572514320636f6e74726163740a20202020202020207075622076617220636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d0a0a20202020202020202f2f2f20546865207075626c6963206b657973206173736f636961746564207769746820746865204469737472696275746564204b65792047656e65726174696f6e0a20202020202020202f2f2f2070726f63657373207468617420636f6e73656e737573206e6f64657320706172746963697061746520696e0a20202020202020202f2f2f2047726f7570206b657920697320746865206c61737420656c656d656e7420617420696e6465783a206c656e677468202d20310a20202020202020207075622076617220646b674b6579733a205b537472696e675d0a0a2020202020202020696e697428636f756e7465723a2055496e7436342c0a20202020202020202020202020736565643a20537472696e672c0a202020202020202020202020207374617274566965773a2055496e7436342c0a20202020202020202020202020656e64566965773a2055496e7436342c0a202020202020202020202020207374616b696e67456e64566965773a2055496e7436342c0a20202020202020202020202020746f74616c526577617264733a205546697836342c0a20202020202020202020202020636f6c6c6563746f72436c7573746572733a205b466c6f77436c757374657251432e436c75737465725d2c0a20202020202020202020202020636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d2c0a20202020202020202020202020646b674b6579733a205b537472696e675d29207b0a0a20202020202020202020202073656c662e636f756e746572203d20636f756e7465720a20202020202020202020202073656c662e73656564203d20736565640a20202020202020202020202073656c662e737461727456696577203d207374617274566965770a20202020202020202020202073656c662e656e6456696577203d20656e64566965770a20202020202020202020202073656c662e7374616b696e67456e6456696577203d207374616b696e67456e64566965770a20202020202020202020202073656c662e746f74616c52657761726473203d20746f74616c526577617264730a20202020202020202020202073656c662e726577617264416d6f756e7473203d205b5d0a20202020202020202020202073656c662e7265776172647350616964203d2066616c73650a20202020202020202020202073656c662e636f6c6c6563746f72436c757374657273203d20636f6c6c6563746f72436c7573746572730a20202020202020202020202073656c662e636c7573746572514373203d20636c75737465725143730a20202020202020202020202073656c662e646b674b657973203d20646b674b6579730a20202020202020207d0a0a2020202020202020616363657373286163636f756e74292066756e20736574546f74616c52657761726473285f206e6577526577617264733a2055466978363429207b0a20202020202020202020202073656c662e746f74616c52657761726473203d206e6577526577617264730a20202020202020207d0a0a2020202020202020616363657373286163636f756e74292066756e20736574526577617264416d6f756e7473285f20726577617264427265616b646f776e3a205b466c6f7749445461626c655374616b696e672e52657761726473427265616b646f776e5d29207b0a20202020202020202020202073656c662e726577617264416d6f756e7473203d20726577617264427265616b646f776e0a20202020202020207d0a0a2020202020202020616363657373286163636f756e74292066756e207365745265776172647350616964285f2072657761726473506169643a20426f6f6c29207b0a20202020202020202020202073656c662e7265776172647350616964203d2072657761726473506169640a20202020202020207d200a0a2020202020202020616363657373286163636f756e74292066756e20736574436c7573746572514373287163733a205b466c6f77436c757374657251432e436c757374657251435d29207b0a20202020202020202020202073656c662e636c7573746572514373203d207163730a20202020202020207d0a0a2020202020202020616363657373286163636f756e74292066756e20736574444b4747726f75704b6579286b6579733a205b537472696e675d29207b0a20202020202020202020202073656c662e646b674b657973203d206b6579730a20202020202020207d0a202020207d0a0a202020202f2f2f204d657461646174612074686174206973206d616e6167656420616e642063616e206265206368616e676564206279207468652041646d696e2f2f2f0a202020207075622073747275637420436f6e666967207b0a20202020202020202f2f2f20546865206e756d626572206f6620766965777320696e20616e20656e746972652065706f63680a2020202020202020707562287365742920766172206e756d5669657773496e45706f63683a2055496e7436340a0a20202020202020202f2f2f20546865206e756d626572206f6620766965777320696e20746865207374616b696e672061756374696f6e0a2020202020202020707562287365742920766172206e756d5669657773496e5374616b696e6741756374696f6e3a2055496e7436340a20202020202020200a20202020202020202f2f2f20546865206e756d626572206f6620766965777320696e206561636820646b672070686173650a2020202020202020707562287365742920766172206e756d5669657773496e444b4750686173653a2055496e7436340a0a20202020202020202f2f2f20546865206e756d626572206f6620636f6c6c6563746f7220636c75737465727320696e20656163682065706f63680a2020202020202020707562287365742920766172206e756d436f6c6c6563746f72436c7573746572733a2055496e7431360a0a20202020202020202f2f2f20547261636b73207468652072617465206174207768696368207468652072657761726473207061796f757420696e637265617365732065766572792065706f63680a20202020202020202f2f2f20546869732076616c7565206973206d756c7469706c6965642062792074686520464c4f5720746f74616c20737570706c7920746f2067657420746865206e657874207061796f75740a202020202020202070756228736574292076617220464c4f57737570706c79496e63726561736550657263656e746167653a205546697836340a0a2020202020202020696e6974286e756d5669657773496e45706f63683a2055496e7436342c206e756d5669657773496e5374616b696e6741756374696f6e3a2055496e7436342c206e756d5669657773496e444b4750686173653a2055496e7436342c206e756d436f6c6c6563746f72436c7573746572733a2055496e7431362c20464c4f57737570706c79496e63726561736550657263656e746167653a2055466978363429207b0a20202020202020202020202073656c662e6e756d5669657773496e45706f6368203d206e756d5669657773496e45706f63680a20202020202020202020202073656c662e6e756d5669657773496e5374616b696e6741756374696f6e203d206e756d5669657773496e5374616b696e6741756374696f6e0a20202020202020202020202073656c662e6e756d5669657773496e444b475068617365203d206e756d5669657773496e444b4750686173650a20202020202020202020202073656c662e6e756d436f6c6c6563746f72436c757374657273203d206e756d436f6c6c6563746f72436c7573746572730a20202020202020202020202073656c662e464c4f57737570706c79496e63726561736550657263656e74616765203d20464c4f57737570706c79496e63726561736550657263656e746167650a20202020202020207d0a202020207d0a0a202020202f2f2f20486f6c6473207468652060466c6f7745706f63682e436f6e666967602073747275637420776974682074686520636f6e666967757261626c65206d657461646174610a2020202061636365737328636f6e747261637429206c657420636f6e666967757261626c654d657461646174613a20436f6e6669670a0a202020202f2f2f204d657461646174612074686174206973206d616e616765642062792074686520736d61727420636f6e74726163740a202020202f2f2f20616e642063616e6e6f74206265206368616e676564206279207468652041646d696e0a0a202020202f2f2f20436f6e7461696e73206120686973746f726963616c207265636f7264206f6620746865206d657461646174612066726f6d20616c6c2070726576696f75732065706f6368730a202020202f2f2f20696e64657865642062792065706f6368206e756d6265720a0a202020202f2f2f2052657475726e7320746865206d657461646174612066726f6d20746865207370656369666965642065706f63680a202020202f2f2f206f72206e696c2069662069742069736e277420666f756e640a202020202f2f2f2045706f6368204d657461646174612069732073746f72656420696e206163636f756e742073746f7261676520736f207468652067726f77696e672064696374696f6e6172790a202020202f2f2f20646f6573206e6f74206861766520746f206265206c6f616465642065766572792074696d652074686520636f6e7472616374206973206c6f616465640a202020207075622066756e2067657445706f63684d65746164617461285f2065706f6368436f756e7465723a2055496e743634293a2045706f63684d657461646174613f207b0a20202020202020206966206c6574206d6574616461746144696374696f6e617279203d2073656c662e6163636f756e742e626f72726f773c267b55496e7436343a2045706f63684d657461646174617d3e2866726f6d3a2073656c662e6d6574616461746153746f726167655061746829207b0a20202020202020202020202072657475726e206d6574616461746144696374696f6e6172795b65706f6368436f756e7465725d0a20202020202020207d0a202020202020202072657475726e206e696c0a202020207d0a0a202020202f2f2f2053617665732061206d6f6469666965642045706f63684d657461646174612073747275637420746f20746865206d6574616461746120696e206163636f756e742073746f726167650a202020202f2f2f200a2020202061636365737328636f6e7472616374292066756e207361766545706f63684d65746164617461285f206e65774d657461646174613a2045706f63684d6574616461746129207b0a2020202020202020707265207b0a20202020202020202020202073656c662e63757272656e7445706f6368436f756e746572203d3d2028302061732055496e74363429207c7c0a202020202020202020202020286e65774d657461646174612e636f756e746572203e3d2073656c662e63757272656e7445706f6368436f756e746572202d2028312061732055496e743634292026260a2020202020202020202020206e65774d657461646174612e636f756e746572203c3d2073656c662e70726f706f73656445706f6368436f756e7465722829293a0a202020202020202020202020202020202243616e6e6f74206d6f646966792065706f6368206d657461646174612066726f6d2065706f636873206166746572207468652070726f706f7365642065706f6368206f72206265666f7265207468652070726576696f75732065706f6368220a20202020202020207d0a20202020202020206966206c6574206d6574616461746144696374696f6e617279203d2073656c662e6163636f756e742e626f72726f773c267b55496e7436343a2045706f63684d657461646174617d3e2866726f6d3a2073656c662e6d6574616461746153746f726167655061746829207b0a2020202020202020202020206966206c6574206d65746164617461203d206d6574616461746144696374696f6e6172795b6e65774d657461646174612e636f756e7465725d207b0a2020202020202020202020202020202061737365727420280a20202020202020202020202020202020202020206d657461646174612e636f756e746572203d3d206e65774d657461646174612e636f756e7465722c0a20202020202020202020202020202020202020206d6573736167653a202243616e6e6f742073617665206d657461646174612077697468206d69736d61746368696e672065706f636820636f756e74657273220a20202020202020202020202020202020290a2020202020202020202020207d0a2020202020202020202020206d6574616461746144696374696f6e6172795b6e65774d657461646174612e636f756e7465725d203d206e65774d657461646174610a20202020202020207d0a202020207d0a0a202020202f2f2f2054686520636f756e7465722c206f722049442c206f66207468652063757272656e742065706f63680a20202020707562207661722063757272656e7445706f6368436f756e7465723a2055496e7436340a0a202020202f2f2f205468652063757272656e742070686173652074686174207468652065706f636820697320696e0a20202020707562207661722063757272656e7445706f636850686173653a2045706f636850686173650a0a202020202f2f2f2050617468207768657265207468652060466c6f7745706f63682e41646d696e60207265736f757263652069732073746f7265640a20202020707562206c65742061646d696e53746f72616765506174683a2053746f72616765506174680a0a202020202f2f2f2050617468207768657265207468652060466c6f7745706f63682e48656172746265617460207265736f757263652069732073746f7265640a20202020707562206c65742068656172746265617453746f72616765506174683a2053746f72616765506174680a0a202020202f2f2f20506174682077686572652074686520607b55496e7436343a2045706f63684d657461646174617d602064696374696f6e6172792069732073746f7265640a20202020707562206c6574206d6574616461746153746f72616765506174683a2053746f72616765506174680a0a202020202f2f2f205265736f7572636520746861742063616e2075706461746520736f6d65206f662074686520636f6e7472616374206669656c64730a20202020707562207265736f757263652041646d696e207b0a20202020202020207075622066756e2075706461746545706f63685669657773285f206e657745706f636856696577733a2055496e74363429207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920757064617465206669656c647320647572696e6720746865207374616b696e672061756374696f6e220a20202020202020202020202020202020466c6f7745706f63682e697356616c69645068617365436f6e66696775726174696f6e28466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e2c0a2020202020202020202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b4750686173652c0a20202020202020202020202020202020202020206e657745706f63685669657773293a20224e65772045706f6368205669657773206d7573742062652067726561746572207468616e207468652073756d206f66207374616b696e6720616e6420444b47205068617365207669657773220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e45706f6368203d206e657745706f636856696577730a20202020202020207d0a0a20202020202020207075622066756e2075706461746541756374696f6e5669657773285f206e657741756374696f6e56696577733a2055496e74363429207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920757064617465206669656c647320647572696e6720746865207374616b696e672061756374696f6e220a20202020202020202020202020202020466c6f7745706f63682e697356616c69645068617365436f6e66696775726174696f6e286e657741756374696f6e56696577732c0a2020202020202020202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b4750686173652c0a2020202020202020202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e45706f6368293a202245706f6368205669657773206d7573742062652067726561746572207468616e207468652073756d206f66206e6577207374616b696e6720616e6420444b47205068617365207669657773220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e203d206e657741756374696f6e56696577730a20202020202020207d0a0a20202020202020207075622066756e20757064617465444b4750686173655669657773285f206e6577506861736556696577733a2055496e74363429207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920757064617465206669656c647320647572696e6720746865207374616b696e672061756374696f6e220a20202020202020202020202020202020466c6f7745706f63682e697356616c69645068617365436f6e66696775726174696f6e28466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e2c0a20202020202020202020202020202020202020206e6577506861736556696577732c0a2020202020202020202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e45706f6368293a202245706f6368205669657773206d7573742062652067726561746572207468616e207468652073756d206f66207374616b696e6720616e64206e657720444b47205068617365207669657773220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b475068617365203d206e6577506861736556696577730a20202020202020207d0a0a20202020202020207075622066756e207570646174654e756d436f6c6c6563746f72436c757374657273285f206e65774e756d436c7573746572733a2055496e74313629207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920757064617465206669656c647320647572696e6720746865207374616b696e672061756374696f6e220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d436f6c6c6563746f72436c757374657273203d206e65774e756d436c7573746572730a20202020202020207d0a0a20202020202020207075622066756e20757064617465464c4f57537570706c79496e63726561736550657263656e74616765285f206e657750657263656e746167653a2055466978363429207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920757064617465206669656c647320647572696e6720746865207374616b696e672061756374696f6e220a202020202020202020202020202020206e657750657263656e74616765203c3d20312e30206173205546697836343a20224e65772076616c7565206d757374206265206265747765656e207a65726f20616e64206f6e65220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e636f6e666967757261626c654d657461646174612e464c4f57737570706c79496e63726561736550657263656e74616765203d206e657750657263656e746167650a20202020202020207d0a0a20202020202020202f2f20456e61626c65206f722064697361626c65206175746f6d6174696320726577617264732063616c63756c6174696f6e7320616e64207061796d656e74730a20202020202020207075622066756e207570646174654175746f6d6174696352657761726473456e61626c6564285f20656e61626c65643a20426f6f6c29207b0a202020202020202020202020466c6f7745706f63682e6163636f756e742e6c6f61643c426f6f6c3e2866726f6d3a202f73746f726167652f666c6f774175746f6d6174696352657761726473456e61626c6564290a202020202020202020202020466c6f7745706f63682e6163636f756e742e7361766528656e61626c65642c20746f3a202f73746f726167652f666c6f774175746f6d6174696352657761726473456e61626c6564290a20202020202020207d0a202020207d0a0a202020202f2f2f205265736f75726365207468617420697320636f6e74726f6c6c6564206279207468652070726f746f636f6c20616e6420697320757365640a202020202f2f2f20746f206368616e6765207468652063757272656e74207068617365206f66207468652065706f6368206f72207265736574207468652065706f6368206966206e65656465640a202020202f2f2f200a20202020707562207265736f7572636520486561727462656174207b0a0a20202020202020202f2f2f2046756e6374696f6e20746861742069732063616c6c656420657665727920626c6f636b20746f20616476616e6365207468652065706f63680a20202020202020202f2f2f20616e64206368616e67652070686173652069662074686520726571756972656420636f6e646974696f6e732068617665206265656e206d65740a20202020202020207075622066756e20616476616e6365426c6f636b2829207b0a0a20202020202020202020202073776974636820466c6f7745706f63682e63757272656e7445706f63685068617365207b0a20202020202020202020202020202020636173652045706f636850686173652e5354414b494e4741554354494f4e3a0a20202020202020202020202020202020202020206c65742063757272656e74426c6f636b203d2067657443757272656e74426c6f636b28290a20202020202020202020202020202020202020206c65742063757272656e7445706f63684d65746164617461203d20466c6f7745706f63682e67657445706f63684d6574616461746128466c6f7745706f63682e63757272656e7445706f6368436f756e74657229210a20202020202020202020202020202020202020202f2f205061792072657761726473206f6e6c79206966206175746f6d6174696320726577617264732061726520656e61626c65640a20202020202020202020202020202020202020202f2f20546869732077696c6c206f6e6c792061637475616c6c792068617070656e206f6e636520696d6d6564696174656c79206166746572207468652065706f636820626567696e730a20202020202020202020202020202020202020202f2f2062656361757365206070617952657761726473466f7250726576696f757345706f63682829602077696c6c206f6e6c79207061792072657761726473206f6e63650a2020202020202020202020202020202020202020696620466c6f7745706f63682e6175746f6d6174696352657761726473456e61626c65642829207b0a20202020202020202020202020202020202020202020202073656c662e70617952657761726473466f7250726576696f757345706f636828290a20202020202020202020202020202020202020207d0a202020202020202020202020202020202020202069662063757272656e74426c6f636b2e76696577203e3d2063757272656e7445706f63684d657461646174612e7374616b696e67456e6456696577207b0a20202020202020202020202020202020202020202020202073656c662e656e645374616b696e6741756374696f6e28290a20202020202020202020202020202020202020207d0a20202020202020202020202020202020636173652045706f636850686173652e45504f434853455455503a0a2020202020202020202020202020202020202020696620466c6f77436c757374657251432e766f74696e67436f6d706c6574656428292026262028466c6f77444b472e646b67436f6d706c65746564282920213d206e696c29207b0a20202020202020202020202020202020202020202020202073656c662e737461727445706f6368436f6d6d697428290a20202020202020202020202020202020202020207d0a20202020202020202020202020202020636173652045706f636850686173652e45504f4348434f4d4d49543a0a20202020202020202020202020202020202020206c65742063757272656e74426c6f636b203d2067657443757272656e74426c6f636b28290a20202020202020202020202020202020202020206c65742063757272656e7445706f63684d65746164617461203d20466c6f7745706f63682e67657445706f63684d6574616461746128466c6f7745706f63682e63757272656e7445706f6368436f756e74657229210a202020202020202020202020202020202020202069662063757272656e74426c6f636b2e76696577203e3d2063757272656e7445706f63684d657461646174612e656e6456696577207b0a20202020202020202020202020202020202020202020202073656c662e63616c63756c617465416e645365745265776172647328290a20202020202020202020202020202020202020202020202073656c662e656e6445706f636828290a20202020202020202020202020202020202020207d0a2020202020202020202020202020202064656661756c743a0a202020202020202020202020202020202020202072657475726e0a2020202020202020202020207d0a20202020202020207d0a0a20202020202020202f2f2f2043616c6c732060466c6f7745706f6368602066756e6374696f6e7320746f20656e6420746865207374616b696e672061756374696f6e2070686173650a20202020202020202f2f2f20616e64207374617274207468652045706f63682053657475702070686173650a20202020202020207075622066756e20656e645374616b696e6741756374696f6e2829207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e3a202243616e206f6e6c7920656e64207374616b696e672061756374696f6e20647572696e6720746865207374616b696e672061756374696f6e220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e656e645374616b696e6741756374696f6e28290a0a202020202020202020202020466c6f7745706f63682e737461727445706f636853657475702872616e646f6d536f757263653a20756e7361666552616e646f6d28292e746f537472696e672829290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c732060466c6f7745706f6368602066756e6374696f6e7320746f20656e64207468652045706f63682053657475702070686173650a20202020202020202f2f2f20616e64207374617274207468652045706f63682053657475702050686173650a20202020202020207075622066756e20737461727445706f6368436f6d6d69742829207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e45504f434853455455503a202243616e206f6e6c7920656e642045706f636820536574757020647572696e672045706f6368205365747570220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e737461727445706f6368436f6d6d697428290a20202020202020207d0a0a20202020202020202f2f2f2043616c6c732060466c6f7745706f6368602066756e6374696f6e7320746f20656e64207468652045706f636820436f6d6d69742070686173650a20202020202020202f2f2f20616e6420737461727420746865205374616b696e672041756374696f6e207068617365206f662061206e65772065706f63680a20202020202020207075622066756e20656e6445706f63682829207b0a202020202020202020202020707265207b0a20202020202020202020202020202020466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e45504f4348434f4d4d49543a202243616e206f6e6c7920656e642065706f636820647572696e672045706f636820436f6d6d6974220a2020202020202020202020207d0a0a202020202020202020202020466c6f7745706f63682e73746172744e657745706f636828290a20202020202020207d0a0a20202020202020202f2f2f204e6565647320746f2062652063616c6c6564206265666f7265207468652065706f6368206973206f7665720a20202020202020202f2f2f2043616c63756c61746573207265776172647320666f72207468652063757272656e742065706f636820616e642073746f726573207468656d20696e2065706f6368206d657461646174610a20202020202020207075622066756e2063616c63756c617465416e64536574526577617264732829207b0a202020202020202020202020466c6f7745706f63682e63616c63756c617465416e645365745265776172647328290a20202020202020207d0a0a20202020202020207075622066756e2070617952657761726473466f7250726576696f757345706f63682829207b0a202020202020202020202020466c6f7745706f63682e70617952657761726473466f7250726576696f757345706f636828290a20202020202020207d0a0a20202020202020202f2f2f2050726f746f636f6c2063616e20757365207468697320746f207265626f6f74207468652065706f636820776974682061206e65772067656e657369730a20202020202020202f2f2f20696e2063617365207468652065706f636820736574757020706861736520646964206e6f7420636f6d706c6574652070726f7065726c790a20202020202020202f2f2f206265666f72652074686520656e64206f6620616e2065706f63680a20202020202020207075622066756e20726573657445706f6368280a20202020202020202020202063757272656e7445706f6368436f756e7465723a2055496e7436342c0a20202020202020202020202072616e646f6d536f757263653a20537472696e672c0a2020202020202020202020207374617274566965773a2055496e7436342c0a2020202020202020202020207374616b696e67456e64566965773a2055496e7436342c0a202020202020202020202020656e64566965773a2055496e7436342c0a202020202020202020202020636f6c6c6563746f72436c7573746572733a205b466c6f77436c757374657251432e436c75737465725d2c0a202020202020202020202020636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d2c0a202020202020202020202020646b675075624b6579733a205b537472696e675d290a20202020202020207b0a202020202020202020202020707265207b0a2020202020202020202020202020202063757272656e7445706f6368436f756e746572203d3d20466c6f7745706f63682e63757272656e7445706f6368436f756e7465723a0a20202020202020202020202020202020202020202243616e6e6f74207375626d697420612063757272656e742045706f636820636f756e746572207468617420646f6573206e6f74206d61746368207468652063757272656e7420636f756e7465722073746f72656420696e2074686520736d61727420636f6e7472616374220a20202020202020202020202020202020466c6f7745706f63682e697356616c69645068617365436f6e66696775726174696f6e287374616b696e67456e64566965772d7374617274566965772b312c20466c6f7745706f63682e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b4750686173652c20656e64566965772d7374617274566965772b31293a0a202020202020202020202020202020202020202022496e76616c6964207374617274566965772c207374616b696e67456e64566965772c20616e6420656e645669657720636f6e66696775726174696f6e220a2020202020202020202020207d0a0a202020202020202020202020696620466c6f7745706f63682e63757272656e7445706f63685068617365203d3d2045706f636850686173652e5354414b494e4741554354494f4e207b0a202020202020202020202020202020202f2f2053696e63652077652061726520726573657474696e67207468652065706f63682c20776520646f206e6f74206e65656420746f0a202020202020202020202020202020202f2f2073746172742065706f636820736574757020616c736f2e205765206f6e6c79206e65656420746f20656e6420746865207374616b696e672061756374696f6e0a20202020202020202020202020202020466c6f7745706f63682e626f72726f775374616b696e6741646d696e28292e656e645374616b696e6741756374696f6e28290a2020202020202020202020207d20656c7365207b0a202020202020202020202020202020202f2f20666f7263652072657365742074686520514320616e6420444b470a20202020202020202020202020202020466c6f7745706f63682e626f72726f77436c7573746572514341646d696e28292e666f72636553746f70566f74696e6728290a20202020202020202020202020202020466c6f7745706f63682e626f72726f77444b4741646d696e28292e666f726365456e64444b4728290a2020202020202020202020207d0a0a2020202020202020202020202f2f20437265617465206e65772045706f6368206d6574616461746120666f7220746865206e6578742065706f63680a2020202020202020202020202f2f207769746820746865206e65772076616c7565730a2020202020202020202020206c6574206e657745706f63684d65746164617461203d2045706f63684d65746164617461280a2020202020202020202020202020202020202020636f756e7465723a2063757272656e7445706f6368436f756e746572202b20312c0a2020202020202020202020202020202020202020736565643a2072616e646f6d536f757263652c0a20202020202020202020202020202020202020207374617274566965773a207374617274566965772c0a2020202020202020202020202020202020202020656e64566965773a20656e64566965772c0a20202020202020202020202020202020202020207374616b696e67456e64566965773a207374616b696e67456e64566965772c0a20202020202020202020202020202020202020202f2f20546869732077696c6c206265206f7665727772697474656e20696e206063616c63756c617465416e6453657452657761726473602062656c6f770a2020202020202020202020202020202020202020746f74616c526577617264733a2055466978363428302e30292c0a2020202020202020202020202020202020202020636f6c6c6563746f72436c7573746572733a20636f6c6c6563746f72436c7573746572732c0a2020202020202020202020202020202020202020636c75737465725143733a20636c75737465725143732c0a2020202020202020202020202020202020202020646b674b6579733a20646b675075624b657973290a0a202020202020202020202020466c6f7745706f63682e7361766545706f63684d65746164617461286e657745706f63684d65746164617461290a0a2020202020202020202020202f2f2043616c63756c617465207265776172647320666f72207468652063757272656e742065706f63680a2020202020202020202020202f2f20616e642073657420746865207061796f757420666f7220746865206e6578742065706f63680a20202020202020202020202073656c662e63616c63756c617465416e645365745265776172647328290a0a2020202020202020202020202f2f2053746172742061206e65772045706f63682c20776869636820696e6372656d656e7473207468652063757272656e742065706f636820636f756e7465720a202020202020202020202020466c6f7745706f63682e73746172744e657745706f636828290a20202020202020207d0a202020207d0a0a202020202f2f2f2043616c63756c617465732061206e657720746f6b656e207061796f757420666f72207468652063757272656e742065706f63680a202020202f2f2f20616e64207365747320746865206e6577207061796f757420666f7220746865206e6578742065706f63680a20202020616363657373286163636f756e74292066756e2063616c63756c617465416e64536574526577617264732829207b0a0a20202020202020206c6574207374616b696e6741646d696e203d2073656c662e626f72726f775374616b696e6741646d696e28290a0a20202020202020202f2f2043616c63756c617465207265776172647320666f72207468652063757272656e742065706f636820746861742069732061626f757420746f20656e640a20202020202020202f2f20616e64207361766520746861742072657761726420627265616b646f776e20696e207468652065706f6368206d6574616461746120666f72207468652063757272656e742065706f63680a20202020202020206c6574207265776172647353756d6d617279203d207374616b696e6741646d696e2e63616c63756c6174655265776172647328290a20202020202020206c65742063757272656e744d65746164617461203d2073656c662e67657445706f63684d657461646174612873656c662e63757272656e7445706f6368436f756e74657229210a202020202020202063757272656e744d657461646174612e736574526577617264416d6f756e7473287265776172647353756d6d6172792e627265616b646f776e290a202020202020202063757272656e744d657461646174612e736574546f74616c52657761726473287265776172647353756d6d6172792e746f74616c52657761726473290a202020202020202073656c662e7361766545706f63684d657461646174612863757272656e744d65746164617461290a0a2020202020202020696620466c6f7745706f63682e6175746f6d6174696352657761726473456e61626c65642829207b0a2020202020202020202020202f2f2043616c63756c6174652074686520746f74616c20737570706c79206f6620464c4f57206166746572207468652063757272656e742065706f63682773207061796f75740a2020202020202020202020202f2f207468652063616c63756c6174696f6e20696e636c756465732074686520746f6b656e73207468617420686176656e2774206265656e206d696e74656420666f72207468652063757272656e742065706f6368207965740a2020202020202020202020206c65742063757272656e745061796f7574203d20466c6f7749445461626c655374616b696e672e67657445706f6368546f6b656e5061796f757428290a2020202020202020202020206c657420666565416d6f756e74203d20466c6f77466565732e67657446656542616c616e636528290a20202020202020202020202076617220666c6f77546f74616c537570706c7941667465725061796f7574203d20302e300a202020202020202020202020696620666565416d6f756e74203e3d2063757272656e745061796f7574207b0a20202020202020202020202020202020666c6f77546f74616c537570706c7941667465725061796f7574203d20466c6f77546f6b656e2e746f74616c537570706c790a2020202020202020202020207d20656c7365207b0a20202020202020202020202020202020666c6f77546f74616c537570706c7941667465725061796f7574203d20466c6f77546f6b656e2e746f74616c537570706c79202b202863757272656e745061796f7574202d20666565416d6f756e74290a2020202020202020202020207d0a0a2020202020202020202020202f2f204c6f61642074686520616d6f756e74206f6620626f6e757320746f6b656e732066726f6d2073746f726167650a2020202020202020202020206c657420626f6e7573546f6b656e73203d20466c6f7745706f63682e676574426f6e7573546f6b656e7328290a0a2020202020202020202020202f2f20537562747261637420626f6e757320746f6b656e732066726f6d2074686520746f74616c20737570706c7920746f2067657420746865207265616c20737570706c790a202020202020202020202020696620626f6e7573546f6b656e73203c20666c6f77546f74616c537570706c7941667465725061796f7574207b0a20202020202020202020202020202020666c6f77546f74616c537570706c7941667465725061796f7574203d20666c6f77546f74616c537570706c7941667465725061796f7574202d20626f6e7573546f6b656e730a2020202020202020202020207d0a0a2020202020202020202020202f2f2043616c63756c61746520746865207061796f757420666f7220746865206e6578742065706f63680a2020202020202020202020206c65742070726f706f7365645061796f7574203d20666c6f77546f74616c537570706c7941667465725061796f7574202a20466c6f7745706f63682e636f6e666967757261626c654d657461646174612e464c4f57737570706c79496e63726561736550657263656e746167650a0a2020202020202020202020202f2f2053657420746865206e6577207061796f757420696e20746865207374616b696e6720636f6e747261637420616e642070726f706f7365642045706f6368204d657461646174610a20202020202020202020202073656c662e626f72726f775374616b696e6741646d696e28292e73657445706f6368546f6b656e5061796f75742870726f706f7365645061796f7574290a2020202020202020202020206c65742070726f706f7365644d65746164617461203d2073656c662e67657445706f63684d657461646174612873656c662e70726f706f73656445706f6368436f756e7465722829290a202020202020202020202020202020203f3f2070616e6963282243616e6e6f7420736574207265776172647320666f7220746865206e6578742065706f63682062656375617365206974206861736e2774206265656e2070726f706f7365642079657422290a20202020202020202020202070726f706f7365644d657461646174612e736574546f74616c526577617264732870726f706f7365645061796f7574290a20202020202020202020202073656c662e7361766545706f63684d657461646174612870726f706f7365644d65746164617461290a20202020202020207d0a202020207d0a0a202020202f2f2f2050617973207265776172647320746f20746865206e6f64657320616e642064656c656761746f7273206f66207468652070726576696f75732065706f63680a20202020616363657373286163636f756e74292066756e2070617952657761726473466f7250726576696f757345706f63682829207b0a20202020202020206966206c65742070726576696f757345706f63684d65746164617461203d2073656c662e67657445706f63684d657461646174612873656c662e63757272656e7445706f6368436f756e746572202d2028312061732055496e7436342929207b0a2020202020202020202020206966202170726576696f757345706f63684d657461646174612e7265776172647350616964207b0a202020202020202020202020202020206c65742073756d6d617279203d20466c6f7749445461626c655374616b696e672e45706f63685265776172647353756d6d61727928746f74616c526577617264733a2070726576696f757345706f63684d657461646174612e746f74616c526577617264732c20627265616b646f776e3a2070726576696f757345706f63684d657461646174612e726577617264416d6f756e7473290a2020202020202020202020202020202073656c662e626f72726f775374616b696e6741646d696e28292e706179526577617264732873756d6d617279290a2020202020202020202020202020202070726576696f757345706f63684d657461646174612e73657452657761726473506169642874727565290a2020202020202020202020202020202073656c662e7361766545706f63684d657461646174612870726576696f757345706f63684d65746164617461290a2020202020202020202020207d0a20202020202020207d0a202020207d0a0a202020202f2f2f204d6f766573207374616b696e6720746f6b656e73206265747765656e206275636b6574732c0a202020202f2f2f20616e642073746172747320746865206e65772065706f6368207374616b696e672061756374696f6e0a20202020616363657373286163636f756e74292066756e2073746172744e657745706f63682829207b0a0a20202020202020202f2f20456e6420514320616e6420444b47206966207468657920617265207374696c6c20656e61626c65640a2020202020202020696620466c6f77436c757374657251432e696e50726f6772657373207b0a20202020202020202020202073656c662e626f72726f77436c7573746572514341646d696e28292e73746f70566f74696e6728290a20202020202020207d0a2020202020202020696620466c6f77444b472e646b67456e61626c6564207b0a20202020202020202020202073656c662e626f72726f77444b4741646d696e28292e656e64444b4728290a20202020202020207d0a0a202020202020202073656c662e626f72726f775374616b696e6741646d696e28292e6d6f7665546f6b656e7328290a0a202020202020202073656c662e63757272656e7445706f63685068617365203d2045706f636850686173652e5354414b494e4741554354494f4e0a0a20202020202020202f2f20557064617465207468652065706f636820636f756e746572730a202020202020202073656c662e63757272656e7445706f6368436f756e746572203d2073656c662e70726f706f73656445706f6368436f756e74657228290a202020207d0a0a202020202f2f2f20456e647320746865207374616b696e672041756374696f6e207769746820616c6c207468652070726f706f736564206e6f64657320617070726f7665640a20202020616363657373286163636f756e74292066756e20656e645374616b696e6741756374696f6e2829207b0a202020202020202073656c662e626f72726f775374616b696e6741646d696e28292e656e645374616b696e6741756374696f6e28290a202020207d0a0a202020202f2f2f20537461727473207468652045706f6368536574757020706861736520616e6420656d697473207468652065706f6368207365747570206576656e740a202020202f2f2f20546869732068617320746f2062652063616c6c6564206469726563746c792061667465722060656e645374616b696e6741756374696f6e600a20202020616363657373286163636f756e74292066756e20737461727445706f636853657475702872616e646f6d536f757263653a20537472696e6729207b0a0a20202020202020202f2f2047657420616c6c20746865206e6f6465732074686174206172652070726f706f73656420666f7220746865206e6578742065706f63680a20202020202020206c657420696473203d20466c6f7749445461626c655374616b696e672e67657450726f706f7365644e6f646549447328290a0a20202020202020202f2f20486f6c647320746865206e6f646520496e666f726d6174696f6e206f6620616c6c2074686520617070726f766564206e6f6465730a2020202020202020766172206e6f6465496e666f41727261793a205b466c6f7749445461626c655374616b696e672e4e6f6465496e666f5d203d205b5d0a0a20202020202020202f2f20486f6c6473206e6f646520494473206f66206f6e6c7920636f6c6c6563746f72206e6f64657320666f722051430a202020202020202076617220636f6c6c6563746f724e6f64654944733a205b537472696e675d203d205b5d0a0a20202020202020202f2f20486f6c6473206e6f646520494473206f66206f6e6c7920636f6e73656e737573206e6f64657320666f7220444b470a202020202020202076617220636f6e73656e7375734e6f64654944733a205b537472696e675d203d205b5d0a0a20202020202020202f2f20476574204e6f6465496e666f20666f7220616c6c20746865206e6f6465730a20202020202020202f2f2047657420616c6c2074686520636f6c6c6563746f7220616e6420636f6e73656e737573206e6f6465730a20202020202020202f2f20746f20696e697469616c697a652074686520514320616e6420444b470a2020202020202020666f7220696420696e20696473207b0a2020202020202020202020206c6574206e6f6465496e666f203d20466c6f7749445461626c655374616b696e672e4e6f6465496e666f286e6f646549443a206964290a0a2020202020202020202020206e6f6465496e666f41727261792e617070656e64286e6f6465496e666f290a0a2020202020202020202020206966206e6f6465496e666f2e726f6c65203d3d204e6f6465526f6c652e436f6c6c6563746f722e72617756616c7565207b0a20202020202020202020202020202020636f6c6c6563746f724e6f64654944732e617070656e64286e6f6465496e666f2e6964290a2020202020202020202020207d0a0a2020202020202020202020206966206e6f6465496e666f2e726f6c65203d3d204e6f6465526f6c652e436f6e73656e7375732e72617756616c7565207b0a20202020202020202020202020202020636f6e73656e7375734e6f64654944732e617070656e64286e6f6465496e666f2e6964290a2020202020202020202020207d0a20202020202020207d0a20202020202020200a20202020202020202f2f204f7267616e697a652074686520636f6c6c6563746f72206e6f64657320696e746f20636c7573746572730a20202020202020206c657420636f6c6c6563746f72436c757374657273203d2073656c662e637265617465436f6c6c6563746f72436c757374657273286e6f64654944733a20636f6c6c6563746f724e6f6465494473290a0a20202020202020202f2f20537461727420514320566f74696e6720776974682074686520737570706c69656420636c7573746572730a202020202020202073656c662e626f72726f77436c7573746572514341646d696e28292e7374617274566f74696e6728636c7573746572733a20636f6c6c6563746f72436c757374657273290a0a20202020202020202f2f20537461727420444b4720776974682074686520636f6e73656e737573206e6f6465730a202020202020202073656c662e626f72726f77444b4741646d696e28292e7374617274444b47286e6f64654944733a20636f6e73656e7375734e6f6465494473290a0a20202020202020206c65742063757272656e7445706f63684d65746164617461203d2073656c662e67657445706f63684d657461646174612873656c662e63757272656e7445706f6368436f756e74657229210a0a20202020202020202f2f20496e697469616c7a6520746865206d6574616461746120666f7220746865206e6578742065706f63680a20202020202020202f2f20514320616e6420444b47206d657461646174612077696c6c2062652066696c6c656420696e206c617465720a20202020202020206c65742070726f706f73656445706f63684d65746164617461203d2045706f63684d6574616461746128636f756e7465723a2073656c662e70726f706f73656445706f6368436f756e74657228292c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020736565643a2072616e646f6d536f757263652c0a2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020207374617274566965773a2063757272656e7445706f63684d657461646174612e656e6456696577202b2055496e7436342831292c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020656e64566965773a2063757272656e7445706f63684d657461646174612e656e6456696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e45706f63682c0a2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020207374616b696e67456e64566965773a2063757272656e7445706f63684d657461646174612e656e6456696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e2c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020746f74616c526577617264733a20302e30206173205546697836342c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020636f6c6c6563746f72436c7573746572733a20636f6c6c6563746f72436c7573746572732c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020636c75737465725143733a205b5d2c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020646b674b6579733a205b5d290a0a202020202020202073656c662e7361766545706f63684d657461646174612870726f706f73656445706f63684d65746164617461290a0a202020202020202073656c662e63757272656e7445706f63685068617365203d2045706f636850686173652e45504f434853455455500a0a2020202020202020656d69742045706f6368536574757028636f756e7465723a2070726f706f73656445706f63684d657461646174612e636f756e7465722c0a2020202020202020202020202020202020202020202020206e6f6465496e666f3a206e6f6465496e666f41727261792c200a2020202020202020202020202020202020202020202020206669727374566965773a2070726f706f73656445706f63684d657461646174612e7374617274566965772c0a20202020202020202020202020202020202020202020202066696e616c566965773a2070726f706f73656445706f63684d657461646174612e656e64566965772c0a202020202020202020202020202020202020202020202020636f6c6c6563746f72436c7573746572733a20636f6c6c6563746f72436c7573746572732c0a20202020202020202020202020202020202020202020202072616e646f6d536f757263653a2072616e646f6d536f757263652c0a202020202020202020202020202020202020202020202020444b4750686173653146696e616c566965773a2070726f706f73656445706f63684d657461646174612e737461727456696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b475068617365202d20312061732055496e7436342c0a202020202020202020202020202020202020202020202020444b4750686173653246696e616c566965773a2070726f706f73656445706f63684d657461646174612e737461727456696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e202b2028322061732055496e743634202a2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b47506861736529202d20312061732055496e7436342c0a202020202020202020202020202020202020202020202020444b4750686173653346696e616c566965773a2070726f706f73656445706f63684d657461646174612e737461727456696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e202b2028332061732055496e743634202a2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e444b47506861736529202d20312061732055496e743634290a202020207d0a0a202020202f2f2f20456e6473207468652045706f63685365747570207068617365207768656e2074686520514320616e6420444b472061726520636f6d706c657465640a202020202f2f2f20616e6420656d697473207468652045706f6368436f6d6d6974206576656e7420776974682074686520726573756c74730a20202020616363657373286163636f756e74292066756e20737461727445706f6368436f6d6d69742829207b0a202020202020202069662021466c6f77436c757374657251432e766f74696e67436f6d706c657465642829207c7c20466c6f77444b472e646b67436f6d706c657465642829203d3d206e696c207b0a20202020202020202020202072657475726e0a20202020202020207d0a0a20202020202020206c657420636c757374657273203d20466c6f77436c757374657251432e676574436c75737465727328290a0a20202020202020202f2f20486f6c6473207468652071756f72756d2063657274696669636174657320666f72206561636820636c75737465720a202020202020202076617220636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d203d205b5d0a0a20202020202020202f2f2069746572617465207468726f75676820616c6c2074686520636c75737465727320616e6420637265617465207468656972206365727469666963617465206172726179730a2020202020202020666f7220636c757374657220696e20636c757374657273207b0a202020202020202020202020766172206365727469666963617465203d20636c75737465722e67656e657261746551756f72756d436572746966696361746528290a202020202020202020202020202020203f3f2070616e69632822436f756c64206e6f742067656e6572617465207468652071756f72756d20636572746966696361746520666f72207468697320636c757374657222290a0a202020202020202020202020636c75737465725143732e617070656e64286365727469666963617465290a20202020202020207d0a0a20202020202020202f2f2053657420636c75737465722051437320696e207468652070726f706f7365642065706f6368206d657461646174610a20202020202020202f2f20616e642073746f7020514320766f74696e670a20202020202020206c65742070726f706f73656445706f63684d65746164617461203d2073656c662e67657445706f63684d657461646174612873656c662e70726f706f73656445706f6368436f756e746572282929210a202020202020202070726f706f73656445706f63684d657461646174612e736574436c7573746572514373287163733a20636c7573746572514373290a0a20202020202020202f2f2053657420444b4720726573756c74206b65797320696e207468652070726f706f7365642065706f6368206d657461646174610a20202020202020202f2f20616e642073746f7020444b470a20202020202020206c657420646b674b657973203d20466c6f77444b472e646b67436f6d706c657465642829210a20202020202020206c657420756e777261707065644b6579733a205b537472696e675d203d205b5d0a2020202020202020666f72206b657920696e20646b674b657973207b0a202020202020202020202020756e777261707065644b6579732e617070656e64286b657921290a20202020202020207d0a202020202020202070726f706f73656445706f63684d657461646174612e736574444b4747726f75704b6579286b6579733a20756e777261707065644b657973290a0a202020202020202073656c662e7361766545706f63684d657461646174612870726f706f73656445706f63684d65746164617461290a0a202020202020202073656c662e63757272656e7445706f63685068617365203d2045706f636850686173652e45504f4348434f4d4d49540a0a2020202020202020656d69742045706f6368436f6d6d697428636f756e7465723a2073656c662e70726f706f73656445706f6368436f756e74657228292c0a20202020202020202020202020202020202020202020202020202020636c75737465725143733a20636c75737465725143732c0a20202020202020202020202020202020202020202020202020202020646b675075624b6579733a20756e777261707065644b657973290a202020207d0a0a202020202f2f2f20426f72726f772061207265666572656e636520746f2074686520466c6f7749445461626c655374616b696e672041646d696e207265736f757263650a2020202061636365737328636f6e7472616374292066756e20626f72726f775374616b696e6741646d696e28293a2026466c6f7749445461626c655374616b696e672e41646d696e207b0a20202020202020206c65742061646d696e526566203d2073656c662e6163636f756e742e626f72726f773c26466c6f7749445461626c655374616b696e672e41646d696e3e2866726f6d3a20466c6f7749445461626c655374616b696e672e5374616b696e6741646d696e53746f7261676550617468290a2020202020202020202020203f3f2070616e69632822436f756c64206e6f7420626f72726f77207374616b696e672061646d696e22290a0a202020202020202072657475726e2061646d696e5265660a202020207d0a0a202020202f2f2f20426f72726f772061207265666572656e636520746f2074686520436c75737465725143732041646d696e207265736f757263650a2020202061636365737328636f6e7472616374292066756e20626f72726f77436c7573746572514341646d696e28293a2026466c6f77436c757374657251432e41646d696e207b0a20202020202020206c65742061646d696e526566203d2073656c662e6163636f756e742e626f72726f773c26466c6f77436c757374657251432e41646d696e3e2866726f6d3a20466c6f77436c757374657251432e41646d696e53746f7261676550617468290a2020202020202020202020203f3f2070616e69632822436f756c64206e6f7420626f72726f772071632061646d696e22290a0a202020202020202072657475726e2061646d696e5265660a202020207d0a0a202020202f2f2f20426f72726f772061207265666572656e636520746f2074686520444b472041646d696e207265736f757263650a2020202061636365737328636f6e7472616374292066756e20626f72726f77444b4741646d696e28293a2026466c6f77444b472e41646d696e207b0a20202020202020206c65742061646d696e526566203d2073656c662e6163636f756e742e626f72726f773c26466c6f77444b472e41646d696e3e2866726f6d3a20466c6f77444b472e41646d696e53746f7261676550617468290a2020202020202020202020203f3f2070616e69632822436f756c64206e6f7420626f72726f7720646b672061646d696e22290a0a202020202020202072657475726e2061646d696e5265660a202020207d0a0a202020202f2f2f204d616b657320737572652074686520736574206f66207068617365206c656e677468732028696e20766965777329206172652076616c69642e0a202020202f2f2f205375622d7068617365732063616e6e6f742062652067726561746572207468616e207468652066756c6c2065706f6368206c656e6774682e0a202020207075622066756e20697356616c69645068617365436f6e66696775726174696f6e285f2061756374696f6e4c656e3a2055496e7436342c205f20646b6750686173654c656e3a2055496e7436342c205f2065706f63684c656e3a2055496e743634293a20426f6f6c207b0a202020202020202072657475726e202861756374696f6e4c656e202b202828332061732055496e743634292a646b6750686173654c656e2929203c2065706f63684c656e0a202020207d0a0a202020202f2f2f2052616e646f6d697a657320746865206c697374206f6620636f6c6c6563746f72206e6f646520494420616e642075736573206120726f756e6420726f62696e20616c676f726974686d0a202020202f2f2f20746f2061737369676e20616c6c20636f6c6c6563746f72206e6f64657320746f20657175616c2073697a656420636c7573746572730a202020207075622066756e20637265617465436f6c6c6563746f72436c757374657273286e6f64654944733a205b537472696e675d293a205b466c6f77436c757374657251432e436c75737465725d207b0a2020202020202020707265207b0a20202020202020202020202055496e743136286e6f64654944732e6c656e67746829203e3d2073656c662e636f6e666967757261626c654d657461646174612e6e756d436f6c6c6563746f72436c7573746572733a202243616e6e6f742068617665206c65737320636f6c6c6563746f72206e6f646573207468616e20636c757374657273220a20202020202020207d0a20202020202020207661722073687566666c6564494473203d2073656c662e72616e646f6d697a65286e6f6465494473290a0a20202020202020202f2f20486f6c647320636c75737465722061737369676e6d656e747320666f7220636f6c6c6563746f72206e6f6465730a20202020202020206c657420636c7573746572733a205b466c6f77436c757374657251432e436c75737465725d203d205b5d0a202020202020202076617220636c7573746572496e6465783a2055496e743136203d20300a20202020202020206c6574206e6f64655765696768747344696374696f6e6172793a205b7b537472696e673a2055496e7436347d5d203d205b5d0a20202020202020207768696c6520636c7573746572496e646578203c2073656c662e636f6e666967757261626c654d657461646174612e6e756d436f6c6c6563746f72436c757374657273207b0a2020202020202020202020206e6f64655765696768747344696374696f6e6172792e617070656e64287b7d290a202020202020202020202020636c7573746572496e646578203d20636c7573746572496e646578202b20312061732055496e7431360a20202020202020207d0a2020202020202020636c7573746572496e646578203d20300a0a2020202020202020666f7220696420696e2073687566666c6564494473207b0a0a2020202020202020202020206c6574206e6f6465496e666f203d20466c6f7749445461626c655374616b696e672e4e6f6465496e666f286e6f646549443a206964290a0a2020202020202020202020206e6f64655765696768747344696374696f6e6172795b636c7573746572496e6465785d5b69645d203d206e6f6465496e666f2e696e697469616c5765696768740a2020202020202020202020200a2020202020202020202020202f2f20416476616e636520746f20746865206e65787420636c75737465722c206f72206261636b20746f20746865206669727374206966207765206861766520676f7474656e20746f20746865206c617374206f6e650a202020202020202020202020636c7573746572496e646578203d20636c7573746572496e646578202b20312061732055496e7431360a202020202020202020202020696620636c7573746572496e646578203d3d2073656c662e636f6e666967757261626c654d657461646174612e6e756d436f6c6c6563746f72436c757374657273207b0a20202020202020202020202020202020636c7573746572496e646578203d20300a2020202020202020202020207d0a20202020202020207d0a0a20202020202020202f2f204372656174652074686520636c75737465727320417272617920746861742069732073656e7420746f2074686520514320636f6e74726163740a20202020202020202f2f20616e6420656d697474656420696e207468652045706f63685365747570206576656e740a2020202020202020636c7573746572496e646578203d20300a20202020202020207768696c6520636c7573746572496e646578203c2073656c662e636f6e666967757261626c654d657461646174612e6e756d436f6c6c6563746f72436c757374657273207b0a202020202020202020202020636c7573746572732e617070656e6428466c6f77436c757374657251432e436c757374657228696e6465783a20636c7573746572496e6465782c206e6f6465576569676874733a206e6f64655765696768747344696374696f6e6172795b636c7573746572496e6465785d2129290a202020202020202020202020636c7573746572496e646578203d20636c7573746572496e646578202b20312061732055496e7431360a20202020202020207d0a0a202020202020202072657475726e20636c7573746572730a202020207d0a20200a202020202f2f2f20412066756e6374696f6e20746f2067656e657261746520612072616e646f6d207065726d75746174696f6e206f66206172725b5d200a202020202f2f2f207573696e6720746865206669736865722079617465732073687566666c696e6720616c676f726974686d0a202020207075622066756e2072616e646f6d697a65285f2061727261793a205b537472696e675d293a205b537472696e675d207b20200a0a20202020202020207661722069203d2061727261792e6c656e677468202d20310a0a20202020202020202f2f2053746172742066726f6d20746865206c61737420656c656d656e7420616e642073776170206f6e65206279206f6e652e20576520646f6e2774200a20202020202020202f2f206e65656420746f2072756e20666f722074686520666972737420656c656d656e7420746861742773207768792069203e2030200a20202020202020207768696c652069203e20300a20202020202020207b200a2020202020202020202020202f2f205069636b20612072616e646f6d20696e6465782066726f6d203020746f2069200a2020202020202020202020207661722072616e646f6d4e756d203d20756e7361666552616e646f6d28290a2020202020202020202020207661722072616e646f6d496e646578203d2072616e646f6d4e756d20252055496e7436342869202b2031290a202020200a2020202020202020202020202f2f2053776170206172725b695d20776974682074686520656c656d656e742061742072616e646f6d20696e646578200a2020202020202020202020207661722074656d70203d2061727261795b695d0a20202020202020202020202061727261795b695d203d2061727261795b72616e646f6d496e6465785d0a20202020202020202020202061727261795b72616e646f6d496e6465785d203d2074656d700a0a20202020202020202020202069203d2069202d20310a20202020202020207d0a0a202020202020202072657475726e2061727261790a202020207d0a0a202020202f2f2f20436f6c6c6563746f72206e6f6465732063616c6c20746869732066756e6374696f6e20746f2067657420746865697220514320566f746572207265736f757263650a202020202f2f2f20696e206f7264657220746f20706172746963697061746520746865207468652051432067656e65726174696f6e20666f7220746865697220636c75737465720a202020207075622066756e20676574436c75737465725143566f746572286e6f64655374616b65723a2026466c6f7749445461626c655374616b696e672e4e6f64655374616b6572293a2040466c6f77436c757374657251432e566f746572207b0a20202020202020206c6574206e6f6465496e666f203d20466c6f7749445461626c655374616b696e672e4e6f6465496e666f286e6f646549443a206e6f64655374616b65722e6964290a0a202020202020202061737365727420280a2020202020202020202020206e6f6465496e666f2e726f6c65203d3d204e6f6465526f6c652e436f6c6c6563746f722e72617756616c75652c0a2020202020202020202020206d6573736167653a20224e6f6465206f70657261746f72206d757374206265206120636f6c6c6563746f72206e6f646520746f20676574206120514320566f746572206f626a656374220a2020202020202020290a0a20202020202020206c657420636c7573746572514341646d696e203d2073656c662e626f72726f77436c7573746572514341646d696e28290a202020202020202072657475726e203c2d636c7573746572514341646d696e2e637265617465566f746572286e6f646549443a206e6f64655374616b65722e69642c207374616b696e674b65793a206e6f6465496e666f2e7374616b696e674b6579290a202020207d0a0a202020202f2f2f20436f6e73656e737573206e6f6465732063616c6c20746869732066756e6374696f6e20746f2067657420746865697220444b47205061727469636970616e74207265736f757263650a202020202f2f2f20696e206f7264657220746f20706172746963697061746520696e2074686520444b4720666f7220746865206e6578742065706f63680a202020207075622066756e20676574444b475061727469636970616e74286e6f64655374616b65723a2026466c6f7749445461626c655374616b696e672e4e6f64655374616b6572293a2040466c6f77444b472e5061727469636970616e74207b0a20202020202020206c6574206e6f6465496e666f203d20466c6f7749445461626c655374616b696e672e4e6f6465496e666f286e6f646549443a206e6f64655374616b65722e6964290a0a202020202020202061737365727420280a2020202020202020202020206e6f6465496e666f2e726f6c65203d3d204e6f6465526f6c652e436f6e73656e7375732e72617756616c75652c0a2020202020202020202020206d6573736167653a20224e6f6465206f70657261746f72206d757374206265206120636f6e73656e737573206e6f646520746f20676574206120444b47205061727469636970616e74206f626a656374220a2020202020202020290a0a20202020202020206c657420646b6741646d696e203d2073656c662e626f72726f77444b4741646d696e28290a202020202020202072657475726e203c2d646b6741646d696e2e6372656174655061727469636970616e74286e6f646549443a206e6f64655374616b65722e6964290a202020207d0a0a202020202f2f2f2052657475726e7320746865206d6574616461746120746861742069732061626c6520746f20626520636f6e66696775726564206279207468652061646d696e0a202020207075622066756e20676574436f6e6669674d6574616461746128293a20436f6e666967207b0a202020202020202072657475726e2073656c662e636f6e666967757261626c654d657461646174610a202020207d0a0a202020202f2f2f205468652070726f706f7365642045706f636820636f756e74657220697320616c77617973207468652063757272656e7420636f756e74657220706c757320310a202020207075622066756e2070726f706f73656445706f6368436f756e74657228293a2055496e743634207b0a202020202020202072657475726e2073656c662e63757272656e7445706f6368436f756e746572202b20312061732055496e7436340a202020207d0a0a202020207075622066756e206175746f6d6174696352657761726473456e61626c656428293a20426f6f6c207b0a202020202020202072657475726e2073656c662e6163636f756e742e636f70793c426f6f6c3e2866726f6d3a202f73746f726167652f666c6f774175746f6d6174696352657761726473456e61626c656429203f3f2066616c73650a202020207d0a0a202020202f2f2f2047657473207468652063757272656e7420616d6f756e74206f6620626f6e757320746f6b656e73206c65667420746f2062652064657374726f7965640a202020202f2f2f20426f6e757320746f6b656e732061726520746f6b656e732074686174207765726520616c6c6f6361746564206173206120646563656e7472616c697a6174696f6e20696e63656e746976650a202020202f2f2f2074686174206172652063757272656e746c7920696e207468652070726f63657373206f66206265696e672064657374726f7965642e205468652070726573656e6365206f6620626f6e75730a202020202f2f2f20746f6b656e73207468726f7773206f66662074686520696e74656e6465642063616c63756c6174696f6e20666f722074686520464c4f5720696e666c6174696f6e20726174650a202020202f2f2f20736f207468657920617265206e6f7420696e636c7564656420696e20746861742063616c63756c6174696f6e0a202020202f2f2f204576656e7475616c6c792c20616c6c2074686520626f6e757320746f6b656e732077696c6c2062652064657374726f79656420616e640a202020202f2f2f20746869732077696c6c206e6f74206265206e656564656420616e796d6f72650a202020207075622066756e20676574426f6e7573546f6b656e7328293a20554669783634207b0a202020202020202072657475726e2073656c662e6163636f756e742e636f70793c5546697836343e2866726f6d3a202f73746f726167652f466c6f77426f6e7573546f6b656e416d6f756e74290a202020202020202020202020202020203f3f20302e300a202020207d0a0a20202020696e6974202863757272656e7445706f6368436f756e7465723a2055496e7436342c0a202020202020202020206e756d5669657773496e45706f63683a2055496e7436342c200a202020202020202020206e756d5669657773496e5374616b696e6741756374696f6e3a2055496e7436342c200a202020202020202020206e756d5669657773496e444b4750686173653a2055496e7436342c200a202020202020202020206e756d436f6c6c6563746f72436c7573746572733a2055496e7431362c0a20202020202020202020464c4f57737570706c79496e63726561736550657263656e746167653a205546697836342c0a2020202020202020202072616e646f6d536f757263653a20537472696e672c0a20202020202020202020636f6c6c6563746f72436c7573746572733a205b466c6f77436c757374657251432e436c75737465725d2c0a20202020202020202020636c75737465725143733a205b466c6f77436c757374657251432e436c757374657251435d2c0a20202020202020202020646b675075624b6579733a205b537472696e675d29207b0a2020202020202020707265207b0a202020202020202020202020466c6f7745706f63682e697356616c69645068617365436f6e66696775726174696f6e286e756d5669657773496e5374616b696e6741756374696f6e2c206e756d5669657773496e444b4750686173652c206e756d5669657773496e45706f6368293a0a2020202020202020202020202020202022496e76616c69642073746172745669657720616e6420656e645669657720636f6e66696775726174696f6e220a20202020202020207d0a0a202020202020202073656c662e636f6e666967757261626c654d65746164617461203d20436f6e666967286e756d5669657773496e45706f63683a206e756d5669657773496e45706f63682c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020206e756d5669657773496e5374616b696e6741756374696f6e3a206e756d5669657773496e5374616b696e6741756374696f6e2c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020206e756d5669657773496e444b4750686173653a206e756d5669657773496e444b4750686173652c0a202020202020202020202020202020202020202020202020202020202020202020202020202020202020206e756d436f6c6c6563746f72436c7573746572733a206e756d436f6c6c6563746f72436c7573746572732c0a20202020202020202020202020202020202020202020202020202020202020202020202020202020202020464c4f57737570706c79496e63726561736550657263656e746167653a20464c4f57737570706c79496e63726561736550657263656e74616765290a20202020202020200a202020202020202073656c662e63757272656e7445706f6368436f756e746572203d2063757272656e7445706f6368436f756e7465720a202020202020202073656c662e63757272656e7445706f63685068617365203d2045706f636850686173652e5354414b494e4741554354494f4e0a202020202020202073656c662e61646d696e53746f7261676550617468203d202f73746f726167652f666c6f7745706f636841646d696e0a202020202020202073656c662e68656172746265617453746f7261676550617468203d202f73746f726167652f666c6f7745706f63684865617274626561740a202020202020202073656c662e6d6574616461746153746f7261676550617468203d202f73746f726167652f666c6f7745706f63684d657461646174610a0a20202020202020206c65742065706f63684d657461646174613a207b55496e7436343a2045706f63684d657461646174617d203d207b7d0a202020202020202073656c662e6163636f756e742e736176652865706f63684d657461646174612c20746f3a2073656c662e6d6574616461746153746f7261676550617468290a0a202020202020202073656c662e6163636f756e742e73617665283c2d6372656174652041646d696e28292c20746f3a2073656c662e61646d696e53746f7261676550617468290a202020202020202073656c662e6163636f756e742e73617665283c2d6372656174652048656172746265617428292c20746f3a2073656c662e68656172746265617453746f7261676550617468290a0a202020202020202073656c662e626f72726f775374616b696e6741646d696e28292e73746172745374616b696e6741756374696f6e28290a0a20202020202020206c65742063757272656e74426c6f636b203d2067657443757272656e74426c6f636b28290a0a20202020202020206c657420666972737445706f63684d65746164617461203d2045706f63684d6574616461746128636f756e7465723a2073656c662e63757272656e7445706f6368436f756e7465722c0a2020202020202020202020202020202020202020736565643a2072616e646f6d536f757263652c0a20202020202020202020202020202020202020207374617274566965773a2063757272656e74426c6f636b2e766965772c0a2020202020202020202020202020202020202020656e64566965773a2063757272656e74426c6f636b2e76696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e45706f6368202d2028312061732055496e743634292c0a20202020202020202020202020202020202020207374616b696e67456e64566965773a2063757272656e74426c6f636b2e76696577202b2073656c662e636f6e666967757261626c654d657461646174612e6e756d5669657773496e5374616b696e6741756374696f6e202d2028312061732055496e743634292c0a2020202020202020202020202020202020202020746f74616c526577617264733a20466c6f7749445461626c655374616b696e672e67657445706f6368546f6b656e5061796f757428292c0a2020202020202020202020202020202020202020636f6c6c6563746f72436c7573746572733a20636f6c6c6563746f72436c7573746572732c0a2020202020202020202020202020202020202020636c75737465725143733a20636c75737465725143732c0a2020202020202020202020202020202020202020646b674b6579733a20646b675075624b657973290a202020202020202073656c662e7361766545706f63684d6574616461746128666972737445706f63684d65746164617461290a202020207d0a7d0a20" + } +] \ No newline at end of file diff --git a/transactions/update-contract/2023/may-3-rewards/upgrade_and_enable_rewards.cdc b/transactions/update-contract/2023/may-3-rewards/upgrade_and_enable_rewards.cdc new file mode 100644 index 00000000..05ea8c99 --- /dev/null +++ b/transactions/update-contract/2023/may-3-rewards/upgrade_and_enable_rewards.cdc @@ -0,0 +1,21 @@ +import FlowIDTableStaking from 0x8624b52f9ddcd04a + +/// Transaction to upgrade the FlowEpoch contract +/// and enable automatic staking rewards + +transaction(bonusTokenAmount: UFix64, code: String) { + + prepare(stakingAccount: AuthAccount) { + + // Borrow the admin to enable automatic staking rewards + let adminRef = stakingAccount.borrow<&FlowIDTableStaking.Admin>(from: FlowIDTableStaking.StakingAdminStoragePath) + ?? panic("Could not borrow reference to staking admin") + + adminRef.updateAutomaticRewardsEnabled(true) + + stakingAccount.load(from: /storage/FlowBonusTokenAmount) + stakingAccount.save(bonusTokenAmount, to: /storage/FlowBonusTokenAmount) + + stakingAccount.contracts.update__experimental(name: "FlowEpoch", code: code.decodeHex()) + } +}