Browse Source

Cli for Foundation-related ops

master
Lev 2 years ago
parent
commit
971a36b4b6
  1. 126
      sources/cli.js
  2. 49
      sources/foundation.deploy.ts
  3. 2
      sources/foundation.tact
  4. 8
      sources/jetton.deploy.ts
  5. 1
      sources/output/jetton_Foundation.abi
  6. BIN
      sources/output/jetton_Foundation.code.boc
  7. 765
      sources/output/jetton_Foundation.code.fc
  8. 1531
      sources/output/jetton_Foundation.code.fif
  9. 2663
      sources/output/jetton_Foundation.code.rev.fif
  10. BIN
      sources/output/jetton_Foundation.init.boc
  11. 78
      sources/output/jetton_Foundation.init.fc
  12. 93
      sources/output/jetton_Foundation.init.fif
  13. 64
      sources/output/jetton_Foundation.init.rev.fif
  14. 162
      sources/output/jetton_Foundation.md
  15. 1
      sources/output/jetton_Foundation.pkg
  16. 1978
      sources/output/jetton_Foundation.ts
  17. 6
      sources/utils/config.ts
  18. 79
      sources/utils/interactions.ts

126
sources/cli.js

@ -1,9 +1,19 @@
const subcommand = require('subcommand');
const { deployTONB, deposit, withdraw, transfer, blacklistAddress } = require('./utils/interactions');
const { wallet_data, client } = require('./utils/config');
const { deployTONB, deposit, withdraw, transfer, blacklistAddress, getTONBOpen, getFoundationOpen, changeTONBOwner, createBlacklistVote } = require('./utils/interactions');
const { wallet_data, client, client4 } = require('./utils/config');
const { randomAddress, TON } = require('./utils/helpers');
const { toNano, Address } = require('ton');
const { TONB } = require('./output/jetton_TONB');
const { Foundation } = require('./output/jetton_Foundation');
const wal_opt = {
name: 'wallet',
abbr: 'w',
default: '0',
required: false
};
const match = subcommand([
{
@ -22,7 +32,7 @@ const match = subcommand([
}
],
async command(opts) {
let {my_wallet, secretKey} = await wallet_data(parseInt(opts._[1]));
let { my_wallet, secretKey } = await wallet_data(parseInt(opts._[1]));
let tonb_addr = await deployTONB(undefined, true);
await deposit(my_wallet, secretKey, parseFloat(opts._[0]) * 1000000000, tonb_addr);
}
@ -44,7 +54,7 @@ const match = subcommand([
}
],
async command(opts) {
let {my_wallet, secretKey} = await wallet_data(parseInt(opts._[1]));
let { my_wallet, secretKey } = await wallet_data(parseInt(opts._[1]));
let tonb_addr = await deployTONB(undefined, true);
await withdraw(my_wallet, secretKey, parseFloat(opts._[0]) * 1000000000, tonb_addr);
}
@ -63,7 +73,7 @@ const match = subcommand([
default: randomAddress()
}],
async command(opts) {
let {my_wallet, secretKey} = await wallet_data();
let { my_wallet, secretKey } = await wallet_data();
let tonb_addr = await deployTONB(undefined, true);
await transfer(my_wallet, secretKey, parseFloat(opts._[0]) * 1000000000, tonb_addr, opts._[1]);
}
@ -82,7 +92,7 @@ const match = subcommand([
}
],
async command(opts) {
let {my_wallet, secretKey} = await wallet_data(parseInt(opts._[1]));
let { my_wallet, secretKey } = await wallet_data(parseInt(opts._[1]));
let tonb_addr = await deployTONB(undefined, true);
if (!opts._[0]) {
opts._[0] = 'kQD7zbEMaWC2yMgSJXmIF7HbLr1yuBo2GnZF_CJNkUiGSVZ8'// my_wallet.address;
@ -90,6 +100,110 @@ const match = subcommand([
let addr = Address.parse(opts._[0]);
await blacklistAddress(my_wallet, secretKey, tonb_addr, addr);
}
},
{
name: 'change-tonb-owner',
options: [
{
name: 'address',
},
{
name: 'tonb',
required: false
}, wal_opt
],
async command(opts) {
let { my_wallet, secretKey } = await wallet_data(parseInt(opts.w));
let tonb = await getTONBOpen();
let addr = Address.parse(opts._[0]);
if (opts._[1]) {
let tonb_addr = Address.parse(opts._[1]);
tonb = client4.open(TONB.fromAddress(tonb_addr));
}
await changeTONBOwner(my_wallet, secretKey, tonb.address, addr);
// await tonb.send(my_wallet, { value: toNano('0.1') }, {
// $$type: 'SetOwner', owner: addr });
}
},
{
name: 'create-blacklist-vote',
options: [
{
name: 'address',
},
{
name: 'foundation-address',
required: false
},
wal_opt
],
async command(opts) {
let { my_wallet, secretKey } = await wallet_data(parseInt(opts.w));
let foundation = await getFoundationOpen((await getTONBOpen()).address);
if (opts._[1]) {
let foundation_addr = Address.parse(opts._[1]);
foundation = client.open(Foundation.fromAddress(foundation_addr));
}
let addr = Address.parse(opts._[0]);
let adminIndex = BigInt(parseInt(opts.w));
// let msg = {
// $$type: 'InitiateBlacklistVote', wallet: addr,
// vote_time: 10n, quorum_percent: 50n, adminIndex // An admin has to create the vote
// };
// await foundation.send(my_wallet, { value: toNano('1.1') }, msg);
await createBlacklistVote(my_wallet, secretKey, foundation.address,
addr, 10n, adminIndex);
}
},
{
name: 'get-vote',
options: [
{
name: 'vote-id'
},
{
name: 'foundation-address',
required: false
}
],
async command(opts) {
let foundation = await getFoundationOpen((await getTONBOpen()).address);
if (opts._[1]) {
let foundation_addr = Address.parse(opts._[1]);
foundation = client4.open(Foundation.fromAddress(foundation_addr));
}
let vote = await foundation.getNthVote(opts._[0]);
console.log(vote);
}
},
{
name: 'vote',
options: [
{
name: 'vote-id'
},
{
name: 'vote',
abbr: 'v',
help: 'Vote for or against the proposal (1 - for, 2 - against)',
},
{
name: 'foundation-address',
required: false
},
wal_opt
],
async command(opts) {
let { my_wallet, secretKey } = await wallet_data(parseInt(opts.w));
let foundation = await getFoundationOpen((await getTONBOpen()).address);
if (opts._[2]) {
let foundation_addr = Address.parse(opts._[2]);
foundation = client.open(Foundation.fromAddress(foundation_addr));
}
await foundation.send(my_wallet, { value: toNano('0.1') }, {
$$type: 'VoteMsg', voteId: opts._[0], vote: opts._[1], adminIndex: BigInt(parseInt(opts.w))
});
}
}
]);
const argv = process.argv.slice(2);

49
sources/foundation.deploy.ts

@ -0,0 +1,49 @@
import { beginCell, contractAddress, toNano, TonClient, TonClient4, Address, WalletContractV4, internal, fromNano, Cell} from "ton";
import {mnemonicToPrivateKey} from "ton-crypto";
import {buildOnchainMetadata} from "./utils/helpers";
import {Foundation} from "./output/jetton_Foundation";
import {client, wallet_data, workchain} from "./utils/config";
import { createDistribution, createAddressList, getTONBState } from './utils/interactions';
(async () => {
//create client for testnet sandboxv4 API - alternative endpoint
const client4 = new TonClient4({
endpoint: "https://sandbox-v4.tonhubapi.com"
})
let {my_wallet, secretKey} = await wallet_data();
// Get deployment wallet balance
let balance: bigint = await my_wallet.getBalance();
// Compute init data for deployment
let init = await Foundation.init(
createDistribution([my_wallet.address], [100n]),
createAddressList([my_wallet.address]),
contractAddress(workchain, await getTONBState()));
let destination_address = contractAddress(workchain, init);
let deployAmount = toNano('0.2');
// send a message on new address contract to deploy it
let seqno: number = await my_wallet.getSeqno();
console.log('🛠Preparing new outgoing massage from deployment wallet. Seqno = ', seqno);
console.log('Current deployment wallet balance = ', fromNano(balance).toString(), '💎TON');
await my_wallet.sendTransfer({
seqno,
secretKey,
messages: [internal({
value: deployAmount,
to: destination_address,
init: {
code : init.code,
data : init.data
}
})]
});
console.log('======deployment message sent to ', destination_address, ' ======');
})();

2
sources/foundation.tact

@ -243,6 +243,8 @@ contract Foundation {
});
}
receive() {}
get fun numVotes(): Int {
return self.n_votes;
}

8
sources/jetton.deploy.ts

@ -3,9 +3,10 @@ import {mnemonicToPrivateKey} from "ton-crypto";
import {buildOnchainMetadata} from "./utils/helpers";
import {TONB} from "./output/jetton_TONB";
import {client, wallet_data, workchain, owner, jettonParams, default_content} from "./utils/config";
import { getTONBState } from "./utils/interactions";
(async () => { //need changes for jetton
(async () => {
//create client for testnet sandboxv4 API - alternative endpoint
const client4 = new TonClient4({
@ -16,13 +17,11 @@ import {client, wallet_data, workchain, owner, jettonParams, default_content} fr
// Get deployment wallet balance
let balance: bigint = await my_wallet.getBalance();
// Compute init data for deployment
let init = await TONB.init(owner, default_content);
let init = await getTONBState();
let destination_address = contractAddress(workchain, init);
let deployAmount = toNano('0.2');
let supply = 500;
let amount = BigInt(supply * Math.pow(10, 9));
// send a message on new address contract to deploy it
@ -31,7 +30,6 @@ import {client, wallet_data, workchain, owner, jettonParams, default_content} fr
console.log('🛠Preparing new outgoing massage from deployment wallet. Seqno = ', seqno);
console.log('Current deployment wallet balance = ', fromNano(balance).toString(), '💎TON');
console.log('Totally supply for deployed Token = ', supply, ', amount = ', amount.toString());
await my_wallet.sendTransfer({
seqno,
secretKey,

1
sources/output/jetton_Foundation.abi

File diff suppressed because one or more lines are too long

BIN
sources/output/jetton_Foundation.code.boc

Binary file not shown.

765
sources/output/jetton_Foundation.code.fc

@ -0,0 +1,765 @@
#pragma version =0.4.1;
#pragma allow-post-modification;
#pragma compute-asm-ltr;
forall X -> X __tact_not_null(X x) inline { throw_if(128, null?(x)); return x; }
(cell, int) __tact_dict_delete(cell dict, int key_len, slice index) asm(index dict key_len) "DICTDEL";
(slice, int) __tact_dict_get(cell dict, int key_len, slice index) asm(index dict key_len) "DICTGET" "NULLSWAPIFNOT";
global (int, slice, int, slice) __tact_context;
global cell __tact_context_sys;
(int, slice, int, slice) __tact_context_get() inline { return __tact_context; }
() __tact_verify_address(slice address) inline {
throw_unless(136, address.slice_bits() != 267);
}
builder __tact_store_bool(builder b, int v) inline {
b = b.store_int(v, 1);
return b;
}
(slice, slice) __tact_load_address(slice cs) inline {
slice raw = cs~load_msg_addr();
__tact_verify_address(raw);
return (cs, raw);
}
(slice, slice) __tact_load_address_opt(slice cs) inline {
slice raw = cs~load_msg_addr();
if (raw.preload_uint(2) != 0) {
__tact_verify_address(raw);
return (cs, raw);
} else {
return (cs, null());
}
}
builder __tact_store_address(builder b, slice address) inline {
__tact_verify_address(address);
b = b.store_slice(address);
return b;
}
builder __tact_store_address_opt(builder b, slice address) inline {
if (null?(address)) {
b = b.store_uint(0, 2);
return b;
} else {
return __tact_store_address(b, address);
}
}
(cell, ()) __tact_dict_set_int_int(cell d, int kl, int k, int v, int vl) inline {
if (null?(v)) {
var (r, ok) = idict_delete?(d, kl, k);
return (r, ());
} else {
return (idict_set_builder(d, kl, k, begin_cell().store_int(v, vl)), ());
}
}
int __tact_dict_get_int_int(cell d, int kl, int k, int vl) inline {
var (r, ok) = idict_get?(d, kl, k);
if (ok) {
return r~load_int(vl);
} else {
return null();
}
}
(cell, ()) __tact_dict_set_int_cell(cell d, int kl, int k, cell v) inline {
if (null?(v)) {
var (r, ok) = idict_delete?(d, kl, k);
return (r, ());
} else {
return (idict_set_ref(d, kl, k, v), ());
}
}
cell __tact_dict_get_int_cell(cell d, int kl, int k) {
var (r, ok) = idict_get_ref?(d, kl, k);
if (ok) {
return r;
} else {
return null();
}
}
slice __tact_dict_get_int_slice(cell d, int kl, int k) inline {
var (r, ok) = idict_get?(d, kl, k);
if (ok) {
return r;
} else {
return null();
}
}
(cell, ()) __tact_dict_set_slice_int(cell d, int kl, slice k, int v, int vl) {
if (null?(v)) {
var (r, ok) = __tact_dict_delete(d, kl, k);
return (r, ());
} else {
return (dict_set_builder(d, kl, k, begin_cell().store_int(v, vl)), ());
}
}
int __tact_dict_get_slice_int(cell d, int kl, slice k, int vl) inline {
var (r, ok) = __tact_dict_get(d, kl, k);
if (ok) {
return r~load_int(vl);
} else {
return null();
}
}
int __tact_address_eq(slice a, slice b) inline {
return equal_slice_bits(a, b);
}
forall X0, X1, X2, X3, X4 -> tuple __tact_tuple_create_5((X0, X1, X2, X3, X4) v) asm "5 TUPLE";
forall X0, X1, X2, X3, X4 -> (X0, X1, X2, X3, X4) __tact_tuple_destroy_5(tuple v) asm "5 UNTUPLE";
forall X0, X1, X2, X3, X4, X5 -> tuple __tact_tuple_create_6((X0, X1, X2, X3, X4, X5) v) asm "6 TUPLE";
forall X0, X1, X2, X3, X4, X5 -> (X0, X1, X2, X3, X4, X5) __tact_tuple_destroy_6(tuple v) asm "6 UNTUPLE";
builder __gen_write_BlacklistWallet(builder build_0, (slice) v) inline {
var (v'wallet) = v;
build_0 = store_uint(build_0, 43811734, 32);
build_0 = __tact_store_address(build_0, v'wallet);
return build_0;
}
cell __gen_writecell_BlacklistWallet((slice) v) inline_ref {
return __gen_write_BlacklistWallet(begin_cell(), v).end_cell();
}
(slice, ((int, slice, int, int))) __gen_read_InitiateBlacklistVote(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 3909090059);
var v'adminIndex = sc_0~load_int(257);
var v'wallet = sc_0~__tact_load_address();
var v'quorum_percent = sc_0~load_int(257);
slice sc_1 = sc_0~load_ref().begin_parse();
var v'vote_time = sc_1~load_int(257);
return (sc_0, (v'adminIndex, v'wallet, v'quorum_percent, v'vote_time));
}
(slice, ((int, int, int))) __gen_read_InitiateLiquidationVote(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 301696559);
var v'adminIndex = sc_0~load_int(257);
var v'quorum_percent = sc_0~load_int(257);
var v'vote_time = sc_0~load_int(257);
return (sc_0, (v'adminIndex, v'quorum_percent, v'vote_time));
}
(slice, ((int))) __gen_read_FinishVote(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 710362179);
var v'voteId = sc_0~load_int(257);
return (sc_0, (v'voteId));
}
(slice, ((int, int, int))) __gen_read_VoteMsg(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 1493035179);
var v'voteId = sc_0~load_int(257);
var v'adminIndex = sc_0~load_int(257);
var v'vote = sc_0~load_int(257);
return (sc_0, (v'voteId, v'adminIndex, v'vote));
}
builder __gen_write_AddressList(builder build_0, (cell, int) v) inline {
var (v'addresses, v'length) = v;
build_0 = build_0.store_dict(v'addresses);
build_0 = build_0.store_int(v'length, 257);
return build_0;
}
(slice, ((cell, int))) __gen_read_AddressList(slice sc_0) inline {
var v'addresses = sc_0~load_dict();
var v'length = sc_0~load_int(257);
return (sc_0, (v'addresses, v'length));
}
builder __gen_write_Distribution(builder build_0, ((cell, int), cell) v) inline {
var ((v'addresses'addresses, v'addresses'length), v'percents) = v;
build_0 = __gen_write_AddressList(build_0, (v'addresses'addresses, v'addresses'length));
build_0 = build_0.store_dict(v'percents);
return build_0;
}
(slice, (((cell, int), cell))) __gen_read_Distribution(slice sc_0) inline {
var v'addresses = sc_0~__gen_read_AddressList();
var v'percents = sc_0~load_dict();
return (sc_0, (v'addresses, v'percents));
}
(slice, ((int, int, int, ((cell, int), cell)))) __gen_read_InitiateDistributionVote(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 2512227654);
var v'adminIndex = sc_0~load_int(257);
var v'quorum_percent = sc_0~load_int(257);
var v'vote_time = sc_0~load_int(257);
slice sc_1 = sc_0~load_ref().begin_parse();
var v'distribution = sc_1~__gen_read_Distribution();
return (sc_0, (v'adminIndex, v'quorum_percent, v'vote_time, v'distribution));
}
builder __gen_write_Unstake(builder build_0, (int) v) inline {
var (v'amount) = v;
build_0 = store_uint(build_0, 3125946401, 32);
build_0 = build_0.store_int(v'amount, 257);
return build_0;
}
cell __gen_writecell_Unstake((int) v) inline_ref {
return __gen_write_Unstake(begin_cell(), v).end_cell();
}
(slice, ((int))) __gen_read_Unstake(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 3125946401);
var v'amount = sc_0~load_int(257);
return (sc_0, (v'amount));
}
(slice, ((int))) __gen_read_RequestUnstake(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 3922648959);
var v'founderIndex = sc_0~load_int(257);
return (sc_0, (v'founderIndex));
}
(slice, ((int))) __gen_read_CollectProfit(slice sc_0) inline {
throw_unless(129, sc_0~load_uint(32) == 1368467253);
var v'adminIndex = sc_0~load_int(257);
return (sc_0, (v'adminIndex));
}
builder __gen_write_Proposal(builder build_0, (int, slice, cell, int, cell) v) inline {
var (v'type, v'blacklistAddress, v'distribution_addresses, v'distribution_addresses_length, v'distribution_percents) = v;
build_0 = build_0.store_int(v'type, 257);
build_0 = __tact_store_address_opt(build_0, v'blacklistAddress);
build_0 = build_0.store_dict(v'distribution_addresses);
build_0 = ~ null?(v'distribution_addresses_length) ? build_0.store_int(true, 1).store_int(v'distribution_addresses_length, 257) : build_0.store_int(false, 1);
build_0 = build_0.store_dict(v'distribution_percents);
return build_0;
}
cell __gen_writecell_Proposal((int, slice, cell, int, cell) v) inline_ref {
return __gen_write_Proposal(begin_cell(), v).end_cell();
}
(slice, ((int, slice, cell, int, cell))) __gen_read_Proposal(slice sc_0) inline {
var v'type = sc_0~load_int(257);
var v'blacklistAddress = sc_0~__tact_load_address_opt();
var v'distribution_addresses = sc_0~load_dict();
var v'distribution_addresses_length = sc_0~load_int(1) ? sc_0~load_int(257) : null();
var v'distribution_percents = sc_0~load_dict();
return (sc_0, (v'type, v'blacklistAddress, v'distribution_addresses, v'distribution_addresses_length, v'distribution_percents));
}
tuple __gen_Proposal_as_optional(((int, slice, cell, int, cell)) v) inline {
var (v'type, v'blacklistAddress, v'distribution_addresses, v'distribution_addresses_length, v'distribution_percents) = v;
return __tact_tuple_create_5(v'type, v'blacklistAddress, v'distribution_addresses, v'distribution_addresses_length, v'distribution_percents);
}
tuple __gen_readopt_Proposal(cell cl) inline_ref {
if (null?(cl)) {
return null();
}
var sc = cl.begin_parse();
return __gen_Proposal_as_optional(sc~__gen_read_Proposal());
}
builder __gen_write_Vote(builder build_0, (int, cell, int, int, int, int) v) inline_ref {
var (v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result) = v;
build_0 = build_0.store_int(v'id, 257);
build_0 = build_0.store_dict(v'votes);
build_0 = build_0.store_int(v'vote_end, 257);
build_0 = build_0.store_int(v'quorum_percent, 257);
build_0 = build_0.store_int(v'ended, 1);
build_0 = ~ null?(v'result) ? build_0.store_int(true, 1).store_int(v'result, 1) : build_0.store_int(false, 1);
return build_0;
}
cell __gen_writecell_Vote((int, cell, int, int, int, int) v) inline_ref {
return __gen_write_Vote(begin_cell(), v).end_cell();
}
(slice, ((int, cell, int, int, int, int))) __gen_read_Vote(slice sc_0) inline_ref {
var v'id = sc_0~load_int(257);
var v'votes = sc_0~load_dict();
var v'vote_end = sc_0~load_int(257);
var v'quorum_percent = sc_0~load_int(257);
var v'ended = sc_0~load_int(1);
var v'result = sc_0~load_int(1) ? sc_0~load_int(1) : null();
return (sc_0, (v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result));
}
tuple __gen_Vote_as_optional(((int, cell, int, int, int, int)) v) inline {
var (v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result) = v;
return __tact_tuple_create_6(v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result);
}
tuple __gen_readopt_Vote(cell cl) inline_ref {
if (null?(cl)) {
return null();
}
var sc = cl.begin_parse();
return __gen_Vote_as_optional(sc~__gen_read_Vote());
}
builder __gen_write_Foundation(builder build_0, ((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) v) inline {
var ((v'founders'addresses, v'founders'length), ((v'admins'addresses'addresses, v'admins'addresses'length), v'admins'percents), v'tonb, v'votes, v'profits, v'proposals, v'n_votes) = v;
build_0 = __gen_write_AddressList(build_0, (v'founders'addresses, v'founders'length));
var build_1 = begin_cell();
build_1 = __gen_write_Distribution(build_1, ((v'admins'addresses'addresses, v'admins'addresses'length), v'admins'percents));
build_1 = __tact_store_address(build_1, v'tonb);
build_1 = build_1.store_dict(v'votes);
var build_2 = begin_cell();
build_2 = build_2.store_dict(v'profits);
build_2 = build_2.store_dict(v'proposals);
build_2 = build_2.store_int(v'n_votes, 257);
build_1 = store_ref(build_1, build_2.end_cell());
build_0 = store_ref(build_0, build_1.end_cell());
return build_0;
}
(slice, (((cell, int), ((cell, int), cell), slice, cell, cell, cell, int))) __gen_read_Foundation(slice sc_0) inline {
var v'founders = sc_0~__gen_read_AddressList();
slice sc_1 = sc_0~load_ref().begin_parse();
var v'admins = sc_1~__gen_read_Distribution();
var v'tonb = sc_1~__tact_load_address();
var v'votes = sc_1~load_dict();
slice sc_2 = sc_1~load_ref().begin_parse();
var v'profits = sc_2~load_dict();
var v'proposals = sc_2~load_dict();
var v'n_votes = sc_2~load_int(257);
return (sc_0, (v'founders, v'admins, v'tonb, v'votes, v'profits, v'proposals, v'n_votes));
}
(cell, int) __gen_AddressList_to_external(((cell, int)) v) inline {
var (v'addresses, v'length) = v;
return (v'addresses, v'length);
}
((int, slice, cell, int, cell)) __gen_Proposal_not_null(tuple v) inline {
throw_if(128, null?(v));
var (int vvv'type, slice vvv'blacklistAddress, cell vvv'distribution_addresses, int vvv'distribution_addresses_length, cell vvv'distribution_percents) = __tact_tuple_destroy_5(v);
return (vvv'type, vvv'blacklistAddress, vvv'distribution_addresses, vvv'distribution_addresses_length, vvv'distribution_percents);
}
((int, cell, int, int, int, int)) __gen_Vote_not_null(tuple v) inline {
throw_if(128, null?(v));
var (int vvv'id, cell vvv'votes, int vvv'vote_end, int vvv'quorum_percent, int vvv'ended, int vvv'result) = __tact_tuple_destroy_6(v);
return (vvv'id, vvv'votes, vvv'vote_end, vvv'quorum_percent, vvv'ended, vvv'result);
}
tuple __gen_Vote_to_tuple(((int, cell, int, int, int, int)) v) inline {
var (v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result) = v;
return __tact_tuple_create_6(v'id, v'votes, v'vote_end, v'quorum_percent, v'ended, v'result);
}
tuple __gen_Vote_opt_to_tuple(tuple v) inline {
if (null?(v)) { return null(); }
return __gen_Vote_to_tuple(__gen_Vote_not_null(v));
}
tuple __gen_Vote_opt_to_external(tuple v) inline {
var loaded = __gen_Vote_opt_to_tuple(v);
if (null?(loaded)) {
return null();
} else {
return (loaded);
}
}
((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) __gen_load_Foundation() inline {
slice sc = get_data().begin_parse();
__tact_context_sys = sc~load_ref();
return sc~__gen_read_Foundation();
}
() __gen_store_Foundation(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) v) impure inline {
builder b = begin_cell();
b = b.store_ref(__tact_context_sys);
b = __gen_write_Foundation(b, v);
set_data(b.end_cell());
}
() $send((int, slice, int, int, cell, cell, cell) $params) impure inline_ref {
var (($params'bounce, $params'to, $params'value, $params'mode, $params'body, $params'code, $params'data)) = $params;
builder $b = begin_cell();
$b = store_int($b, 1, 2);
$b = __tact_store_bool($b, $params'bounce);
$b = store_int($b, 0, 3);
$b = __tact_store_address($b, $params'to);
$b = store_coins($b, $params'value);
$b = store_int($b, 0, ((((1 + 4) + 4) + 64) + 32));
if (((~ null?($params'code)) | (~ null?($params'data)))) {
$b = __tact_store_bool($b, true);
builder $bc = begin_cell();
$bc = __tact_store_bool($bc, false);
$bc = __tact_store_bool($bc, false);
if ((~ null?($params'code))) {
$bc = __tact_store_bool($bc, true);
$bc = store_ref($bc, __tact_not_null($params'code));
} else {
$bc = __tact_store_bool($bc, false);
}
if ((~ null?($params'data))) {
$bc = __tact_store_bool($bc, true);
$bc = store_ref($bc, __tact_not_null($params'data));
} else {
$bc = __tact_store_bool($bc, false);
}
$bc = __tact_store_bool($bc, false);
$b = __tact_store_bool($b, true);
$b = store_ref($b, end_cell($bc));
} else {
$b = __tact_store_bool($b, false);
}
cell $body = $params'body;
if ((~ null?($body))) {
$b = __tact_store_bool($b, true);
$b = store_ref($b, __tact_not_null($body));
} else {
$b = __tact_store_bool($b, false);
}
cell $c = end_cell($b);
send_raw_message($c, $params'mode);
}
int $__gen_Foundation_numVotes(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self) impure inline_ref {
var ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes)) = $self;
return $self'n_votes;
}
_ $__gen_get_numVotes() method_id(70748) {
var self = __gen_load_Foundation();
var res = $__gen_Foundation_numVotes(self);
return res;
}
tuple $__gen_Foundation_nthVote(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, int $n) impure inline_ref {
var ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes)) = $self;
return __gen_readopt_Vote(__tact_dict_get_int_cell($self'votes, 257, $n));
}
_ $__gen_get_nthVote(int $$n) method_id(115768) {
int $n = $$n;
var self = __gen_load_Foundation();
var res = $__gen_Foundation_nthVote(self, $n);
return __gen_Vote_opt_to_external(res);
}
(cell, int) $__gen_Foundation_AdminList(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self) impure inline_ref {
var ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes)) = $self;
return ($self'admins'addresses'addresses, $self'admins'addresses'length);
}
_ $__gen_get_AdminList() method_id(125436) {
var self = __gen_load_Foundation();
var res = $__gen_Foundation_AdminList(self);
return __gen_AddressList_to_external(res);
}
cell $__gen_Foundation_AdminPercents(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self) impure inline_ref {
var ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes)) = $self;
return $self'admins'percents;
}
_ $__gen_get_AdminPercents() method_id(87676) {
var self = __gen_load_Foundation();
var res = $__gen_Foundation_AdminPercents(self);
return res;
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_FinishVote(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'voteId) = $msg;
throw_unless(46931, ($msg'voteId < $self'n_votes));
var ($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result) = __gen_Vote_not_null(__gen_readopt_Vote(__tact_dict_get_int_cell($self'votes, 257, $msg'voteId)));
throw_unless(30386, ($vote'ended == false));
throw_unless(34326, ($vote'vote_end >= now()));
int $n_yes = 0;
int $n_no = 0;
int $n_abstain = 0;
int $i = 0;
while (($i < $self'admins'addresses'length)) {
int $vote_i = __tact_not_null(__tact_dict_get_int_int($vote'votes, 257, $i, 257));
if (($vote_i == 1)) {
$n_yes = ($n_yes + __tact_not_null(__tact_dict_get_int_int($self'admins'percents, 257, $i, 257)));
} elseif (($vote_i == 2)) {
$n_no = ($n_no + __tact_not_null(__tact_dict_get_int_int($self'admins'percents, 257, $i, 257)));
} elseif (($vote_i == 0)) {
$n_abstain = ($n_abstain + __tact_not_null(__tact_dict_get_int_int($self'admins'percents, 257, $i, 257)));
}
$i = ($i + 1);
}
int $n_total = (($n_yes + $n_no) + $n_abstain);
int $present = $n_total;
if (($present < $vote'quorum_percent)) {
$vote'result = false;
} elseif (($n_yes > $n_no)) {
$vote'result = true;
} else {
$vote'result = false;
}
$vote'ended = true;
$self'votes~__tact_dict_set_int_cell(257, $msg'voteId, __gen_writecell_Vote(($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result)));
if (($vote'result == true)) {
var ($prop'type, $prop'blacklistAddress, $prop'distribution_addresses, $prop'distribution_addresses_length, $prop'distribution_percents) = __gen_Proposal_not_null(__gen_readopt_Proposal(__tact_dict_get_int_cell($self'proposals, 257, $msg'voteId)));
if (($prop'type == 0)) {
$send((true, $self'tonb, 0, 64, __gen_writecell_BlacklistWallet((__tact_not_null($prop'blacklistAddress))), null(), null()));
}
if (($prop'type == 1)) {
}
if (($prop'type == 2)) {
(($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents) = (($prop'distribution_addresses, __tact_not_null($prop'distribution_addresses_length)), $prop'distribution_percents);
}
}
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_VoteMsg(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int, int, int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'voteId, $msg'adminIndex, $msg'vote) = $msg;
throw_unless(49606, ($msg'adminIndex < $self'admins'addresses'length));
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(56549, __tact_address_eq($ctx'sender, __tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $msg'adminIndex)));
throw_unless(46931, ($msg'voteId < $self'n_votes));
var ($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result) = __gen_Vote_not_null(__gen_readopt_Vote(__tact_dict_get_int_cell($self'votes, 257, $msg'voteId)));
throw_unless(30386, ($vote'ended == false));
throw_unless(29720, (($msg'vote >= 0) & ($msg'vote <= 2)));
$vote'votes~__tact_dict_set_int_int(257, $msg'adminIndex, $msg'vote, 257);
$self'votes~__tact_dict_set_int_cell(257, $msg'voteId, __gen_writecell_Vote(($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result)));
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_InitiateBlacklistVote(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int, slice, int, int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'adminIndex, $msg'wallet, $msg'quorum_percent, $msg'vote_time) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(6873, __tact_address_eq($ctx'sender, __tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $msg'adminIndex)));
throw_unless(29821, ($ctx'value >= 1000000000));
throw_unless(19362, (($msg'quorum_percent > 20) & ($msg'quorum_percent <= 100)));
throw_unless(61070, (($msg'vote_time >= 0) & ($msg'vote_time < ((3 * 24) * 3600))));
var ($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents) = (0, $msg'wallet, null(), null(), null());
var ($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result) = ($self'n_votes, null(), (now() + $msg'vote_time), $msg'quorum_percent, false, null());
int $i = 0;
while (($i < $self'admins'addresses'length)) {
$vote'votes~__tact_dict_set_int_int(257, $i, (- 1), 257);
$i = ($i + 1);
}
$self'votes~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Vote(($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result)));
$self'proposals~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Proposal(($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents)));
$self'n_votes = ($self'n_votes + 1);
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_InitiateDistributionVote(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int, int, int, ((cell, int), cell)) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'adminIndex, $msg'quorum_percent, $msg'vote_time, (($msg'distribution'addresses'addresses, $msg'distribution'addresses'length), $msg'distribution'percents)) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(6873, __tact_address_eq($ctx'sender, __tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $msg'adminIndex)));
throw_unless(29821, ($ctx'value >= 1000000000));
throw_unless(19362, (($msg'quorum_percent > 20) & ($msg'quorum_percent <= 100)));
throw_unless(61070, (($msg'vote_time >= 0) & ($msg'vote_time < ((3 * 24) * 3600))));
var ($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents) = (2, null(), $msg'distribution'addresses'addresses, $msg'distribution'addresses'length, $msg'distribution'percents);
var ($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result) = ($self'n_votes, null(), (now() + $msg'vote_time), $msg'quorum_percent, false, null());
int $i = 0;
while (($i < $self'admins'addresses'length)) {
$vote'votes~__tact_dict_set_int_int(257, $i, (- 1), 257);
$i = ($i + 1);
}
$self'votes~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Vote(($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result)));
$self'proposals~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Proposal(($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents)));
$self'n_votes = ($self'n_votes + 1);
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_InitiateLiquidationVote(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int, int, int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'adminIndex, $msg'quorum_percent, $msg'vote_time) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(6873, __tact_address_eq($ctx'sender, __tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $msg'adminIndex)));
throw_unless(29821, ($ctx'value >= 1000000000));
throw_unless(19362, (($msg'quorum_percent > 85) & ($msg'quorum_percent <= 100)));
throw_unless(61070, (($msg'vote_time > 0) & ($msg'vote_time < ((3 * 24) * 3600))));
var ($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result) = ($self'n_votes, null(), (now() + $msg'vote_time), $msg'quorum_percent, false, null());
int $i = 0;
while (($i < $self'admins'addresses'length)) {
$vote'votes~__tact_dict_set_int_int(257, $i, (- 1), 257);
$i = ($i + 1);
}
var ($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents) = (1, null(), null(), null(), null());
$self'votes~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Vote(($vote'id, $vote'votes, $vote'vote_end, $vote'quorum_percent, $vote'ended, $vote'result)));
$self'proposals~__tact_dict_set_int_cell(257, $self'n_votes, __gen_writecell_Proposal(($proposal'type, $proposal'blacklistAddress, $proposal'distribution_addresses, $proposal'distribution_addresses_length, $proposal'distribution_percents)));
$self'n_votes = ($self'n_votes + 1);
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_Unstake(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'amount) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
if (__tact_address_eq($ctx'sender, $self'tonb)) {
int $value = $ctx'value;
int $i = 0;
while (($i < $self'admins'addresses'length)) {
slice $addr = __tact_not_null(__tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $i));
int $percent = __tact_not_null(__tact_dict_get_int_int($self'admins'percents, 257, $i, 257));
int $amount = (($value * $percent) / 100);
int $current_profit = 0;
int $profit_record = __tact_dict_get_slice_int($self'profits, 267, $addr, 257);
if ((~ null?($profit_record))) {
$current_profit = __tact_not_null($profit_record);
}
$self'profits~__tact_dict_set_slice_int(267, $addr, ($current_profit + $amount), 257);
$i = ($i + 1);
}
}
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_RequestUnstake(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'founderIndex) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(37444, __tact_address_eq(__tact_dict_get_int_slice($self'founders'addresses, 257, $msg'founderIndex), $ctx'sender));
$send((true, $self'tonb, 0, 64, __gen_writecell_Unstake((0)), null(), null()));
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive_CollectProfit(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self, (int) $msg) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
var ($msg'adminIndex) = $msg;
var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get();
throw_unless(53981, __tact_address_eq(__tact_dict_get_int_slice($self'admins'addresses'addresses, 257, $msg'adminIndex), $ctx'sender));
int $profit = __tact_dict_get_slice_int($self'profits, 267, $ctx'sender, 257);
throw_unless(42983, (~ null?($profit)));
int $amount = __tact_not_null($profit);
$self'profits~__tact_dict_set_slice_int(267, $ctx'sender, 0, 257);
$send((true, $ctx'sender, ($amount - 150000000), 64, null(), null(), null()));
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
((((cell, int), ((cell, int), cell), slice, cell, cell, cell, int)), ()) $__gen_Foundation_receive(((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) $self) impure inline {
var (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes) = $self;
return ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes), ());
}
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
;; Parse incoming message
int op = 0;
if (slice_bits(in_msg) >= 32) {
op = in_msg.preload_uint(32);
}
var cs = in_msg_cell.begin_parse();
var msg_flags = cs~load_uint(4);
var msg_bounced = ((msg_flags & 1) == 1 ? true : false);
slice msg_sender_addr = cs~load_msg_addr();
__tact_context = (msg_bounced, msg_sender_addr, msg_value, cs);
;; Handle bounced messages
if (msg_bounced) {
return ();
}
;; Receive FinishVote message
if (op == 710362179) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_FinishVote();
self~$__gen_Foundation_receive_FinishVote(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive VoteMsg message
if (op == 1493035179) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_VoteMsg();
self~$__gen_Foundation_receive_VoteMsg(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive InitiateBlacklistVote message
if (op == 3909090059) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_InitiateBlacklistVote();
self~$__gen_Foundation_receive_InitiateBlacklistVote(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive InitiateDistributionVote message
if (op == 2512227654) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_InitiateDistributionVote();
self~$__gen_Foundation_receive_InitiateDistributionVote(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive InitiateLiquidationVote message
if (op == 301696559) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_InitiateLiquidationVote();
self~$__gen_Foundation_receive_InitiateLiquidationVote(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive Unstake message
if (op == 3125946401) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_Unstake();
self~$__gen_Foundation_receive_Unstake(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive RequestUnstake message
if (op == 3922648959) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_RequestUnstake();
self~$__gen_Foundation_receive_RequestUnstake(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive CollectProfit message
if (op == 1368467253) {
var self = __gen_load_Foundation();
var msg = in_msg~__gen_read_CollectProfit();
self~$__gen_Foundation_receive_CollectProfit(msg);
__gen_store_Foundation(self);
return ();
}
;; Receive empty message
if ((op == 0) & (slice_bits(in_msg) <= 32)) {
var self = __gen_load_Foundation();
self~$__gen_Foundation_receive();
__gen_store_Foundation(self);
return ();
}
throw(130);
}
_ supported_interfaces() method_id {
return (
"org.ton.introspection.v0"H >> 128,
"org.ton.abi.ipfs.v0"H >> 128
);
}
_ get_abi_ipfs() {
return "ipfs://QmTpahMZ5QmQr9Tr28bzZjVXyrZDoiJu5wUsDtQignQvds";
}

1531
sources/output/jetton_Foundation.code.fif

File diff suppressed because it is too large Load Diff

2663
sources/output/jetton_Foundation.code.rev.fif

File diff suppressed because it is too large Load Diff

BIN
sources/output/jetton_Foundation.init.boc

Binary file not shown.

78
sources/output/jetton_Foundation.init.fc

@ -0,0 +1,78 @@
#pragma version =0.4.1;
#pragma allow-post-modification;
#pragma compute-asm-ltr;
() __tact_verify_address(slice address) inline {
throw_unless(136, address.slice_bits() != 267);
}
builder __tact_store_address(builder b, slice address) inline {
__tact_verify_address(address);
b = b.store_slice(address);
return b;
}
forall X0, X1 -> (X0, X1) __tact_tuple_destroy_2(tuple v) asm "2 UNTUPLE";
builder __gen_write_AddressList(builder build_0, (cell, int) v) inline {
var (v'addresses, v'length) = v;
build_0 = build_0.store_dict(v'addresses);
build_0 = build_0.store_int(v'length, 257);
return build_0;
}
builder __gen_write_Distribution(builder build_0, ((cell, int), cell) v) inline {
var ((v'addresses'addresses, v'addresses'length), v'percents) = v;
build_0 = __gen_write_AddressList(build_0, (v'addresses'addresses, v'addresses'length));
build_0 = build_0.store_dict(v'percents);
return build_0;
}
builder __gen_write_Foundation(builder build_0, ((cell, int), ((cell, int), cell), slice, cell, cell, cell, int) v) inline {
var ((v'founders'addresses, v'founders'length), ((v'admins'addresses'addresses, v'admins'addresses'length), v'admins'percents), v'tonb, v'votes, v'profits, v'proposals, v'n_votes) = v;
build_0 = __gen_write_AddressList(build_0, (v'founders'addresses, v'founders'length));
var build_1 = begin_cell();
build_1 = __gen_write_Distribution(build_1, ((v'admins'addresses'addresses, v'admins'addresses'length), v'admins'percents));
build_1 = __tact_store_address(build_1, v'tonb);
build_1 = build_1.store_dict(v'votes);
var build_2 = begin_cell();
build_2 = build_2.store_dict(v'profits);
build_2 = build_2.store_dict(v'proposals);
build_2 = build_2.store_int(v'n_votes, 257);
build_1 = store_ref(build_1, build_2.end_cell());
build_0 = store_ref(build_0, build_1.end_cell());
return build_0;
}
(cell, int) __gen_AddressList_from_tuple(tuple v) inline {
var (cell v'addresses, int v'length) = __tact_tuple_destroy_2(v);
return (v'addresses, v'length);
}
((cell, int), cell) __gen_Distribution_from_tuple(tuple v) inline {
var (tuple v'addresses, cell v'percents) = __tact_tuple_destroy_2(v);
return (__gen_AddressList_from_tuple(v'addresses), v'percents);
}
cell $__gen_Foundation_init(cell sys', ((cell, int), cell) $admins, (cell, int) $founders, slice $tonb) {
var ((($admins'addresses'addresses, $admins'addresses'length), $admins'percents)) = $admins;
var (($founders'addresses, $founders'length)) = $founders;
var ((($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes)) = (null(), null(), null(), null(), null(), null(), 0);
(($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents) = (($admins'addresses'addresses, $admins'addresses'length), $admins'percents);
($self'founders'addresses, $self'founders'length) = ($founders'addresses, $founders'length);
$self'tonb = $tonb;
var b' = begin_cell();
b' = b'.store_ref(sys');
b' = __gen_write_Foundation(b', (($self'founders'addresses, $self'founders'length), (($self'admins'addresses'addresses, $self'admins'addresses'length), $self'admins'percents), $self'tonb, $self'votes, $self'profits, $self'proposals, $self'n_votes));
return b'.end_cell();
}
cell init(cell sys', tuple $$admins, tuple $$founders, slice $$tonb) method_id {
((cell, int), cell) $admins = __gen_Distribution_from_tuple($$admins);
(cell, int) $founders = __gen_AddressList_from_tuple($$founders);
slice $tonb = $$tonb;
return $__gen_Foundation_init(sys', $admins, $founders, $tonb);
}
() main() {
}

93
sources/output/jetton_Foundation.init.fif

@ -0,0 +1,93 @@
PROGRAM{
DECLPROC __tact_verify_address
DECLPROC __tact_store_address
DECLPROC __gen_write_AddressList
DECLPROC __gen_write_Distribution
DECLPROC __gen_write_Foundation
DECLPROC __gen_AddressList_from_tuple
DECLPROC __gen_Distribution_from_tuple
DECLPROC $__gen_Foundation_init
107886 DECLMETHOD init
DECLPROC main
__tact_verify_address PROCINLINE:<{
SBITS
267 PUSHINT
NEQ
136 THROWIFNOT
}>
__tact_store_address PROCINLINE:<{
STSLICER
}>
__gen_write_AddressList PROCINLINE:<{
s0 s2 XCHG
STDICT
257 PUSHINT
STIX
}>
__gen_write_Distribution PROCINLINE:<{
3 -ROLL
__gen_write_AddressList INLINECALLDICT
STDICT
}>
__gen_write_Foundation PROCINLINE:<{
s10 s9 s8 XCHG3
__gen_write_AddressList INLINECALLDICT
NEWC
s6 s1 s3 XCHG3
s5 s4 XCHG2
__gen_write_Distribution INLINECALLDICT
SWAP
__tact_store_address INLINECALLDICT
s1 s2 XCHG
STDICT
s0 s4 XCHG
NEWC
STDICT
s1 s3 XCHG
STDICT
257 PUSHINT
STIX
ENDC
ROT
STREF
ENDC
SWAP
STREF
}>
__gen_AddressList_from_tuple PROCINLINE:<{
2 UNTUPLE
}>
__gen_Distribution_from_tuple PROCINLINE:<{
2 UNTUPLE
SWAP
__gen_AddressList_from_tuple INLINECALLDICT
ROT
}>
$__gen_Foundation_init PROC:<{
PUSHNULL
PUSHNULL
PUSHNULL
0 PUSHINT
s0 s10 XCHG
NEWC
STREF
s0 s10 XCHG
s6 s9 XCHG
4 5 REVERSE
s5 s6 XCHG
__gen_write_Foundation INLINECALLDICT
ENDC
}>
init PROC:<{
s0 s2 XCHG
__gen_Distribution_from_tuple INLINECALLDICT
s0 s3 XCHG
__gen_AddressList_from_tuple INLINECALLDICT
s3 s5 XCHG
s1 s0 s4 XCHG3
s0 s3 XCHG
$__gen_Foundation_init CALLDICT
}>
main PROC:<{
}>
}END>c

64
sources/output/jetton_Foundation.init.rev.fif

@ -0,0 +1,64 @@
SETCP0
(:methods
recv_internal:
8:
PUSHNULL
PUSHNULL
PUSHNULL
0 PUSHINT
s0 s10 XCHG
NEWC
STREF
s0 s10 XCHG
s6 s9 XCHG
4 5 REVERSE
s5 s6 XCHG
s10 s9 s8 XCHG3
s0 s2 XCHG
STDICT
257 PUSHINT
STIX
NEWC
s6 s1 s3 XCHG3
s5 s4 XCHG2
3 1 BLKSWAP
s0 s2 XCHG
STDICT
257 PUSHINT
STIX
STDICT
s0 s1 XCHG
STSLICER
s1 s2 XCHG
STDICT
s0 s4 XCHG
NEWC
STDICT
s1 s3 XCHG
STDICT
257 PUSHINT
STIX
ENDC
ROT
STREF
ENDC
s0 s1 XCHG
STREF
ENDC
107886:
s0 s2 XCHG
2 UNTUPLE
s0 s1 XCHG
2 UNTUPLE
ROT
s0 s3 XCHG
2 UNTUPLE
s3 s5 XCHG
s1 s0 s4 XCHG3
s0 s3 XCHG
8 CALLDICT
) 19 DICTPUSHCONST
DICTIGETJMPZ
11 THROWARG

162
sources/output/jetton_Foundation.md

@ -0,0 +1,162 @@
# TACT Compilation Report
Contract: Foundation
BOC Size: 3554 bytes
# Types
Total Types: 36
## StateInit
TLB: `_ code:^cell data:^cell = StateInit`
Signature: `StateInit{code:^cell,data:^cell}`
## Context
TLB: `_ bounced:bool sender:address value:int257 raw:^slice = Context`
Signature: `Context{bounced:bool,sender:address,value:int257,raw:^slice}`
## SendParameters
TLB: `_ bounce:bool to:address value:int257 mode:int257 body:Maybe ^cell code:Maybe ^cell data:Maybe ^cell = SendParameters`
Signature: `SendParameters{bounce:bool,to:address,value:int257,mode:int257,body:Maybe ^cell,code:Maybe ^cell,data:Maybe ^cell}`
## TokenTransfer
TLB: `token_transfer#0f8a7ea5 queryId:uint64 amount:coins destination:address responseDestination:Maybe address customPayload:Maybe ^cell forwardTonAmount:coins forwardPayload:remainder<slice> = TokenTransfer`
Signature: `TokenTransfer{queryId:uint64,amount:coins,destination:address,responseDestination:Maybe address,customPayload:Maybe ^cell,forwardTonAmount:coins,forwardPayload:remainder<slice>}`
## TokenTransferInternal
TLB: `token_transfer_internal#178d4519 queryId:uint64 amount:coins from:address responseAddress:Maybe address forwardTonAmount:coins forwardPayload:remainder<slice> setLinker:Maybe int257 setLinkerAddress:Maybe address = TokenTransferInternal`
Signature: `TokenTransferInternal{queryId:uint64,amount:coins,from:address,responseAddress:Maybe address,forwardTonAmount:coins,forwardPayload:remainder<slice>,setLinker:Maybe int257,setLinkerAddress:Maybe address}`
## TokenNotification
TLB: `token_notification#7362d09c queryId:uint64 amount:coins from:address forwardPayload:remainder<slice> = TokenNotification`
Signature: `TokenNotification{queryId:uint64,amount:coins,from:address,forwardPayload:remainder<slice>}`
## TokenBurn
TLB: `token_burn#595f07bc queryId:uint64 amount:coins owner:address responseAddress:Maybe address = TokenBurn`
Signature: `TokenBurn{queryId:uint64,amount:coins,owner:address,responseAddress:Maybe address}`
## TokenBurnNotification
TLB: `token_burn_notification#7bdd97de queryId:uint64 amount:coins owner:address responseAddress:Maybe address = TokenBurnNotification`
Signature: `TokenBurnNotification{queryId:uint64,amount:coins,owner:address,responseAddress:Maybe address}`
## TokenExcesses
TLB: `token_excesses#d53276db queryId:uint64 = TokenExcesses`
Signature: `TokenExcesses{queryId:uint64}`
## TokenUpdateContent
TLB: `token_update_content#0c087a9e content:Maybe ^cell = TokenUpdateContent`
Signature: `TokenUpdateContent{content:Maybe ^cell}`
## StakingWithdraw
TLB: `staking_withdraw#da803efd value:coins = StakingWithdraw`
Signature: `StakingWithdraw{value:coins}`
## JettonData
TLB: `_ totalSupply:int257 mintable:bool owner:address content:Maybe ^cell walletCode:^cell = JettonData`
Signature: `JettonData{totalSupply:int257,mintable:bool,owner:address,content:Maybe ^cell,walletCode:^cell}`
## JettonWalletData
TLB: `_ balance:int257 owner:address master:address walletCode:^cell = JettonWalletData`
Signature: `JettonWalletData{balance:int257,owner:address,master:address,walletCode:^cell}`
## SetLinkerNeighbor
TLB: `set_linker_neighbor#b3fcf4c1 neighbor:Maybe address = SetLinkerNeighbor`
Signature: `SetLinkerNeighbor{neighbor:Maybe address}`
## InitLinker
TLB: `init_linker#67c08154 neighbor:Maybe address walletAmount:int257 walletCode:^cell walletData:^cell walletAddress:address responseAddress:Maybe address = InitLinker`
Signature: `InitLinker{neighbor:Maybe address,walletAmount:int257,walletCode:^cell,walletData:^cell,walletAddress:address,responseAddress:Maybe address}`
## ForwardToWallet
TLB: `forward_to_wallet#5d1da2bb body:^cell = ForwardToWallet`
Signature: `ForwardToWallet{body:^cell}`
## BlacklistWallet
TLB: `blacklist_wallet#029c8396 wallet:address = BlacklistWallet`
Signature: `BlacklistWallet{wallet:address}`
## InitiateBlacklistVote
TLB: `initiate_blacklist_vote#e8fffb0b adminIndex:int257 wallet:address quorum_percent:int257 vote_time:int257 = InitiateBlacklistVote`
Signature: `InitiateBlacklistVote{adminIndex:int257,wallet:address,quorum_percent:int257,vote_time:int257}`
## InitiateLiquidationVote
TLB: `initiate_liquidation_vote#11fb862f adminIndex:int257 quorum_percent:int257 vote_time:int257 = InitiateLiquidationVote`
Signature: `InitiateLiquidationVote{adminIndex:int257,quorum_percent:int257,vote_time:int257}`
## FinishVote
TLB: `finish_vote#2a574443 voteId:int257 = FinishVote`
Signature: `FinishVote{voteId:int257}`
## VoteMsg
TLB: `vote_msg#58fde8ab voteId:int257 adminIndex:int257 vote:int257 = VoteMsg`
Signature: `VoteMsg{voteId:int257,adminIndex:int257,vote:int257}`
## AddressList
TLB: `_ addresses:dict<int, address> length:int257 = AddressList`
Signature: `AddressList{addresses:dict<int, address>,length:int257}`
## Distribution
TLB: `_ addresses:AddressList{addresses:dict<int, address>,length:int257} percents:dict<int, int> = Distribution`
Signature: `Distribution{addresses:AddressList{addresses:dict<int, address>,length:int257},percents:dict<int, int>}`
## InitiateDistributionVote
TLB: `initiate_distribution_vote#95bd8d46 adminIndex:int257 quorum_percent:int257 vote_time:int257 distribution:Distribution{addresses:AddressList{addresses:dict<int, address>,length:int257},percents:dict<int, int>} = InitiateDistributionVote`
Signature: `InitiateDistributionVote{adminIndex:int257,quorum_percent:int257,vote_time:int257,distribution:Distribution{addresses:AddressList{addresses:dict<int, address>,length:int257},percents:dict<int, int>}}`
## SetStakingPool
TLB: `set_staking_pool#0764d148 staking_pool:Maybe address = SetStakingPool`
Signature: `SetStakingPool{staking_pool:Maybe address}`
## RequestLinker
TLB: `request_linker#5a29431e client:address = RequestLinker`
Signature: `RequestLinker{client:address}`
## Unstake
TLB: `unstake#ba522821 amount:int257 = Unstake`
Signature: `Unstake{amount:int257}`
## RequestUnstake
TLB: `request_unstake#e9cedf7f founderIndex:int257 = RequestUnstake`
Signature: `RequestUnstake{founderIndex:int257}`
## CollectProfit
TLB: `collect_profit#51912735 adminIndex:int257 = CollectProfit`
Signature: `CollectProfit{adminIndex:int257}`
## SetOwner
TLB: `set_owner#b71c6df6 owner:address = SetOwner`
Signature: `SetOwner{owner:address}`
## WithdrawalRequests
TLB: `_ addresses:dict<int, address> amounts:dict<int, int> n_requests:int257 = WithdrawalRequests`
Signature: `WithdrawalRequests{addresses:dict<int, address>,amounts:dict<int, int>,n_requests:int257}`
## Proposal
TLB: `_ type:int257 blacklistAddress:Maybe address distribution_addresses:dict<int, address> distribution_addresses_length:Maybe int257 distribution_percents:dict<int, int> = Proposal`
Signature: `Proposal{type:int257,blacklistAddress:Maybe address,distribution_addresses:dict<int, address>,distribution_addresses_length:Maybe int257,distribution_percents:dict<int, int>}`
## Vote
TLB: `_ id:int257 votes:dict<int, int> vote_end:int257 quorum_percent:int257 ended:bool result:Maybe bool = Vote`
Signature: `Vote{id:int257,votes:dict<int, int>,vote_end:int257,quorum_percent:int257,ended:bool,result:Maybe bool}`
## ChangeOwner
TLB: `change_owner#0f474d03 newOwner:address = ChangeOwner`
Signature: `ChangeOwner{newOwner:address}`
## Deposit
TLB: `deposit#21eeb607 amount:coins = Deposit`
Signature: `Deposit{amount:coins}`
## Withdraw
TLB: `withdraw#60591510 amount:int257 = Withdraw`
Signature: `Withdraw{amount:int257}`
# Get Methods
Total Get Methods: 4
## numVotes
## nthVote
Argument: n
## AdminList
## AdminPercents

1
sources/output/jetton_Foundation.pkg

File diff suppressed because one or more lines are too long

1978
sources/output/jetton_Foundation.ts

File diff suppressed because it is too large Load Diff

6
sources/utils/config.ts

@ -1,5 +1,5 @@
import { TonClient, Address, WalletContractV3R2, WalletContractV4 } from "ton";
import { TonClient, Address, WalletContractV3R2, WalletContractV4, TonClient4 } from "ton";
import { mnemonicToPrivateKey } from "ton-crypto";
import { buildOnchainMetadata } from "./helpers";
@ -8,6 +8,10 @@ export const client = new TonClient({
apiKey: 'bb38df0c2756c66e2ab49f064e2484ec444b01244d2bd49793bd5b58f61ae3d2'
})
export const client4 = new TonClient4({
endpoint: "https://sandbox-v4.tonhubapi.com"
})
let mnemonics = "basic security merge opera inject core melody polar become force cool glance history order warfare consider company slim twice balcony scare shoot winner rude";
let mnemonics2 = "road learn slow crucial mixed grunt copy ribbon coyote shrimp onion pledge any tornado rebel three glimpse winner bless thunder immune february coin egg"
// read more about wallet apps https://ton.org/docs/participate/wallets/apps#tonhub-test-environment

79
sources/utils/interactions.ts

@ -1,11 +1,13 @@
import { Cell, Address, internal, beginCell, contractAddress, toNano, fromNano, SendMode } from "ton";
import { storeDeposit, storeWithdraw, storeTokenTransfer, storeBlacklistWallet } from "../output/jetton_TONB";
import { TON } from "./helpers";
import { wallet_data, owner, default_content, workchain } from './config';
import { wallet_data, owner, default_content, workchain, client } from './config';
import { TONB } from "../output/jetton_TONB";
import { TONBWallet } from '../output/jetton_TONBWallet';
import { Distribution, AddressList } from '../output/jetton_TONBWallet';
import { Dictionary } from 'ton-core';
import { PseudoStaking, storeSetOwner, storeInitiateBlacklistVote } from '../output/jetton_PseudoStaking';
import { Foundation } from '../output/jetton_Foundation';
export async function sendMessage(wallet: any, secretKey: Buffer, msg: { value: string | bigint, to: Address, bounce?: boolean, init?: { code?: Cell, data?: Cell }, body?: any }) {
let seqno: number = await wallet.getSeqno();
@ -65,18 +67,67 @@ export async function blacklistAddress(wallet: any, secretKey: Buffer, tonb: Add
await sendMessage(wallet, secretKey, { value: msg_value, to: tonb, body: msg_body });
}
export async function getTONBState(tonb_content?: any) {
export async function getTONBState(tonb_content?: any, add_staking: boolean | Address = false) {
if (!tonb_content) {
tonb_content = default_content;
}
return await TONB.init(owner, tonb_content, null);
let staking_addr: null | Address = null;
if (add_staking === true) {
staking_addr = contractAddress(workchain, await PseudoStaking.init());
} else if (add_staking instanceof Address) {
staking_addr = add_staking;
}
return await TONB.init(owner, tonb_content, staking_addr);
}
export async function getTONB(tonb_content?: any) {
export async function getTONB(owner2?: Address, tonb_content?: any, add_staking: boolean | Address = false) {
if (!tonb_content) {
tonb_content = default_content;
}
return await TONB.fromInit(owner, tonb_content, null);
let staking_addr: null | Address = null;
if (add_staking === true) {
staking_addr = contractAddress(workchain, await PseudoStaking.init());
} else if (add_staking instanceof Address) {
staking_addr = add_staking;
}
if (!owner2) {
owner2 = owner;
}
return await TONB.fromInit(owner2, tonb_content, staking_addr);
}
export async function getTONBOpen(tonb_content?: any, add_staking: boolean | Address = false) {
let tonb = await getTONB(tonb_content, add_staking);
return client.open(tonb);
}
export async function getFoundation(
tonb_address: Address,
admins?: Address[],
admin_percents?: bigint[],
founders?: Address[],
) {
if (!admins) {
admins = [owner];
admin_percents = [100n];
}
if (!founders) {
founders = [owner];
}
return await Foundation.fromInit(
createDistribution(admins, admin_percents as bigint[]),
createAddressList(founders),
tonb_address);
}
export async function getFoundationOpen(
tonb_address: Address,
admins?: Address[],
admin_percents?: bigint[],
founders?: Address[],
) {
let foundation = await getFoundation(tonb_address, admins, admin_percents, founders);
return client.open(foundation);
}
@ -148,4 +199,22 @@ export async function getWalletAddress(master_: string | Address, owner_: string
let master = typeof master_ === 'string' ? Address.parse(master_) : master_;
let owner = typeof owner_ === 'string' ? Address.parse(owner_) : owner_;
return contractAddress(workchain, await TONBWallet.init(master, owner));
}
export async function changeTONBOwner(wallet: any, secretKey: Buffer, tonb: Address, new_owner: Address) {
let msg_body_b = beginCell();
storeSetOwner({ owner: new_owner, $$type: 'SetOwner' })(msg_body_b);
let msg_body = msg_body_b.endCell();
let msg_value = toNano('0.11');
await sendMessage(wallet, secretKey, { value: msg_value, to: tonb, body: msg_body });
}
export async function createBlacklistVote(
wallet: any, secretKey: Buffer, foundation: Address, target: Address,
vote_time: bigint, adminIndex: bigint, quorum_percent: bigint = 50n) {
let msg_body_b = beginCell();
storeInitiateBlacklistVote({ $$type: 'InitiateBlacklistVote', wallet: target, vote_time, adminIndex, quorum_percent })(msg_body_b);
let msg_body = msg_body_b.endCell();
let msg_value = toNano('1.01');
await sendMessage(wallet, secretKey, { value: msg_value, to: foundation, body: msg_body });
}
Loading…
Cancel
Save