import "./messages"; struct Proposal { type: Int; // 0 - Blacklist, 1 - Full liquidation, 2 - Change percents data: Cell; // Address for blacklist, Distribution for percents } struct Vote { id: Int; votes: map[Int]Int; // -1 - no vote, 0 - abstain, 1 - yes, 2 - no vote_end: Int; proposal: Proposal; quorum_percent: Int; ended: Bool = false; result: Bool?; // None - no result, True - passed, False - failed } fun get_message(prop: Proposal): Cell { if (prop.type == 0) { return BlacklistWallet { wallet: prop.data.readAddress() }.asCell(); } } contract Foundation { founders: AddressList; // aka superadmins admins: Distribution/* Distribution is defined in messages.tact */; tonb: Address; votes: map[Int]Vote; n_votes: Int; init(admins: Distribution, founders: AddressList, tonb: Address) { self.admins = admins; self.founders = founders; self.tonb = tonb; } receive(msg: FinishVote) { require(msg.vote_id < self.n_votes, "Invalid vote id"); let vote: Vote = self.votes.get(msg.vote_id)!!; require(vote.ended == false, "Vote already ended"); require(vote.vote_end < now(), "Vote is not finished yet"); let n_yes: Int = 0; let n_no: Int = 0; let n_abstain: Int = 0; let i: Int = 0; while (i < self.admins.addresses.length) { let vote_: Int = vote.votes.get(i)!!; if (vote_i == 1) { n_yes = n_yes + 1; } else if (vote_i == 2) { n_no = n_no + 1; } else if (vote_i == 0) { n_abstain = n_abstain + 1; } i = i + 1; } let n_total: Int = n_yes + n_no + n_abstain; let present: Int = n_total * 100 / self.admins.addresses.length; if (present < vote.quorum_percent) { vote.result = false; } else if (n_yes > n_no) { vote.result = true; } else { vote.result = false; } vote.ended = true; self.votes.set(msg.vote_id, vote); if (vote.result == true) { let msg: Cell = get_message(vote.proposal); send(SendParameters{ to: self.tonb, value: 0, mode: SendRemainingValue, body: msg }); } } receive(msg: Vote) { require(msg.adminIndex < self.admins.addresses.length, "Invalid admin index") let ctx: Context = context(); require(ctx.sender == self.admins.addresses.addresses.get(msg.adminIndex), "Only an admin can vote"); require(msg.vote_id < self.n_votes, "Invalid vote id"); let vote: Vote = self.votes.get(msg.vote_id)!!; require(vote.ended == false, "Vote already ended"); require(vote.vote_end > now(), "Vote is finished"); require(msg.vote >= 0 && msg.vote <= 2, "Invalid vote"); vote.votes.set(msg.adminIndex, msg.vote); self.votes.set(msg.vote_id, vote); } receive(msg: InitiateBlacklistVote) { let ctx: Context = context(); require(ctx.sender == self.admins.addresses.addresses.get(msg.adminIndex), "Only an admin can initiate a vote"); require(ctx.value >= ton("1.0"), "Voting requires at least 1 ton for the fees") require(msg.quorum_percent > 20 && msg.quorum_percent <= 100, "Invalid quorum percent"); require(msg.vote_time > 0 && msg.vote_time < 3 * 24 * 3600, "Invalid vote time"); let vote = Vote { id: self.n_votes, vote_end: now() + msg.vote_time, proposal: Proposal { type: 0, data: msg.address }, quorum_percent: msg.quorum_percent }; let i: Int = 0; while (i < self.admins.addresses.length) { vote.votes.set(i, -1); i = i + 1; } self.votes.set(self.n_votes, vote); self.n_votes = self.n_votes + 1; } receive(msg: InitiateDistributionVote) { let ctx: Context = context(); require(ctx.sender == self.admins.addresses.addresses.get(msg.adminIndex), "Only an admin can initiate a vote"); require(ctx.value >= ton("1.0"), "Voting requires at least 1 ton for the fees") require(msg.quorum_percent > 20 && msg.quorum_percent <= 100, "Invalid quorum percent"); require(msg.vote_time > 0 && msg.vote_time < 3 * 24 * 3600, "Invalid vote time"); let vote = Vote { id: self.n_votes, vote_end: now() + msg.vote_time, proposal: Proposal { type: 2, data: msg.distribution }, quorum_percent: msg.quorum_percent }; let i: Int = 0; while (i < self.admins.addresses.length) { vote.votes.set(i, -1); i = i + 1; } self.votes.set(self.n_votes, vote); self.n_votes = self.n_votes + 1; } receive(msg: InitiateFullLiquidationVote) { let ctx: Context = context(); require(ctx.sender == self.admins.addresses.addresses.get(msg.adminIndex), "Only an admin can initiate a vote"); require(ctx.value >= ton("1.0"), "Voting requires at least 1 ton for the fees") require(msg.quorum_percent > 85 && msg.quorum_percent <= 100, "Invalid quorum percent"); require(msg.vote_time > 0 && msg.vote_time < 3 * 24 * 3600, "Invalid vote time"); let vote = Vote { id: self.n_votes, vote_end: now() + msg.vote_time, proposal: Proposal { type: 1, data: beginCell().endCell() }, quorum_percent: msg.quorum_percent }; let i: Int = 0; while (i < self.admins.addresses.length) { vote.votes.set(i, -1); i = i + 1; } self.votes.set(self.n_votes, vote); self.n_votes = self.n_votes + 1; } }